Skip to content

Troubleshooting iOS Deep Links

Visit https://your-domain/.well-known/apple-app-site-association in a browser. Verify:

  • The file loads without redirects (redirects break AASA validation).
  • The appID field matches <TeamID>.<BundleID> exactly.
  • The paths array includes the route prefix you are testing.
  • Content-Type is application/json.

Use Apple’s AASA Validator to check for issues.

In Xcode, go to your target’s Signing & Capabilities and verify:

  • The Associated Domains capability is added.
  • The entry reads applinks:your-domain.com (no https://, no trailing slash).
  • If using both a Tolinku subdomain and a custom domain, both are listed.

In the Tolinku dashboard under Appspace Settings > iOS:

  • Bundle ID must match your Xcode project exactly.
  • Team ID must match your Apple Developer account (found in Membership details).
  • The route must have Universal Link enabled.

iOS caches the AASA file aggressively:

  • On iOS 14+, Apple fetches AASA files through its CDN. Changes may take up to 24 hours to propagate.
  • Deleting and reinstalling the app forces a fresh AASA fetch.
  • During development, you can use the ?mode=developer flag on the associated domain entry: applinks:your-domain.com?mode=developer. This bypasses the Apple CDN and fetches directly from your server.

If a user long-presses a Universal Link and chooses “Open in Safari”, iOS remembers this preference. All subsequent taps on that domain will open in Safari.

Fix: Long-press the link again and choose “Open in [App Name]” to restore the default behavior.

This is an iOS behavior that cannot be overridden programmatically.

Section titled “Links work from Messages but not from Safari”

This is expected behavior. Universal Links triggered from within Safari on the same domain open in Safari, not the app. This is Apple’s same-domain restriction.

Workaround: Use a different domain for your website and your deep links. For example, use links.myapp.com for deep links and www.myapp.com for your website.

Work through these in order. The first is by far the most common cause.

1. Check your appspaceId is the Appspace ID, not the subdomain.

This is the single most common cause of a claim that never matches. If your Appspace is at myapp.tolinku.com, your Appspace ID is not myapp. Copy the real value from the dashboard under Settings, at the top of the General panel. It looks like 64f0a1b2c3d4e5f60718.

To confirm this is your problem, call the endpoint against your own Appspace domain rather than api.tolinku.com:

Terminal window
curl -X POST https://YOUR-SUBDOMAIN.tolinku.com/v1/api/deferred/claim-by-signals \
-H 'Content-Type: application/json' \
-d '{"appspace_id":"WHAT-YOUR-APP-SENDS","timezone":"UTC","language":"en-US"}'

A 403 appspace_id does not match this domain confirms the ID is wrong. A 404 means the ID is accepted and no click is currently waiting for that device.

2. Confirm the click reached Tolinku at all.

Every landing page mode collects device signals, including None. That mode redirects straight to the store, so it serves a small page that reports the signals and replaces itself in the same moment, which costs the visitor nothing noticeable. You do not need to switch a route to Generic or Custom for deferred linking to work.

What does prevent collection is the click never reaching us: a link opened directly in the app through Universal Links (in which case the app already has the URL and does not need deferred linking), or a click on a domain that is not configured for your Appspace.

3. Check the timing. Signal matching only considers clicks from the last 2 hours, which is shorter than the 24 hour window for token-based claiming.

4. Check the signal formats. Timezone must be an IANA name (Asia/Seoul, not KST). Screen dimensions must be logical/CSS pixels, matching what screen.width reports in the browser, so divide Flutter’s physicalSize by devicePixelRatio.

Language should be a full BCP-47 tag (ko-KR). A bare primary subtag (ko) also matches, since the server compares leniently when either side omits the region, but two tags that both carry a region must agree on it (ko-KR does not match ko-KP).

5. Call it on the very first app open, before any navigation.

6. Network changes. A WiFi to cellular handoff during the store download, carrier CGNAT, or a VPN can change the device’s address between click and install. Tolinku falls back to matching within the same subnet, but that fallback requires all four signals to agree.

Section titled “The link opens the App Store even though the app is installed”

This looks like a broken entitlement and usually is not. If iOS does not recognise the URL as belonging to your app, it hands it to Safari, Safari follows the redirect, and the visitor lands in the App Store with your app already on their phone.

Check in this order:

  1. Is the path in your association file? Open https://your-domain/.well-known/apple-app-site-association and confirm the path you are testing appears. Both a route’s prefix and its short code are listed, so /product-detail/* and /rujo02w/* should both be there for the same route.
  2. Is the route’s Universal Links setting on? A route with it disabled is deliberately left out of the file.
  3. Reinstall the app. iOS fetches the association file when the app is installed and caches it. A change to your routes does not reach an existing install, so a build from before the change keeps the old list.
  4. Check how the link is being opened. Universal Links do not fire when a URL is typed into Safari’s address bar, or when it is opened from the same domain you are already on. Test by tapping a link in Messages or Notes.
  • Verify the URL’s host matches a domain in your Associated Domains entitlement.
  • Check that the URL path matches a route with Universal Links enabled.
  • handleUniversalLink only parses the URL; it does not make API calls. If it returns nil, the URL format is unexpected.
  1. AASA file accessible at /.well-known/apple-app-site-association (no redirects).
  2. Bundle ID and Team ID set in Appspace Settings.
  3. Route has Universal Links enabled.
  4. Associated Domains entitlement added in Xcode with correct domain.
  5. App installed on a physical device (Universal Links do not work in Simulator).
  6. Link opened from a different domain (not same-domain).
  7. SDK initialized with Tolinku.configure(apiKey:) before handling links.