Deeplinkly
Free · No login · Runs in your browser

Universal Link Tester

Paste your apple-app-site-association and a list of URLs. See exactly which ones open your app, which fall through to Safari, and which rule decided — without building the app.

Paste the file you host at /.well-known/apple-app-site-association. Nothing leaves your browser.

Full URLs or bare paths. Query strings and fragments are matched too.

3 open the app
3 stay in the browser

https://example.com/products/42

OPENS THE APP
rule #2/products/*
  • path /products/* vs /products/42

https://example.com/admin/users

STAYS IN BROWSER
rule #1/admin/*exclude

Keep the admin console on the web

  • path /admin/* vs /admin/users

https://example.com/search?q=running+shoes

OPENS THE APP
rule #3/search ?q=*
  • path /search vs /search
  • query q=* vs q=running shoes

https://example.com/search

STAYS IN BROWSER

No rule matched, so iOS leaves this URL in the browser. Add a component that covers this path if it should open the app.

https://example.com/help#faq

OPENS THE APP
rule #4/help #faq
  • path /help vs /help
  • fragment faq vs faq

https://example.com/about

STAYS IN BROWSER

No rule matched, so iOS leaves this URL in the browser. Add a component that covers this path if it should open the app.

This tests the rules in your AASA file. It does not check whether the file is actually reachable — a perfect ruleset still fails if the file 404s, redirects, or serves the wrong content type. Run the Deep Link Debugger against your live domain for that half, and use the AASA generator to build a clean file from scratch.

How iOS decides

  1. 1

    iOS downloads your apple-app-site-association file when the app installs or updates, and caches it through Apple's CDN.

  2. 2

    When a link is tapped, it walks the components array for your app in order.

  3. 3

    The first component whose path, query and fragment patterns all match wins. Later matches are never evaluated.

  4. 4

    If that winning component has exclude: true, the URL opens in Safari. Otherwise it opens your app.

  5. 5

    If no component matches at all, the URL opens in Safari.

Step 3 is where most broken AASA files go wrong. A catch-all rule near the top of the array silently shadows every specific rule below it, including your excludes. This tool shows you when that is happening.

Frequently asked questions

How do I test Universal Links without building the app?
Paste your apple-app-site-association file and the URLs you care about into this tool. It applies Apple's matching rules — path, query and fragment patterns, wildcards, and exclude flags — and tells you which URLs open the app and which fall through to Safari. Normally the only way to check this is to build, sign and install the app on a physical device, which is why broken component arrays usually ship to production before anyone notices.
Does * match across slashes in an AASA path?
Yes. In an AASA pattern, * matches zero or more of any character, including /. So /products/* matches /products/42 and also /products/shoes/running/42. This surprises people who expect shell or .gitignore behaviour where a single * stops at a path separator. The ? wildcard matches exactly one character.
Why isn't my exclude rule working?
Almost always because an earlier component already matched. iOS walks the components array in order and stops at the first match, so a catch-all like { "/": "/*" } placed above your exclude rule swallows every URL before the exclude is ever evaluated. This tool flags that case explicitly: it shows the rule that decided the outcome and lists any later rules that also matched but never ran.
What's the difference between components and paths?
The legacy paths format is a flat array of path strings, using a "NOT " prefix to exclude. It can only match on the path. The modern iOS 13+ components format is an array of dictionaries, where each entry can match on path (/), query (?) and fragment (#) independently and carries an explicit exclude flag. This tool evaluates both and warns when it finds the legacy format.
Can an AASA component match on query parameters?
Yes, with the components format. The "?" key takes either a pattern matched against the whole query string, or a dictionary of parameter names to patterns — for example { "/": "/search", "?": { "q": "*" } } matches /search?q=shoes but not a bare /search. That distinction is a common source of links that work in testing and fail in the wild.
Is my AASA file uploaded anywhere?
No. The entire matching engine runs in your browser — your file, your Team IDs and your URLs never leave your device. There is no account and no request to our servers.
My rules are correct but Universal Links still don't work. What now?
This tool checks the rules, not the delivery. A perfect components array still fails if the file is served with a redirect, returns the wrong content type, 404s, sits behind auth, or is cached stale by Apple's CDN. Run your live domain through the Deep Link Debugger to check the delivery half, and confirm the app has the applinks: associated domains entitlement.
Are AASA patterns case-sensitive?
By default yes. Each component accepts a caseSensitive flag you can set to false to match case-insensitively. This tool honours that flag per component, defaulting to case-sensitive when it is absent — which matches Apple's behaviour and catches the class of bug where /Products fails against a /products/* rule.