Apple App Clip Skill
Guide users through creating, configuring, and implementing Apple App Clips — lightweight versions of iOS apps that provide instant, in-the-moment experiences or demo versions.
For the full Apple developer documentation reference, read: references/apple-appclip-full-docs.md
What is an App Clip?
An App Clip is a lightweight version of an iOS app that offers some of its functionality instantly — without requiring installation from the App Store. App Clips are designed for:
-
In-the-moment experiences: Order food, pay for parking, rent a scooter — fast, focused tasks
-
Demo versions: Let users try a game level, a workout, or a feature before buying/subscribing
App Clips don't appear on the Home Screen and are removed by the system after a period of inactivity.
Size Limits
iOS Version Max Uncompressed App Clip Binary
iOS 15 and earlier 10 MB
iOS 16 and earlier 15 MB
iOS 17 and later 100 MB (with restrictions below)
The 100 MB limit on iOS 17+ requires:
-
Only digital invocations (website, Spotlight) — no physical invocations (NFC, QR, App Clip Codes)
-
Reliable internet expected
-
No iOS 16 or earlier support
-
Exception: The App Clip demo link from App Store Connect allows 100 MB AND physical invocations
Use Background Assets framework to download additional content (but not with isEssential priority).
Xcode Project Setup
Add an App Clip Target
-
Open your existing iOS project (or create a new one)
-
Add a new target using the App Clip template
-
Choose product name and options, click Finish
Xcode automatically creates:
-
A scheme to build/run the App Clip
-
The On Demand Install Capable capability (com.apple.developer.on-demand-install-capable )
-
The Parent Application Identifiers Entitlement
-
An app identifier: $(AppIdentifierPrefix)com.example.MyApp.Clip
-
The _XCAppClipURL environment variable for debugging invocations
Share Code Between App Clip and Full App
-
Use Swift packages for shared components
-
Share asset catalogs between targets
-
Use Active Compilation Conditions for conditional code:
#if !APPCLIP // Code only for full app #else // Code for App Clip #endif
Add APPCLIP to the App Clip target's Active Compilation Conditions build setting.
Verify Size
-
Archive the app in Xcode
-
Export as Ad Hoc/Development with App Thinning enabled
-
Check App Thinning Size Report.txt for uncompressed sizes per variant
Invocations & Launch Experience
How Users Discover App Clips
-
App Clip Codes (NFC-integrated or scan-only)
-
QR codes and NFC tags
-
Safari Smart App Banners
-
Links in Messages
-
Maps and Spotlight search
-
Location-based Siri suggestions
-
Other apps (via App Clip links)
Invocation URLs
Invocation URLs identify which experience to show. Configure them in App Store Connect:
-
Default App Clip experience: Basic experience with auto-generated App Clip link
-
Demo link: Generated by App Store Connect, supports 100 MB size limit
-
Advanced App Clip experiences: Custom URLs with prefix matching
Example URL structure:
https://example.com/location1 https://example.com/location2 https://appclip.example.com/shop?p=123
Both the App Clip AND the full app must handle all registered invocation URLs.
Responding to Invocations in Code
SwiftUI lifecycle:
@main struct MyAppClip: App { var body: some Scene { WindowGroup { ContentView() .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in respondTo(activity) } } } }
Scene-based lifecycle: Implement scene(:willConnectTo:options:) for first launch and scene(:willContinueUserActivityWithType:) for subsequent invocations.
Extract the URL:
func respondTo(_ activity: NSUserActivity?) { guard let activity, activity.activityType == NSUserActivityTypeBrowsingWeb else { return } let incomingURL = activity.webpageURL guard let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true) else { return } // Update UI based on URL components }
Important: If you register a generic URL like https://example.com/ , your code must handle that URL even if you only intend to use it as a prefix for more specific invocations.
App Clip Experiences Configuration
Default Experience
-
Created automatically in App Store Connect
-
Uses the auto-generated App Clip link or a custom URL
Demo Link
-
Generated by App Store Connect
-
Allows 100 MB App Clips with physical invocations
-
No launch parameters supported
Advanced Experiences
-
Custom invocation URLs with prefix matching
-
Required for App Clip Codes
-
Must associate App Clip with your website (AASA file)
-
Supports location-based experiences
App Clip Codes
Types
-
NFC-integrated: Users hold device near the code OR scan it
-
Scan-only: Users scan with Camera app or Code Scanner
Creation Tools
-
App Store Connect: Visual interface, instant preview
-
App Clip Code Generator CLI: Scriptable, works without ASC experience
CLI example:
AppClipCodeGenerator generate
--url https://example.com/shop
--index 0
--output ~/Downloads/AppClipCode.svg
--logo badge
URL Encoding Best Practices
-
Use short hostnames, few subdomains
-
Remove www subdomain
-
Use appclip as first subdomain for efficient encoding: https://appclip.example.com
-
Use short query parameter names: ?p=0 not ?status=view
-
Use decimal numbers for values
-
Omit trailing slashes
-
Avoid long UUIDs
-
Use single-word path components from Apple's optimized list (see reference docs)
Valid URL characters:
-
Host: lowercase a-z , . , -
-
Path/query: a-z , A-Z , 0-9 , /#?=%-._,+;:&
Website Association (AASA)
Required for advanced App Clip experiences and iOS 16.3 or earlier invocations.
Server-Side Setup
Add to https://yourdomain.com/.well-known/apple-app-site-association :
{ "appclips": { "apps": ["ABCDE12345.com.example.MyApp.Clip"] } }
Requirements:
-
Serve from /.well-known/ path directly (no redirects)
-
Content-Type: application/json
-
Valid HTTPS with trusted certificate
-
File size ≤ 128 KB
Smart App Banner
Add to your website's <head> :
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-clip-bundle-id=com.example.MyApp.Clip, app-clip-display=card">
Data Sharing: App Clip → Full App
Shared App Group Container
// In both App Clip and full app let sharedDefaults = UserDefaults(suiteName: "group.com.example.myapp") sharedDefaults?.set("someValue", forKey: "someKey")
Keychain (for sensitive data)
// App Clip stores: let addQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecValueData as String: "secret-token".data(using: .utf8)!, kSecAttrLabel as String: "my-appclip" ] SecItemAdd(addQuery as CFDictionary, nil)
// Full app reads: var readQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecReturnAttributes as String: true, kSecAttrLabel as String: "my-appclip", kSecReturnData as String: true ] var result: AnyObject? SecItemCopyMatching(readQuery as CFDictionary, &result)
Sign in with Apple
Store credentials in shared UserDefaults so the full app can sign in automatically:
let groupDefaults = UserDefaults(suiteName: "group.com.example.myapp") guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else { return } groupDefaults?.set(credential.user, forKey: "SavedUserID")
CloudKit (iOS 16+)
App Clips can read public iCloud database only. No writes, no private/shared containers.
Recommending the Full App
Use SKOverlay to display an install prompt:
import StoreKit
func recommendFullApp(in scene: UIWindowScene) { let config = SKOverlay.AppClipConfiguration(position: .bottom) let overlay = SKOverlay(configuration: config) overlay.present(in: scene) }
Notifications
App Clips can request notification permission for a limited time:
-
8 hours by default after each launch
-
Up to 1 week if enabled in App Store Connect
Configure in Info.plist :
<key>NSAppClip</key> <dict> <key>NSAppClipRequestEphemeralUserNotification</key> <true/> </dict>
Live Activities
App Clips can offer Live Activities by including a widget extension target. Use ActivityKit to display on Lock Screen and Dynamic Island.
Location Confirmation
Verify a user's physical location for NFC/visual code invocations:
guard let payload = userActivity.appClipActivationPayload else { return }
let region = CLCircularRegion( center: CLLocationCoordinate2D(latitude: 37.334722, longitude: -122.008889), radius: 100, identifier: "store" )
payload.confirmAcquired(in: region) { inRegion, error in if let error = error { // Handle APActivationPayloadError return } // inRegion indicates if user is within the region }
Fails with disallowed if invocation source isn't NFC tag or visual code.
Framework & API Restrictions
Unavailable Frameworks (no runtime functionality)
App Intents, Assets Library, Background Tasks, CallKit, CareKit, Contacts, Contacts UI, Core Motion, EventKit, EventKit UI, File Provider, File Provider UI, HealthKit, HomeKit, Media Player, Messages, Message UI, Nearby Interaction, PhotoKit, ResearchKit, SensorKit, Speech
Privacy Restrictions
-
No SKAdNetwork , no App Tracking Transparency
-
UIDevice.name and identifierForVendor return empty strings
-
No continuous location access (only When In Use, resets at 4 AM)
-
No Face ID (Touch ID via LocalAuthentication is available)
-
Can't share data with other apps (only with its full app)
Reserved for Full App Only (in-the-moment App Clips)
App extensions (except widget for Live Activities), settings bundles, in-app purchases, multiple scenes on iPad, on-demand resources, custom URL schemes, background networking
Testing
Local Testing in Xcode
Use the _XCAppClipURL environment variable to set invocation URLs for debugging.
TestFlight
-
Upload app with App Clip to App Store Connect
-
Configure up to 3 App Clip experiences for testing
-
Testers launch via the TestFlight app (not Home Screen)
Diagnostics (Released App Clips)
Settings → Developer → App Clips Testing → Diagnostics Enter your URL to verify: advanced experience registration, App Store publication, website association, App Clip Code URL fit, Smart App Banner presence.
Clear Cache
Settings → Developer → Clear Experience Cache (to test new advanced experiences)
AR Integration with App Clip Codes
App Clip Codes can be tracked in ARKit for augmented reality experiences:
guard ARWorldTrackingConfiguration.supportsAppClipCodeTracking else { return }
let config = ARWorldTrackingConfiguration() config.appClipCodeTrackingEnabled = true arView.session.run(config)
Requires Apple Neural Engine (ANE) on device.
Distribution Checklist
-
✅ App Clip target added to Xcode project
-
✅ Code shared between App Clip and full app (Swift packages recommended)
-
✅ App Clip responds to all registered invocation URLs
-
✅ App Clip binary within size limits
-
✅ Default App Clip experience configured in App Store Connect
-
✅ (Optional) Advanced experiences configured
-
✅ (Optional) Website associated via AASA file
-
✅ (Optional) App Clip Codes created
-
✅ (Optional) Smart App Banner on website
-
✅ Full app recommends itself via SKOverlay
-
✅ Data migration path from App Clip to full app (shared container/keychain)
-
✅ Tested locally, via TestFlight, and verified via Diagnostics