Skip to content
Tolinku
Tolinku
Sign In Start Free
iOS Development · · 8 min read

Universal Links and Redirects: Why They Break and How to Fix Them

By Tolinku Staff
|
Tolinku universal links dashboard screenshot for ios blog posts

You set up Universal Links correctly. The apple-app-site-association (AASA) file is valid JSON, it is served at the right path, your app entitlements are correct, and testing with a direct link works perfectly. Then you drop the URL into your email campaign, wrap it in a click tracker, and suddenly the link opens Safari instead of your app.

This is one of the most common Universal Links problems in production, and it comes down to a single rule that Apple does not make obvious: iOS checks the domain of the URL it initially receives, not the domain of the final destination after redirects.

This guide explains why that matters, walks through the scenarios where it causes failures, and covers every practical solution. If you need a refresher on Universal Links fundamentals, start with our complete Universal Links guide.

The Core Problem: iOS Reads the First Domain, Not the Last

When a user taps a Universal Link, iOS checks its locally cached copy of the AASA file for the domain in that URL. If the AASA file is registered for that domain and the path matches, iOS opens your app. If not, it falls through to Safari.

Here is what iOS does not do: follow HTTP redirects and check the AASA file at the final destination. The Universal Link check happens at the very first URL, before any redirect occurs.

This behavior is documented by Apple, though it is easy to miss in the middle of a longer setup guide.

So if the tap URL is https://click.emailprovider.com/track?url=https://yourdomain.com/product/123, iOS looks for an AASA file on click.emailprovider.com. That domain almost certainly has no AASA file, or its AASA file has no entry for your app. iOS falls back to loading the URL in Safari. Safari follows the redirect, lands on your domain, and your app never opens.

Common Redirect Chain Scenarios

Email Click Trackers

Email marketing platforms (Mailchimp, Klaviyo, Brevo, Iterable, and others) wrap every link in your email with their own tracking URL. Our article on Universal Links in email covers platform-specific workarounds for the most popular email services. The real destination is encoded as a query parameter. When the recipient taps the link, the platform records the click and then issues a redirect to your URL.

The tap URL looks like:

https://click.mailchimp.com/track/click/XXXXXXXX/yourdomain.com?p=eyJzIjoiX1...

iOS sees click.mailchimp.com and checks for an AASA file there. There is none that covers your app. Universal Link fails.

URL Shorteners

Services like Bitly, t.co, short.io, and similar shorteners produce URLs on their own domains. Tapping https://bit.ly/3xYzAbc means iOS checks bit.ly for your AASA. This will never work unless you control the short domain and host your AASA file there.

Marketing Attribution Platforms

Any platform that wraps links to record UTM parameters, device fingerprints, or attribution data runs the same redirect pattern. The click goes to the platform's domain first, gets recorded, and then redirects to your destination.

CDN and Load Balancer Redirects

A subtler case: your own infrastructure redirecting between domains or subdomains. If your CDN redirects www.yourdomain.com to yourdomain.com (or vice versa), the AASA file must be configured correctly on both the initial domain iOS sees and the final domain. Both hostnames need entries in your app's Associated Domains entitlement.

Similarly, HTTP-to-HTTPS redirects. If someone taps an http:// link, iOS will not apply Universal Links to it at all. Universal Links only activate for https:// URLs.

Vanity Domains and Custom Short URLs

Marketing teams often use branded short domains like go.yourcompany.com or links.yourapp.com. These are great for branding, but they need their own AASA file and their own Associated Domains entry in your app. Many teams set up the redirect but forget the AASA registration.

Solutions

Option 1: Register AASA on Every Domain in the Chain

If you control every domain in the redirect chain, you can host an AASA file on each one and add each domain to your app's Associated Domains entitlement.

For a branded short domain like go.yourcompany.com, this is the clean solution:

  1. Host your AASA file at https://go.yourcompany.com/.well-known/apple-app-site-association
  2. Add applinks:go.yourcompany.com to your app's Associated Domains entitlement
  3. Configure the short link to redirect to https://yourdomain.com/path

The first URL iOS sees is go.yourcompany.com, it finds the AASA file, and it opens your app directly without following the redirect at all. For a complete walkthrough of setting up and validating the AASA file, see our AASA file setup guide.

Example AASA for the short domain:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.yourcompany.app"],
        "components": [
          { "/": "/*" }
        ]
      }
    ]
  }
}

You do not need to reproduce your full path configuration on the short domain. A wildcard /* works because iOS opens the app for any path, and your app receives the short URL. Your app (or your deep link routing logic) can then resolve the short URL to the full destination path.

For email campaigns, some platforms let you disable click tracking for specific links, or they let you use your own tracking domain. If you can serve the tracking URL from your own domain (say, track.yourdomain.com) and AASA-register that domain, the link will work.

Some platforms support "branded tracking domains" specifically for this purpose. The setup varies by platform, but the concept is the same: the click tracker runs on a domain you control, you host the AASA there, and iOS sees your domain first.

Option 3: The JavaScript Redirect Workaround

If you cannot control the redirect chain at all, a JavaScript-based redirect can help in limited cases. Instead of a server-side HTTP 301/302 redirect, the intermediate page loads in Safari and runs JavaScript that sets window.location to your Universal Link target.

The reason this sometimes works is that iOS evaluates Universal Links when a tap originates from certain contexts (like Safari links to other domains), but same-domain navigation in Safari does not always trigger the Universal Link check. The JavaScript approach changes the navigation context.

However, this is fragile. Whether the Universal Link activates depends on how the navigation was initiated and which iOS version is running. It also requires a real web page to load before the redirect fires, adding latency. Using SFSafariViewController for deep links instead of WKWebView can help in some in-app browser scenarios, but for general redirect chains, treat JavaScript redirects as a last resort, not a reliable production strategy.

Option 4: Accept the Fallback and Handle It on the Web

For cases you cannot fix on the link side (third-party click trackers you cannot control), design your web fallback page to do the work.

When the link opens in Safari and lands on your web page, you can use the Smart App Banner meta tag to prompt users to open the app, or you can use JavaScript to attempt a custom URI scheme open first, then fall back to the App Store. This is not as seamless as a Universal Link opening the app directly, but it recovers the session.

<meta name="apple-itunes-app" content="app-id=YOUR_APP_STORE_ID, app-argument=https://yourdomain.com/path">

Platforms like Tolinku handle this fallback logic automatically, including deferred deep linking so users land on the right screen after installing the app.

Server-Side vs. Client-Side Redirects

The distinction matters for Universal Links. A server-side redirect is an HTTP 301 or 302 response. The browser (or iOS) receives the response, reads the Location header, and makes a new request to the redirect target. iOS evaluates the Universal Link check on the initial URL before any server response arrives.

A client-side redirect is HTML or JavaScript that fires after the page loads (<meta http-equiv="refresh">, window.location =, etc.). The initial request loads a real page, and only then does the redirect occur.

For Universal Links, both cases result in the same problem: iOS checked the original domain before anything else happened. The type of redirect does not change that.

Testing Redirect Chains

Before debugging iOS behavior, map out the full redirect chain so you know exactly what iOS is seeing.

Use curl with the -L flag to follow redirects and the -I flag to print headers only:

curl -ILv "https://click.emailprovider.com/track?url=https://yourdomain.com/product/123"

The -v verbose flag shows each request and response header. You will see each Location: header and can trace the full chain from the initial URL to the final destination.

A cleaner view using just the effective URL:

curl -Ls -o /dev/null -w "%{url_effective}" "https://your-short-link.com/abc"

To see every hop explicitly:

curl -v -L --max-redirs 10 "https://your-short-link.com/abc" 2>&1 | grep -E "^(> GET|< HTTP|< Location)"

This gives you output like:

> GET /abc HTTP/2
< HTTP/1.1 301 Moved Permanently
< Location: https://click.tracker.com/r?url=https%3A%2F%2Fyourdomain.com%2Fproduct%2F123
> GET /r?url=... HTTP/2
< HTTP/1.1 302 Found
< Location: https://yourdomain.com/product/123
> GET /product/123 HTTP/2
< HTTP/1.1 200 OK

Once you have the full chain, you know which domains need AASA files. For each domain in the chain (except the final one if iOS is opening the app before following redirects), check whether it has a valid AASA:

curl -s "https://click.tracker.com/.well-known/apple-app-site-association" | python3 -m json.tool

If that returns a 404 or malformed JSON, that domain is the break point.

Verifying Your AASA Registration

Apple's CDN caches AASA files, so changes take time to propagate. Use the Apple App Site Association validator with caution (it is a competitor tool), or test directly using Apple's CDN endpoint:

curl -s "https://app-site-association.cdn-apple.com/a/v1/yourdomain.com" | python3 -m json.tool

This is the exact file Apple's servers have cached for your domain. If this does not match what you have at /.well-known/apple-app-site-association, Apple has not picked up your changes yet. Updates typically propagate within 24 hours after a new app install or update.

For testing your full link before publishing a campaign, use the Apple WWDC Universal Links test flow: paste the final tap URL into Apple Notes on a real device and long-press the link. The context menu will show "Open in Safari" if Universal Links are not activating, or your app name if they are. This bypasses some of the redirect complexity and lets you verify that the AASA is correctly registered.

A Practical Checklist

When a Universal Link is opening Safari instead of your app through a redirect chain, work through this in order:

  1. Use curl -ILv to map the full redirect chain
  2. Identify the first domain iOS will see (the tap URL)
  3. Check whether that domain has a valid AASA file with your app's Team ID and bundle ID
  4. Check whether that domain is listed in your app's Associated Domains entitlement (applinks:that-domain.com)
  5. Verify Apple's CDN has the AASA by fetching https://app-site-association.cdn-apple.com/a/v1/that-domain.com
  6. If you cannot put an AASA on that domain, look for a way to eliminate the redirect (direct links, branded tracking domain, or disabling click wrapping)
  7. If none of that is possible, build a web fallback that recovers the session

Redirect chains are one of the most common reasons Universal Links break in production. The fix is almost always the same: get your AASA on the domain iOS sees first. Once you understand that rule, debugging these failures becomes straightforward.

For more on Universal Links configuration and troubleshooting, see the Tolinku iOS troubleshooting guide.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.