PushUlinkDomain Ops

Universal Links Not Working? Your Deep-Link Subdomain May Be Silently Redirecting

Universal links not working? A blanket redirect on your deep-link subdomain can silently break iOS Universal Links and Android App Links. Here's how to audit and prevent it.

Quick Answer

Universal links not working? A blanket redirect on your deep-link subdomain can silently break iOS Universal Links and Android App Links. Here's how to audit and prevent it.

Key Sections

Start With These Sections

Answer First

Definition: Universal Links (iOS) and App Links (Android) are the standards that let a tap on an ordinary https:// URL open your installed app instead of the browser. The handoff is not magic: your app claims a domain, and the operating system verifies the claim by fetching a machine-readable file from that domain — apple-app-site-association on iOS, assetlinks.json on Android — at the /.well-known/ path over HTTPS. That branded subdomain is a trust anchor, not a marketing shortcut.

Why: The verification fetch must receive the file itself. Apple’s documentation requires the file to be accessible over HTTPS “without any redirects,” and per RFC 9110 a 3xx response (301, 302, 307, 308) points somewhere else — it is not the payload. If your deep-link subdomain is a blanket forwarding entry, the fetch receives a redirect and verification fails. The app does not crash, no error appears in your logs, and the link quietly opens the browser instead. That is why “universal links not working” shows up as a silent regression rather than a loud outage.

Example: Your app claims applinks:go.acme.com and has shipped for a year. After a rebrand, a colleague re-points go.acme.com with a blanket 301 to the new corporate site. The OS now fetches https://go.acme.com/.well-known/apple-app-site-association and receives a redirect instead of the JSON file. Verification fails, and every deep link that used to open the app now opens the browser. The mobile team finds out weeks later, from a dip in app opens or a support thread — not from any alert.

Key Facts

  • Two platforms, one pattern: iOS fetches /.well-known/apple-app-site-association (or the root-path apple-app-site-association); Android fetches /.well-known/assetlinks.json. Both must be served over HTTPS with a JSON content type (application/json; Apple also accepts application/pkcs7-mime for signed files).
  • Verification is performed by the platform, not your code: iOS checks at install, first launch, and periodically; Android checks at install when autoVerify is set. Your logs never see these fetches — the failure is invisible to the app team by construction.
  • Redirects are the failure mode to fear. Apple’s requirement is explicit: the file must be reachable “without any redirects.” RFC 9110 defines the 3xx class as “further action needs to be taken by the user agent” — a redirect is a pointer to a different resource, not the file.
  • Redirect chains multiply the risk: each hop is another rule that can catch the /.well-known/ path, and MDN notes every redirect costs an extra round trip while chains are best avoided.
  • A valid TLS certificate is required; verification is HTTPS-only.
  • Practical limits: You cannot force Apple or Google to re-verify on your schedule. A fix does not take effect instantly, and platform-side caching means the regression can persist after the underlying redirect is corrected. Android lets you trigger re-verification from a test device (see the FAQ); iOS has no public manual trigger.

Expert Explanation

How the handoff actually works

On iOS, your app lists applinks: entries in its com.apple.developer.associated-domains entitlement. On Android, your activity declares an intent filter with autoVerify="true". In both cases the OS fetches the association file from each claimed domain, checks that your app identifier appears in it, and only then treats links on that domain as app-launchable. If the file is missing, malformed, or never delivered, the platform simply does not associate the domain — the fallback is the designed one: the link opens in the browser. Graceful degradation is a feature of the standard, and exactly why the failure is quiet.

Why a blanket forward breaks it

The failure is a collision between two things that both look like “redirects” to a human:

  • The subdomain that forwards. A catch-all 301/302 rule at the host or CDN/WAF level, a DNS re-point (CNAME/ALIAS) to a host that serves another site which redirects, a “simplify everything into one domain” consolidation, or a well-meaning trailing-slash or case-normalizing rule that catches /.well-known/.
  • The fetch that must not redirect. The OS’s verification fetch follows none of that intent. Apple’s documentation is unambiguous: the file must be accessible via HTTPS “without any redirects” at https://<domain>/apple-app-site-association or https://<domain>/.well-known/apple-app-site-association.

When the two collide, verification gets a 3xx and the association never establishes. HTML <meta http-equiv="refresh"> and JavaScript redirects do not rescue you: they are not the file, and a JSON client will not execute them.

The same redirect chains that quietly strip cookies and break affiliate attribution in a browser are far more damaging here, because no visible page signals that anything changed — a topic we cover in our guide to what ops teams should check in the redirect chain.

The audit: where to look

Run these checks from a machine outside your office network, and treat any 3xx on the first response as a failure:

CheckCommand or sourceFailing sign
File reachable (iOS)curl -i https://<domain>/.well-known/apple-app-site-associationFirst status line is not 200 OK
File reachable (Android)curl -i https://<domain>/.well-known/assetlinks.jsonFirst status line is not 200 OK
No redirect before the filecurl -s -o /dev/null -w "%{http_code}" https://<domain>/.well-known/assetlinks.jsonAny 3xx code, not 200
Correct content typeResponse Content-Type header on both fetchesNot application/json
No blanket forwardingRequest a random path, e.g. curl -i https://<domain>/zzz-check3xx to a different host
DNS points where you thinkDNS provider records for the subdomainCNAME/ALIAS to an unexpected destination
Who changed the destinationDNS, CDN/WAF rule, and entry-layer change historyRecent re-point with no mobile-team review

Who changed the destination

The most useful post-mortem question is rarely “what is the rule today” — it is “who changed the destination, and what did the entry look like before?” A rebrand, an agency handoff, a domain consolidation, or a well-intentioned cleanup can all re-point a subdomain your app silently depends on. This is the same class of problem as a landing page being swapped after an ad is approved: the link still resolves, the destination is different, and nobody who depends on the old behavior is notified — we covered that failure mode in The Ad Is Approved, But the Landing Page Changed.

Decision Framework

Not every subdomain is a forwarding candidate. Use these rules when deciding what belongs in your entry layer:

  1. If a mobile app claims the host, it is a non-forwarding entry. Anything listed in your iOS associated domains or Android intent filters must resolve and serve the well-known files. It must never be covered by a blanket forward.
  2. A non-forwarding entry is still an entry. It belongs in the same registry as your forwarding entries — with an owner, a status (for example “infrastructure — do not forward”), and a change log — so a re-point is a deliberate, reviewed change. Because the failure is silent, the only real protection is traceability: who changed the destination, when, and what the entry was before. That is the same evidence trail auditors look for in entry management for compliance audits.
  3. Exclude deep-link subdomains from consolidation passes. When a team simplifies dozens of subdomains into a few forwarding rules — the scenario in our acquisition subdomain entry consolidation playbook — the check is simple: any host referenced by the mobile app is carved out of blanket rules and stays a direct-serving entry.
  4. Verify after any change, and make verification someone’s job. DNS, CDN, and WAF changes all count as candidate breakers. If your entry layer records status, access statistics, logs, and change history — the capabilities PushULink provides through its Console and OpenAPI — a deep-link subdomain’s status is visible and auditable like any other entry, which turns a silent regression into a findable one.

Key Takeaways

  • Deep-link subdomains are infrastructure, not shortcuts. Treat the hosts your app claims as non-forwarding entries, always.
  • Never put a blanket redirect in front of /.well-known/ on a claimed domain; the first response to the verification fetch must be 200 with the JSON file.
  • Audit after every DNS, CDN, WAF, or redirect-rule change — and ask who changed the destination and what the entry was before.
  • Keep these entries in the entry layer with an owner, a status, and a change log so re-points are reviewed, not silent.
  • When “universal links not working” lands on your desk, check the web side first: the app binary is usually innocent. The same silent fallback that makes entry mismatches look like “clicks but no conversions” hides this failure too — see our write-up on campaign entry mismatches for the pattern.

FAQ

Q: Why do universal links stop working when we never changed the app?

A: The app side is usually not where the failure lives. Verification is a web-side contract: the OS fetches the association file from the domain the app claims. If someone re-pointed DNS or added a blanket forward on that subdomain, the fetch returns a 3xx instead of the file and verification fails — while the app binary is unchanged. Audit the destination and redirect rules for every claimed domain before touching app code.

Q: Does a www-to-non-www or an http-to-https redirect break the files?

A: HTTPS enforcement (http to https) does not interfere, because verification fetches over HTTPS to begin with. But a www-to-non-www redirect (or the reverse) can break things if the domain you claimed in the app is the one whose /.well-known/ path redirects. Apple requires the file “without any redirects” on each domain you claim: if you claim both www and the apex domain, serve the file with a 200 on both, or claim only the canonical host.

Q: How do I test whether the well-known files are being redirected?

A: From a machine outside your office network, run curl -i https://yourdomain/.well-known/apple-app-site-association and the same for assetlinks.json. The first HTTP status line must be 200, not a 3xx, and Content-Type should be application/json. Then request a random path such as /.well-known/zzz-check to see whether the host blanket-redirects everything. Finally, check DNS and CDN/WAF rules, and ask who changed the destination and when.

Q: After we fix the redirect, how long until deep links work again?

A: Not instantly, and not on a schedule you control. Apple and Google cache verification results and re-check on their own timing. On Android you can trigger re-verification from a test device with adb shell pm verify-app-links (and by reinstalling the app); on iOS there is no public manual trigger, so plan for the fix to propagate over hours to days before treating the regression as cleared.

Sources

  • Apple — App Search Programming Guide: Support Universal Links. Source for the well-known/root paths, HTTPS, JSON content type, and the explicit “without any redirects” requirement.
  • Apple — Technical Note TN3155: Debugging universal links. Apple’s official troubleshooting flow for Universal Link failures.
  • Google — Verify Android App Links. Source for the assetlinks.json well-known path, HTTPS and application/json requirements, and install-time verification.
  • MDN — Redirections in HTTP. Source for 3xx semantics, redirect chains, and common redirect use cases.
  • IETF — RFC 9110: HTTP Semantics, Section 15.4 (Redirection 3xx). Definition of the 3xx class as requiring further user-agent action rather than delivering the requested payload.

Further Reading

FAQ

Common Questions

Who should read this article?

This article is for teams managing campaign links, customer domains, partner routes, social entries, redirect statistics, or cross-team launch workflows.

Do teams need to replace existing tools immediately?

No. A practical first step is to audit important entries, add owners, destinations, status, analytics, and retirement plans, then decide whether a unified entry layer is needed.

Is PushUlink only a short-link tool?

No. PushUlink focuses on managed subdomain forwarding, routing changes, permission boundaries, access statistics, and operation logs, so entries become manageable business objects.