# Apple Appclip

> Use this skill whenever the user wants to create, configure, implement, debug, or learn about Apple App Clips for iOS apps. Triggers include: any mention of 'App Clip', 'app clip', 'App Clip Code', 'invocation URL', 'App Clip experience', lightweight app, instant app experience, or demo version of an iOS app. Also use when the user asks about sharing data between an App Clip and a full app, configuring App Clip experiences in App Store Connect, App Clip size limits, responding to invocations, Smart App Banners for App Clips, NFC-integrated codes, or App Clip to full app transitions. Use this skill even if the user just mentions wanting a "lightweight version" or "instant experience" for their iOS app — they likely need an App Clip. Do NOT use for general iOS development unrelated to App Clips, Android Instant Apps, or Progressive Web Apps.

- Skill: `ios-agent/apple-appclip` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add ios-agent/apple-appclip`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ios-agent/apple-appclip/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ios-agent (https://skillmd.com/u/ios-agent)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ios-agent/apple-appclip

---


# 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

1. Open your existing iOS project (or create a new one)
2. Add a new target using the **App Clip** template
3. 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:

```swift
#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

1. Archive the app in Xcode
2. Export as Ad Hoc/Development with App Thinning enabled
3. 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:**
```swift
@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:**
```swift
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:
```bash
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`:

```json
{
    "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>`:
```html
<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
```swift
// In both App Clip and full app
let sharedDefaults = UserDefaults(suiteName: "group.com.example.myapp")
sharedDefaults?.set("someValue", forKey: "someKey")
```

### Keychain (for sensitive data)
```swift
// 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:
```swift
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:

```swift
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`:
```xml
<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:

```swift
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
1. Upload app with App Clip to App Store Connect
2. Configure up to 3 App Clip experiences for testing
3. 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:

```swift
guard ARWorldTrackingConfiguration.supportsAppClipCodeTracking else { return }

let config = ARWorldTrackingConfiguration()
config.appClipCodeTrackingEnabled = true
arView.session.run(config)
```

Requires Apple Neural Engine (ANE) on device.

---

## Distribution Checklist

1. ✅ App Clip target added to Xcode project
2. ✅ Code shared between App Clip and full app (Swift packages recommended)
3. ✅ App Clip responds to all registered invocation URLs
4. ✅ App Clip binary within size limits
5. ✅ Default App Clip experience configured in App Store Connect
6. ✅ (Optional) Advanced experiences configured
7. ✅ (Optional) Website associated via AASA file
8. ✅ (Optional) App Clip Codes created
9. ✅ (Optional) Smart App Banner on website
10. ✅ Full app recommends itself via SKOverlay
11. ✅ Data migration path from App Clip to full app (shared container/keychain)
12. ✅ Tested locally, via TestFlight, and verified via Diagnostics

