deep-linking

Email Deep Linking: Why Tracked Links Break Universal Links

Email deep linking breaks because click tracking rewrites every link to a tracking domain, so Universal Links never fire. The mechanism, the fixes, and ESPs.

WarpLink Team··20 min read

TL;DR: Email deep linking breaks because click tracking rewrites every link in your message to your provider's tracking domain, and that rewritten URL is the one the recipient actually taps. iOS and Android hand a link to your app only when the tapped domain is one your app has verified, so a tracking domain with no apple-app-site-association and no assetlinks.json sends the tap to a browser. The 302 that follows is a server redirect rather than a user tap, and neither platform treats it as one. Three fixes work: run click tracking on a branded domain that serves your association files, exclude deep link URLs from tracking, or point the email at a link domain that does the redirect and the analytics itself. Several major providers support the first in 2026, including SendGrid, Klaviyo, Iterable, Customer.io, and Amazon SES, each with different mechanics. Recipients without the app are a separate case: a deferred deep link carries the destination through the install and keeps working even when the Universal Link does not.

Why Email Deep Linking Breaks: The Tracking Domain Owns the Tap

You built the link correctly. https://links.yourapp.com/spring-sale sits on your associated domain, the AASA file is valid, the entitlement is in the provisioning profile, and tapping that URL from Messages opens the app on the right screen. Paste it into a campaign, send yourself a test, tap it in your inbox, and you get a web page.

Nothing about your app changed between those two taps. The URL did.

What click tracking does to your HTML

Every mainstream email service rewrites links to measure clicks. The anchor you authored:

goes out on the wire as something closer to this:

The original destination is encoded in the path or a query parameter. The recipient's tap requests the tracking URL, the provider records a click against that recipient, and the response is a 302 to your real link. For a web page this is invisible and harmless. For a deep link it is fatal, because of the order in which the operating system makes its decision.

The decision happens before the redirect

Universal Links work through a domain-to-app association. iOS fetches apple-app-site-association from https://<domain>/.well-known/apple-app-site-association, checks that the file names your Team ID and bundle ID, and checks the tapped path against the declared components. Apple is strict about that fetch: HTTPS, application/json, no redirects (Technical Q&A QA1916).

Now walk the email tap through that machinery. The domain in the tapped URL is click.esp-domain.com, so that is what iOS looks up. Either there is no AASA file, or there is one belonging to the email provider that never mentions your app. Either way the domain is not associated with an installed app, and the URL goes to a browser.

The redirect to links.yourapp.com happens after that decision, inside the browser, and does not reopen the question. A tap is a user gesture on a specific URL. A 302 is a server telling a browser where to go next. The association is evaluated against the first one. This is also why Universal Links are a poor OAuth callback target, and it is the model working as designed rather than a bug in your configuration.

The App Links version of the same story

Android reaches the same outcome by a different route. App Links verification runs against the host in the intent's data URI: the system checks https://<host>/.well-known/assetlinks.json for an entry whose package_name and sha256_cert_fingerprints match the installed app, and on Android 12 and later an unverified host is never offered to your app.

The tracking domain is an unverified host, so the intent resolves to the browser, the browser follows the redirect, and your verified domain is reached by a navigation rather than by an intent. Chrome does not restart link verification for a redirect it followed itself.

You can read the verification state on a device with adb shell pm get-app-links com.yourapp.android. Your own domain will read verified. The tracking domain will not appear at all, because your manifest never declared it, which is exactly the point.

Why some people insist it used to work

Redirect handling has never been perfectly consistent. Teams have shipped chains that opened the app on some iOS versions and broke on an update with no code change, and developers reported exactly that on iOS 18, where a tracking link redirecting into a Universal Link opened the App Store or a browser after working on iOS 17 (Apple Developer Forums thread 780496). A behaviour that shifts across point releases is not a foundation.

Custom URL schemes are the other source of false confidence: they still resolve through redirects in some clients, so a team that tested with yourapp:// declares the problem solved. A scheme URL has no domain verification and no store fallback, so it fails silently for every recipient without the app.

The Three Fixes, and When Each One Is Right

There are three shapes of solution. Everything else is a variation on one.

Fix 1: a branded tracking domain that serves your association files

Keep click tracking, but move it onto a domain you control, such as click.yourapp.com, and get your apple-app-site-association and assetlinks.json served from it. Then add that domain to your Associated Domains entitlement and your App Links intent filter, exactly as you did for your main link domain.

Now the tapped URL is on a verified host, so both platforms hand the tap to your app and your provider still records the click, because the click event comes from the request the tracking domain would have received anyway. Providers that support this either host the files for you after you upload them or let you route the .well-known paths yourself.

It is the best outcome available, and the one with the most moving parts: a DNS change, HTTPS on the tracking domain, two association files kept in sync with your signing configuration, and a path structure the provider and your AASA agree on.

Turn tracking off for the links that must open the app and leave it on for everything else. The anchor goes out with your real URL intact, the tap lands on your verified domain, and the app opens. Most providers expose this per link rather than per campaign. Amazon SES uses an attribute on the anchor:

Others expose a checkbox in the editor or a template flag. The cost is what it sounds like: your email dashboard shows a suspiciously low click rate for that link. The tap is still measured by the link domain the user lands on, so the number moves rather than disappears. What you lose is the per-recipient click record that drives click-triggered automations, so check what is wired to those events first.

Send https://links.yourapp.com/spring-sale with tracking disabled and let the link domain redirect, resolve the platform, and record the click. This is fix 2 plus a deliberate decision about which system owns click measurement.

The advantage is that the same URL works everywhere else without a second thought. In a push notification, an SMS, a QR code, or a social bio it produces one set of click analytics under one set of rules, and the email provider goes back to measuring delivery, bounces, opens, and unsubscribes. It also keeps deep linking and attribution in one place: a link domain that already hosts your association files, resolves the platform, and stores the click for deferred matching does not care that the tap came from an email.

Choosing between them

SituationFix
Your ESP supports a branded tracking domain and hosts association files1
Your ESP supports a branded domain but will not serve .well-known paths2 or 3
You need per-recipient click events for automations on this exact link1
You send the same link across email, SMS, push, and print3
You are debugging right now and need it working today2

What the Major Providers Support in 2026

Support is real but uneven, and details change. Verify against your provider's current documentation before planning a send; every claim below links to its source.

ProviderBranded click tracking domainAssociation files on that domainPer-link opt-out
SendGridYes, via link brandingYes, you host them and tag linksYes
KlaviyoYes, self-serve on paid plansYes, Klaviyo hosts themNot verified
IterableYes, tracking domain per projectYes, uploaded per destination domainNot verified
Customer.ioYes, link tracking on your domainOn your domain, with a signed link requirementYes
Amazon SESYes, custom open and click domainsNot served by the providerYes
BrazeDepends on the sending provider underneathGuidance to host on the tracking domainYes

"Not verified" means we did not find it documented, not that it is unavailable.

SendGrid takes the tagging approach. You brand your links onto your own domain, then mark individual anchors with universal="true", which changes the wrapped URL path to include /uni/. Declare that path in your AASA components and your Android intent filter, and only tagged links are treated as app links while the rest stay ordinary tracked web links. The association files must be served over HTTPS under that same branded domain (SendGrid docs).

Klaviyo requires a dedicated click tracking domain for Universal Links and App Links in email, then hosts the files for you at https://<your tracking domain>/.well-known/apple-app-site-association and the assetlinks.json beside it. Dedicated click tracking is self-serve from account settings on paid plans (setup guide, dedicated click tracking).

Iterable rewrites message URLs to a tracking domain it hosts, such as links.yourdomain.com. You configure destination paths for that domain, upload the apple-app-site-association and assetlinks.json files per destination, and verify them at https://<your tracking domain>/apple-app-site-association. HTTPS on the click recording domain is a prerequisite (iOS Universal Links, deep links setup).

Customer.io documents Universal Link and App Link tracking through a Liquid tag rather than a wrapper, and adds a constraint worth knowing before you improvise: each link ID is cryptographically signed against your tracking domain, so the click request has to arrive on that same domain to validate (Customer.io docs).

Amazon SES supports custom domains for open and click tracking (configuration guide) and, since August 2026, a ses:custom-path attribute that carries a path segment through into the tracking URL so the operating system can match it against your Universal Links or App Links configuration without disabling tracking. The attributes are mutually exclusive: with ses:no-track on the same anchor, tracking is off and ses:custom-path has no effect (announcement).

Braze states the general rule most clearly, because it sits on top of a sending provider and has to explain the constraint rather than solve it. Host the AASA file on the click tracking domain as well as your primary domain, and when that domain cannot serve .well-known paths, either disable click tracking on deep link URLs or front the tracking subdomain with a CDN that serves the association files locally and proxies everything else (Braze docs).

Absence matters too. If your provider's help center has no article on Universal Links, App Links, or .well-known hosting, assume fix 1 is unavailable.

Mail Client Behaviour: Apple Mail, Gmail, and Outlook

Even with the link correct, the recipient's client decides what a tap means. This layer changes more often than the platform layer, so retest it each release cycle.

Apple Mail

The straightforward case. A tap in Apple Mail reaches the system as a real link tap, so a URL on a properly associated domain opens your app on iOS 17 and 18 with no special handling. If Apple Mail still opens Safari, the cause is the association, not the client, and the Universal Links triage applies unchanged.

One Apple Mail behaviour affects your numbers rather than your routing. Mail Privacy Protection preloads remote images, so the tracking pixel fires whether or not a human read the message. It inflates opens, does not touch taps, and does not affect deferred matching, which is keyed to the request the device makes when the person taps.

Gmail

As of September 2026, Gmail opens links in an in-app browser by default on both platforms, and that is the whole story for deep linking.

On Android the setting is explicit: as of this writing Gmail's general settings include an option to open web links in Gmail, on by default, which routes taps into an embedded browser built on Custom Tabs. Turning it off sends links to the default handler, which is the path where App Link verification applies. You cannot change that setting for your recipients, and Google has moved this default before.

On iOS, Gmail has likewise preferred its own in-app browser, with a default browser setting inside the app. Universal Links are unreliable from inside embedded web views generally, and Gmail's behaviour has changed more than once across versions, so test the current build rather than trusting a claim from a blog post, including this one.

Gmail is therefore the client where fix 1 pays off least and the deferred safety net matters most. Plan for a share of taps landing on a web page even when everything is configured correctly, and make that page render the content and offer a control to continue in the app, which produces a real tap on your verified domain.

Outlook

Outlook has a problem the others do not, and it belongs to the recipient's employer. Microsoft 365 tenants can enable Safe Links, which rewrites URLs in inbound mail to *.safelinks.protection.outlook.com with the original URL encoded as a parameter. The recipient taps a Microsoft domain, so the association check runs against a Microsoft domain, and nothing you configure changes that (Microsoft Q&A on Outlook and app links). The documented remedy is an exclusion in the tenant's Safe Links policy, which needs the recipient's IT administrator: available for an enterprise customer you have a relationship with, not for a consumer list.

Outlook mobile also tends to route taps through its own browser preference rather than the system default. For business audiences, assume a share of Outlook recipients will never open your app from an email link, and design the landing experience for them.

A note on scanners

Security products, prefetchers, and link checkers fetch URLs from their own servers before any human is involved, and those requests reach your link domain looking like clicks. Counts inflate unless the redirect layer filters known bot user agents.

Everything above is about recipients who already have the app. The ones who do not are the more valuable case, and the tracking domain problem barely touches them.

Follow the tap. The provider records the click and redirects, the browser lands on your link domain, and that domain does what it does for every other channel: identify the platform, record the click with the request signals, store the intended destination, and send the person to the App Store or Play Store. After the install, the SDK asks on first launch whether this install belongs to a recent click, and on a match the app routes to the content the email promised.

The redirect that ruins Universal Links is irrelevant here, because the browser really does arrive at your link domain and the request really does come from the recipient's device. Deferred deep linking works from a tracked email link even when the direct app open does not.

Two details decide how well it works. Matching is not one mechanism. On Android the Play Install Referrer carries the click through the install deterministically. On iOS a first install has no equivalent, so the match is probabilistic: the server scores click-time signals against install-time signals, higher within the first hour than at twenty, with no match at all past twenty-four. Gate anything sensitive, such as automatic sign-in, on the deterministic flag rather than a confidence threshold. The deferred deep links reference has the published bands.

The match window is short on purpose. A typical default is six hours with a ceiling of twenty-four, and that is not timidity. The probabilistic key identifies a network rather than a device, so every extra hour lets more strangers behind the same address join the same bucket while adding very few genuine matches.

For an email campaign that argues for two things: send at a time your audience acts on rather than one that maximises opens, because the window starts at the tap, and make the landing experience the store handoff rather than a marketing detour, because every step between tap and install is confidence decay.

Measuring Opens, Taps, and Installs

Three systems count three different things in the same campaign, and adding them together produces a number that means nothing.

Opens come from a tracking pixel in the message. Since mail privacy features began preloading images, an open no longer means a human read anything, though it still says delivery worked and the address is live. Treat the absolute number as directional and the trend as useful.

Taps come from the link. If click tracking is on, the ESP counts them. If the link points at your own domain, that domain counts them under its own rules for bots and duplicates. Do not read the gap between the two as data loss: they use different bot filtering, deduplication windows, and treatment of prefetch. Pick the system you trust for each question and stay with it.

Installs come from the SDK on first launch, attributed back to a specific click. It is the only one of the three that says the campaign produced a user.

One habit matters more than any of this: one link per placement. A distinct link for the hero button, the body link, and the footer, plus one per campaign, turns the click stream into an answer. Set campaign parameters on the link itself rather than hand-editing query strings in the HTML, so the same fields reach the destination from every channel.

A Checklist Before You Send

  1. Send yourself the real campaign, not a preview. Previews often skip link rewriting, which is why tests look fine and production does not.

  2. Long-press the link in the delivered message and read the URL. If it is not your domain, click tracking is rewriting it, and no amount of AASA debugging will help.

  3. Confirm the association file on whatever domain the tapped URL uses:

    Anything other than a clean 200 with application/json and no redirect means iOS will not associate it.

  4. Check Android verification for every host you declared, including the tracking domain:

  5. Test on a physical device, in the mail clients your recipients use, with the app installed and again after deleting it.

  6. Test the not-installed path end to end: tap, store, install, first launch, landing on the content rather than the home screen.

  7. Check what your click-triggered automations depend on before disabling tracking on a link.

Frequently Asked Questions

Why does my deep link open the browser instead of the app when tapped from an email? Because your email provider rewrote the link. The URL the recipient taps points at the provider's click tracking domain, and that domain has no apple-app-site-association or assetlinks.json naming your app, so iOS and Android hand the tap to a browser. The redirect that follows lands on your real domain, but a server redirect is not a tap and does not trigger the association.

Can I keep email click tracking and still open the app? Yes, if your provider lets you run click tracking on a branded domain and serves your association files from it. SendGrid, Klaviyo, Iterable, Customer.io, and Amazon SES all document a path to this in 2026, with different mechanics. If yours does not, exclude deep link URLs from tracking or point the email at a link domain that does the redirect and the measurement itself.

Do Universal Links or App Links fire after an HTTP redirect? Treat the answer as no. Both platforms decide from the URL the user actually tapped, not from where that URL ends up. Redirect chains have opened apps inconsistently in the past, which is why teams believe it works, and developers have reported redirect-based handoff failing on iOS 18 where it worked on iOS 17. Do not design around it.

Why do email deep links work in Apple Mail but not in Gmail or Outlook? Apple Mail hands the tapped URL to the system, so a correctly associated domain opens your app. Gmail opens links in its own in-app browser by default on both platforms, and Microsoft 365 tenants running Safe Links rewrite every URL to a Microsoft scanning domain before the recipient ever sees it. The Safe Links case is controlled by the recipient's IT policy, not by you.

What happens when the recipient does not have the app installed? That is the deferred deep link case, and it is unaffected by the Universal Link problem. The tap ends at your link domain, which records the click and sends the user to the store, and the SDK claims the stored destination on first launch. The recipient lands on the content the email promised instead of your home screen.

How do I tell an email open apart from a real tap and an install? Keep the three numbers in the systems that own them and never add them together. Opens come from a tracking pixel and are inflated by mail privacy features that preload images, taps come from your link domain after bot and prefetch filtering, and attributed installs come from the SDK on first launch. Opens measure delivery, taps measure interest, installs measure outcome.

This whole article is about who owns the domain in the tapped URL, so the fix is about making that domain yours and making it capable.

A WarpLink custom domain is two DNS records: one that routes traffic, one that lets the HTTPS certificate be issued and renewed for you, with no certificate to upload or remember. Once the domain is verified, the apple-app-site-association and assetlinks.json files are generated and served on it automatically, and regenerated whenever your app configuration changes. Declare the domain in the Associated Domains entitlement, the App Links intent filter, and the SDK, and links on it open your app from the first launch. That is fix 3 with the hosting problem removed, and the setup is in the custom domains documentation.

Three pillars ride the same link. Deep linking routes the tap into the right screen. Install attribution matches the install back to the click for recipients who did not have the app, through the deferred payload stored at click time. Real-time analytics show taps by platform, referrer, and device, deduplicated in the database rather than guessed at the edge, so the email number and the in-app number describe the same event.

Create a free WarpLink account and put a domain in your next campaign that your app already trusts.

WarpLink Team

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

Related Posts