Skip to main content
deep-linking

Universal Links Not Working? 15 Causes and the Fix for Each

Universal Links not working or opening Safari? Fifteen causes in order, from address-bar tests to AASA files and handlers, each with the check and the fix.

WarpLink Team13 min read

TL;DR: Universal Links fail for 15 reasons in three groups: a test method iOS never routes to an app, a broken domain-to-app association, or an app that opens and never reads the URL. Rule out the test method first, then check the association: run sudo swcutil dl -d yourdomain.com on a Mac and compare Apple's CDN copy.

Work the reasons in order. The AASA file has its own deep dive, and you can test a domain in one step with the free AASA validator.

The Commands That Find the Cause Fastest

The first must return a 200 with content-type: application/json and no redirect. The second confirms the file downloads on a Mac. The third shows the copy Apple's CDN serves to devices, which must match the file you deployed.

Quick Triage: Which Group Are You In?

A developer on the Apple Developer Forums described the version of this that wastes the most time: "despite having a correctly configured AASA file and associated domains setup, our application does not consistently handle Universal Links and we simply end up getting a blank page... after successful login the control never gets passed back to the iOS mobile app."

That quote holds two different bugs. "Opens Safari instead of the app" means iOS did not hand the URL to your app. "Opens the app but shows a blank page" means your app got the URL and did nothing with it. Fixing one does nothing for the other. Tap the link and see what happens.

What you seeGroupReasons
Works for some taps, never from the address bar or a social appTesting1 to 6
Opens Safari or the App Store on a real tapAssociation7 to 12
Opens the app, shows the wrong screen or nothingHandler13 to 15

Each reason below follows one pattern: the symptom, the check, and the fix.

1. You Pasted the URL Into the Address Bar

Symptom: The page loads in Safari and the app never opens.

Check: Did you type or paste the link into the address bar? Apple's debugging note TN3155 says entering the URL directly "will never open the app, as this is direct navigation within the web browser."

Fix: Paste the link into Notes, then tap it or long-press it. Apple's recommended test shows both the app option and the browser option when the setup is correct.

Symptom: The link works from Notes and fails from a button on your own website.

Check: Is the page you tapped from on the same domain as the link? Apple's docs say a universal link tapped on the same domain in Safari opens in Safari, and TN3155 says the browser "will expect the user wants to continue navigating within the browser."

Fix: Put your links on a different host than the page that shows them, such as go.yourdomain.com with its own AASA file and its own entitlement entry. Apple recommends a different subdomain for this case.

3. You Tapped Inside an In-App Browser

Symptom: The link opens a web view inside Instagram, X, or Facebook.

Check: Open the same link from Messages or Notes. If it opens your app there, the association is fine.

Fix: There is nothing to fix in your app. The embedding app controls the tap. See Deep Links in Instagram and Facebook In-App Browsers for the cases and the workarounds.

4. You Are Testing on the Simulator

Symptom: The link opens inconsistently on the Simulator and works on a device, or the reverse.

Check: xcrun simctl openurl booted "https://yourdomain.com/path" opens the app only when the entitlement lists the host and the domain serves a valid AASA file that matches the path.

Fix: Use a physical device for the final check. Tapping links inside the Simulator is unreliable.

5. A Saved Choice Sends This Domain to the Browser

Symptom: The link worked before, and now it always opens the browser.

Check: Paste a link to the domain into Notes and long-press it. If the default is the browser, iOS saved that choice. TN3155 notes that "the option you choose will set the default behavior for your device when following universal links from this domain in the future."

Fix: Repeat the same steps and choose to open the link in your app. There is no API to reset the choice from your code.

6. The Device Is Holding an Old Copy of the File

Symptom: You fixed the AASA file and nothing changed on a device that already has the app.

Check: Apple's docs say the app no longer fetches the file from your server. Since iOS 14 it asks an Apple-managed CDN, the CDN requests your file "within 24 hours," and devices check for updates "approximately once per week after app installation."

Fix: Delete and reinstall the app to force a fresh check. For development, append ?mode=developer to the entitlement (applinks:yourdomain.com?mode=developer) and switch on Settings > Developer > Associated Domains Development to bypass the CDN. Remove the mode before you ship.

7. The AASA File Is Not Reachable the Way iOS Fetches It

Symptom: The link opens the browser on a real tap, from a clean install.

Check:

Apple requires the file at https://<fully qualified domain>/.well-known/apple-app-site-association with no extension, served over https:// with a valid certificate and "with no redirects." Serve it as application/json. On a Mac, sudo swcutil dl -d yourdomain.com confirms the file downloads.

Fix: Remove every redirect (http to https, apex to www), fix the certificate, and make sure the response is a direct 200 with no login wall. Allow Apple's CDN through any firewall or bot protection. You can test a domain in one step with our free AASA validator. The full file checklist is in Universal Links Open Safari? Fix Your apple-app-site-association File.

8. The appIDs Value Is Wrong

Symptom: The file is reachable, valid JSON, and the app still does not open.

Check: Apple's format for an app ID is <Application Identifier Prefix>.<Bundle Identifier>, such as ABCDE12345.com.example.app. Compare it with your Team ID in the developer account and the bundle ID in Xcode.

Fix: Correct the value in appIDs, keeping the Team ID, a dot, and the exact bundle ID.

9. The components Do Not Match the URL Path

Symptom: Some links open the app and others open the browser.

Check: Look at components in the file. A rule such as { "/": "/buy/*" } matches only paths that start with /buy/. An exclude rule can block a path that a broader rule allows. On a Mac, sudo swcutil verify -d yourdomain.com -j aasa.json -u https://yourdomain.com/buy/1 prints whether the pattern matched.

Fix: Add or widen the rule for the path you link to, and check that no exclude entry catches it. The older paths array is the legacy form of components, so do not mix the two in one entry.

10. The Associated Domains Entitlement Is Wrong

Symptom: The file passes every check and the app was never associated with the domain.

Check: The entitlement value must look like applinks:yourdomain.com. Apple's format is <service>:<fully qualified domain> and says to include only the subdomain and top-level domain, with no path, query, or trailing slash.

Fix: Use the bare host: no https://, no path, no port. Rebuild and reinstall.

Symptom: Links to yourdomain.com work and links to go.yourdomain.com do not.

Check: Apple says each subdomain "requires its own entry in the Associated Domains Entitlement, and each must serve its own apple-app-site-association file." applinks:yourdomain.com does not cover www.yourdomain.com.

Fix: List each host, or add the wildcard form applinks:*.yourdomain.com, and confirm the file is reachable at every host you actually link to.

12. The Provisioning Profile Lacks the Capability

Symptom: The entitlement is in Xcode and the installed build still ignores the domain.

Check: Open the signed build's entitlements and confirm com.apple.developer.associated-domains is present. Adding the capability in Xcode is not enough if the profile that signs the build was generated before you enabled it.

Fix: Regenerate the provisioning profile with the Associated Domains capability, re-sign, and reinstall.

13. The Warm-Start Handler Is Missing

Symptom: The app opens from the background and shows a blank screen or the wrong screen.

Check: iOS delivers a Universal Link as an NSUserActivity. With a SceneDelegate, it arrives in scene(_:continue:). Implementing application(_:continue:restorationHandler:) on the AppDelegate does not fire while scenes are active.

Fix:

On macOS or Mac Catalyst, use .onContinueUserActivity(NSUserActivityTypeBrowsingWeb). On iOS, .onOpenURL already covers Universal Links.

14. The Cold-Start Handler Is Missing

Symptom: Links work with the app in the background and fail when it is closed.

Check: When the app is not running, scene(_:continue:) does not fire. The activity arrives in the connection options at launch.

Fix:

That one asymmetry sits behind many "it works sometimes" reports.

15. A Login Redirect Is Supposed to Return to the App

Symptom: After sign-in, the user stays in the web view and the app never comes back, which is the forum quote above.

Check: Is the return trip an https://yourdomain.com/callback link that an identity provider reaches by redirect? Apple's TN3155 says a redirect to a universal link from another app is allowed, "although not preferred," and routes the user through the browser to the app. Universal Links are built for a user tap.

Fix: Claim the callback path in components and handle it with the scene handlers above. For OAuth and web checkout, use ASWebAuthenticationSession with a custom callback scheme (callbackURLScheme), which intercepts the return itself. An HTTPS callback is possible on iOS 17.4 and later.

iOS Versions and Cross-Platform Apps

Behavior around callback timing has shifted across iOS 15 through 18, so test on the OS versions your users run. React Native, Expo, Capacitor, and Flutter sit on the same native machinery. A Universal Link that fails there fails for one of the reasons above, so debug it as an iOS problem first and then confirm the framework's link listener is wired up.

The Short Version

Reasons 7 to 9 are about hosting the AASA file correctly. When you register an app in WarpLink, we generate and serve the apple-app-site-association file for you, with the right content type and no redirects. Each app gets its own link host, {handle}.aplnk.to, and each host has its own AASA and assetlinks pair, which matches how iOS and Android tie a link host to one app. The file is regenerated when you change the app, and verified custom domains get their own pair too.

To check the result, open https://{host}/test on your app's host. It is a setup page served at the edge that shows the host is ready, so you can confirm the file is live before you test a tap. Reasons 13 and 14 collapse into one call: pass the incoming URL to WarpLink.handleDeepLink(url) from your scene handler or .onOpenURL, and it returns the destination, custom parameters, and attribution data on the main thread, for cold and warm start. The full setup is in the iOS deep links docs, and the deep linking page shows what an app registration generates.

Frequently Asked Questions

Why are my Universal Links not opening on iOS 26? First rule out the testing mistakes in reasons 1 to 6, which catch most reports: pasting into the address bar, same-domain taps, in-app browsers, the Simulator, a saved Safari choice, and a stale cached file. If it is a real failure, the cause is the same as on earlier versions: the AASA file, the entitlement, or a missing link handler.

How do I re-enable a Universal Link that iOS disabled? If you once chose to open a domain's links in the browser, iOS keeps that choice for the domain. Paste a link to the domain into Notes, long-press it, and choose the option to open it in your app. Apple documents the same steps to change the default.

Why does Private Relay not break my Universal Links? Private Relay masks the device IP. That affects IP-based deferred deep link attribution, not Universal Link routing or the AASA fetch. If links open the browser, check the file and the entitlement first.

Why do Universal Links work in the background but not on a fresh launch? That is the cold-start handler gap in reason 14. The app handles the warm-start path with scene(_:continue:) or .onOpenURL but does not read connectionOptions.userActivities in scene(_:willConnectTo:options:). Add the cold-start handler.

Why does the link open my app but land on the home screen? The app received the URL but is not routing it, or is not reading it at all. Confirm your link handler is implemented for your app lifecycle and that it parses the path. This is a code problem, not an AASA problem.

Sources

  • Apple Developer Documentation, Supporting associated domains: the file location, valid certificate and no redirects, the CDN and weekly update check, alternate mode, wildcard subdomains, the entitlement format, one file and one entry per subdomain, and the app ID format.
  • Apple Developer Documentation, TN3155: Debugging universal links: same-domain behavior, direct navigation, testing in Notes, the saved default choice, Developer Mode diagnostics, swcutil, and redirects from another app.
  • Apple Developer Documentation, Allowing apps and websites to link to your content: how the system routes a universal link, and the same-domain rule in Safari.

Once your links open the right screen, the next question is which link and channel drove the tap and the install. That is what WarpLink install attribution answers after the link resolves.

Check the file with the free AASA validator, then let WarpLink host and update the AASA file and handle the cold start out of the box.

Get your first deep link working today

Deep linking, install attribution, and real-time analytics in one SDK. Free for 10K clicks a month, no sales call.

WarpLink is link infrastructure that sends one link to the right place on iOS, Android, and the web, with install attribution and real-time analytics on every tap.

Stuck on setup? Email support@warplink.app and we will help you get one real link working.

WarpLink Team

Building affordable, reliable link infrastructure for mobile teams. Deep linking, install attribution, and real-time analytics in one SDK.