Sun Oct 05 Estimated time: PT50M

How to Debug App Clips on iOS

A step-by-step guide to debugging iOS App Clips. Learn how to test invocation URLs, diagnose AASA issues, validate experiences locally, and troubleshoot common problems.

Debugging App Clips on iOS

Before You Start

Debugging App Clips is different from debugging a standard iOS app. App Clips are invoked through URLs, constrained by size limits, and tied to domain verification. A bug in any of these layers can silently break the experience without a clear error message.

This guide walks through the full debugging process, from local Xcode testing to production troubleshooting. Each step builds on the previous one, so work through them in order if you are debugging a new App Clip. If you are tracking down a specific issue, jump to the relevant section.

You will need Xcode 14 or later, a physical iOS device running iOS 16 or later (some features work on iOS 14+), and an Apple Developer account with App Store Connect access.

Step 1: Set Up Your Xcode Project for App Clip Debugging

The most common early debugging problems come from incorrect Xcode configuration. Get this right first and you will avoid hours of confusing failures later.

Bundle Identifier

Your App Clip’s bundle identifier must follow this format:

com.yourcompany.yourapp.Clip

It must be your main app’s bundle identifier with .Clip appended. If this does not match, domain verification will fail silently and your App Clip will never launch from a URL.

Associated Domains Entitlement

Add the Associated Domains capability to your App Clip target (not just your main app target). The domain entry should use the appclips service type:

appclips:yourdomain.com

This is separate from the applinks entries you use for Universal Links. Both the main app and the App Clip target need their own Associated Domains configurations.

Environment Variable for URL Testing

In your App Clip scheme’s Run configuration, add an environment variable:

  • Name: _XCAppClipURL
  • Value: The URL you want to simulate, e.g., https://yourdomain.com/menu/test-restaurant

This tells Xcode to pass this URL to your App Clip when you run it from the debugger, simulating a real invocation without needing to scan a QR code or tap an NFC tag.

Scheme Configuration Checklist

Verify these settings in your App Clip scheme:

  • Build configuration is set to Debug
  • The executable is your App Clip target, not your main app
  • The _XCAppClipURL environment variable is set and enabled
  • Any launch arguments for testing are configured

Step 2: Test Invocation URLs with the Local Experience

With the Xcode project configured, start testing how your App Clip responds to different URLs.

Testing Different URL Patterns

Change the _XCAppClipURL value to test each registered URL pattern:

https://yourdomain.com/menu/restaurant-a
https://yourdomain.com/menu/restaurant-b
https://yourdomain.com/parking/lot-123
https://yourdomain.com/checkout?item=abc&promo=WELCOME

For each URL, verify:

  • The App Clip launches without crashing
  • The correct screen or feature loads
  • Path parameters are parsed correctly
  • Query parameters are extracted and applied
  • Invalid or unrecognized paths show a graceful fallback

Reading the URL in Code

Add logging to your URL handling code to confirm what your App Clip receives:

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    guard let url = userActivity.webpageURL else {
        print("[AppClip] No URL received")
        return
    }
    print("[AppClip] Invoked with URL: \(url.absoluteString)")
    print("[AppClip] Path: \(url.path)")
    print("[AppClip] Query: \(url.query ?? "none")")

    routeToFeature(from: url)
}

Check the Xcode console output after each launch. If the URL is nil or missing components, your environment variable may be misconfigured or the NSUserActivity is not being delivered correctly.

Installing the App Clip Diagnostics Profile

Apple provides a diagnostics profile that enables additional App Clip debugging features on your device:

  1. Open Settings on your iOS device
  2. Navigate to Developer > App Clips Testing
  3. Enable “Local Experiences”

With local experiences enabled, you can register test URLs on your device that trigger your development App Clip without going through App Store Connect or TestFlight.

Registering a Local Experience

On your device, go to Settings > Developer > Local Experiences > Register Local Experience:

  • URL Prefix: https://yourdomain.com/menu
  • Bundle ID: com.yourcompany.yourapp.Clip
  • Title: Your App Clip Card title
  • Subtitle: Your App Clip Card subtitle

Now when you open this URL in Safari or scan a QR code with this URL, your locally installed development App Clip will launch.

Step 3: Validate the Apple-App-Site-Association File

The AASA file is the bridge between your domain and your App Clip. If it is misconfigured, your App Clip will work in Xcode but fail in every real-world invocation scenario.

File Location and Format

Your AASA file must be hosted at exactly this path:

https://yourdomain.com/.well-known/apple-app-site-association

The file must be:

  • Served over HTTPS with a valid certificate
  • Returned with content type application/json
  • Accessible without any redirects (no HTTP-to-HTTPS redirect, no www redirect)
  • Not behind authentication or a CDN that modifies the response

Required Structure

The minimum AASA configuration for App Clips:

{
  "appclips": {
    "apps": [
      "TEAMID.com.yourcompany.yourapp.Clip"
    ]
  }
}

If you also use Universal Links for your full app, include both sections:

{
  "appclips": {
    "apps": [
      "TEAMID.com.yourcompany.yourapp.Clip"
    ]
  },
  "applinks": {
    "details": [
      {
        "appIDs": [
          "TEAMID.com.yourcompany.yourapp",
          "TEAMID.com.yourcompany.yourapp.Clip"
        ],
        "components": [
          { "/": "/menu/*" },
          { "/": "/parking/*" }
        ]
      }
    ]
  }
}

Common AASA Mistakes

Wrong Team ID: The prefix before your bundle ID must be your Apple Developer Team ID, not your App ID prefix. Find it at developer.apple.com under Membership.

Missing .Clip suffix: The appclips section must reference the App Clip bundle ID (ending in .Clip), not the main app bundle ID.

Redirect in the path: If yourdomain.com/.well-known/apple-app-site-association redirects to www.yourdomain.com/..., the verification will fail. Configure your server to serve the file directly.

JSON syntax errors: Validate your file with a JSON linter before deploying. A single trailing comma or missing bracket will break the entire file.

Testing the AASA File

Use curl to verify the file is accessible:

curl -v https://yourdomain.com/.well-known/apple-app-site-association

Check that:

  • The response code is 200 (not 301, 302, or 404)
  • The content type header includes application/json
  • The JSON body is valid and contains your App Clip bundle ID

Step 4: Debug Domain Verification and Entitlements

Even with a correct AASA file, domain verification can fail due to caching, entitlement mismatches, or CDN behavior.

Using swcutil on macOS

The swcutil tool inspects the system’s cached domain association data. Run it on your Mac connected to your development device:

# Check the AASA file for a specific domain
swcutil dl -d yourdomain.com

# Verify the association status
swcutil verify -d yourdomain.com -j

Look for "appclips" in the output and confirm your App Clip bundle ID appears.

Device Console Logs

Connect your device to your Mac and open Console.app. Filter for swcd (the system daemon that handles app-site associations):

process:swcd

Trigger an App Clip invocation and watch for log messages. Common messages and their meanings:

  • "No matching apps for URL" - Your AASA file does not include the requested URL pattern or the domain is not verified
  • "Failed to verify" - The AASA file could not be fetched or parsed
  • "App ID does not match" - The bundle ID in your entitlements does not match the AASA file

CDN Caching Issues

Apple caches AASA files through its own CDN. After you update your AASA file, it can take up to 24 hours for Apple’s CDN to pick up the change. During development, this is frustrating.

Workarounds:

  • Use the ?mode=developer query parameter when testing (this bypasses the CDN in some configurations)
  • Add the Associated Domains entitlement with the ?mode=developer suffix during development: appclips:yourdomain.com?mode=developer
  • Wait 24 hours after deploying AASA changes before testing in production

Entitlement Verification

Open your App Clip’s .entitlements file and confirm:

<key>com.apple.developer.associated-domains</key>
<array>
    <string>appclips:yourdomain.com</string>
</array>

Make sure this entitlement is in your App Clip target, not just your main app target. Also verify that the provisioning profile for your App Clip includes the Associated Domains capability.

Step 5: Test on Physical Devices

Simulator testing has significant limitations for App Clips. NFC, QR code scanning, location-based triggers, and App Clip Cards only work on physical devices.

TestFlight Distribution

Upload your app (including the App Clip) to App Store Connect and distribute via TestFlight. TestFlight App Clips support invocation from URLs, giving you a more realistic testing environment than Xcode alone.

When testing via TestFlight:

  • Share the invocation URL with testers
  • Testers open the URL in Safari, which triggers the TestFlight App Clip
  • All URL patterns registered in App Store Connect are testable

QR Code Testing

Generate QR codes for each of your invocation URLs. Use any QR code generator and encode the full URL:

https://yourdomain.com/menu/test-restaurant

Scan with the device camera. If the App Clip is correctly configured and the domain is verified, an App Clip Card should appear at the bottom of the screen.

If the QR code opens Safari instead of showing an App Clip Card:

  • Domain verification may have failed
  • The URL may not match any registered pattern
  • The App Clip may not be available in your region or device

NFC Tag Testing

Program an NFC tag with a NDEF record containing your invocation URL. Tap the tag with your test device. The same App Clip Card should appear.

NFC-triggered App Clips have the fastest invocation path. If NFC works but QR codes do not, the issue is likely in how the QR code URL is encoded rather than in domain verification.

App Clip Codes

App Clip Codes are Apple’s proprietary visual codes that combine NFC and visual scanning. You can generate them in App Store Connect under your App Clip’s Advanced App Clip Experiences.

Test both scan modes:

  • Camera scan (visual recognition)
  • NFC tap (proximity trigger)

Step 6: Diagnose App Clip Card and Metadata Issues

The App Clip Card is what users see before they tap “Open” to launch your App Clip. If the card looks wrong or does not appear, users will never reach your experience.

App Store Connect Configuration

In App Store Connect, navigate to your app > App Clip > App Clip Experiences. Verify:

  • Header image: 1800x1200 pixels, displayed at 3:2 aspect ratio
  • Title: Clear and descriptive (up to 32 characters recommended)
  • Subtitle: Supporting text that explains the value (up to 56 characters)
  • Action button: “Open” is the default; verify it matches your use case

Default vs Advanced Experiences

  • Default experience: One card per App Clip, triggered by any registered URL
  • Advanced experiences: Different cards for different URL patterns, locations, or businesses

If you are using advanced experiences, verify that each URL pattern is mapped to the correct card configuration. A mismatch will show the default card instead of the location-specific one.

Testing Card Appearance

The App Clip Card only appears in production or TestFlight builds. You cannot see the card when running from Xcode. To test:

  1. Upload a build to TestFlight
  2. Configure the App Clip experience in App Store Connect
  3. Open the invocation URL on a test device
  4. Verify the card image, title, subtitle, and action button

If the card does not appear at all, check domain verification (Step 4) and ensure the URL matches a registered pattern.

Step 7: Profile Performance and Size Constraints

App Clips must load fast and stay small. Performance issues during debugging often point to size violations or unoptimized asset loading.

Size Limit Verification

The App Clip binary must be under 15 MB uncompressed (10 MB for the initial download on cellular). Check your size with Xcode’s App Thinning Size Report:

  1. Archive your app in Xcode
  2. Select “Distribute App” > “Development”
  3. Check “App Thinning” and select “All compatible device variants”
  4. Review the App Thinning Size Report in the export folder

If your App Clip exceeds the limit:

  • Remove unused frameworks and libraries
  • Compress or reduce image assets
  • Use on-demand resources for non-critical content
  • Strip unused code paths with dead code elimination
  • Audit third-party dependencies for size impact

Launch Time Profiling

App Clips should become interactive within 1-2 seconds. Use Instruments to profile launch time:

  1. In Xcode, select Product > Profile
  2. Choose the “App Launch” template
  3. Run your App Clip and analyze the results

Common launch time issues:

  • Heavy initialization in application(_:didFinishLaunchingWithOptions:)
  • Synchronous network requests on the main thread
  • Large asset loading during startup
  • Third-party SDK initialization blocking the UI

Memory and Network Profiling

App Clips run with the same memory constraints as regular apps, but users expect instant performance. Profile with Instruments:

  • Allocations - track memory usage and identify leaks
  • Network - verify that API calls are minimal and fast
  • Energy - check that location and sensor usage is efficient

Step 8: Debug the App Clip to Full App Transition

The ultimate goal of most App Clips is to convert users to the full app. If this transition breaks, you lose the acquisition value of the entire instant experience.

Data Transfer via App Groups

App Clips and their parent app can share data through a shared App Groups container:

// In the App Clip - save user data
let defaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")
defaults?.set(cartItems, forKey: "pendingCart")
defaults?.set(true, forKey: "hasUsedAppClip")

// In the full app - read App Clip data
let defaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")
if let cart = defaults?.array(forKey: "pendingCart") {
    restoreCart(cart)
}

Verify that:

  • Both targets use the same App Group identifier
  • Data written by the App Clip is readable by the full app
  • The full app checks for App Clip data on first launch
  • Shared data is cleaned up after migration to avoid stale state

Install Prompt Timing

The SKOverlay API lets you show an install prompt within your App Clip:

let config = SKOverlay.AppClipConfiguration(position: .bottom)
let overlay = SKOverlay(configuration: config)
overlay.present(in: windowScene)

Debug the timing carefully:

  • Don’t show the prompt immediately on launch (let the user experience value first)
  • Show it after a meaningful interaction (completed a task, viewed key content)
  • Test that the overlay appears correctly and links to the right App Store listing
  • Verify that tapping “Get” installs the correct app

Seamless Transition Testing

After a user installs the full app from an App Clip:

  1. The App Clip is automatically removed from the device
  2. The full app should detect and restore App Clip data
  3. The user should land in a contextually appropriate screen, not a blank onboarding flow

Test this full flow end-to-end:

  1. Launch the App Clip from a URL
  2. Interact with it and generate some state
  3. Tap the install prompt
  4. Install the full app
  5. Open the full app and verify data was preserved
  6. Confirm the App Clip no longer appears on the home screen

Common Issues Quick Reference

SymptomLikely causeFix
App Clip does not launch from URLDomain verification failedCheck AASA file and entitlements (Steps 3-4)
App Clip launches but shows wrong screenURL routing bugAdd logging and test each URL pattern (Step 2)
App Clip Card does not appearURL not registered in App Store ConnectAdd the URL pattern as an App Clip experience
Card shows default instead of location-specificAdvanced experience URL mismatchVerify URL pattern mapping in App Store Connect
”App Clip not available” errorBinary not uploaded or region restrictionCheck TestFlight or App Store availability
Slow launch timeOversized binary or heavy initializationProfile with Instruments (Step 7)
Data lost after full app installApp Group not configured on both targetsVerify shared container setup (Step 8)
AASA changes not taking effectApple CDN cachingWait 24 hours or use developer mode
Works in Xcode but fails on deviceMissing entitlement on App Clip targetCheck both targets have Associated Domains