Free Tool

Free Mobile Deep Link Tester

Test iOS Universal Links and Android App Links in one shot. Validates apple-app-site-association and assetlinks.json - JSON syntax, content type, app-ID matches, common gotchas. Free, no signup.

Fetches /.well-known/apple-app-site-association (iOS) and /.well-known/assetlinks.json (Android). Cached 5 min.

No signup required
Free forever
GDPR compliant
Powered by U2L

Quick Answer

A deep link tester fetches the apple-app-site-association (AASA) and assetlinks.json files from a domain's /.well-known/ path, parses them, and validates against Apple's and Google's published format requirements. The U2L Deep Link Tester surfaces both platforms in one view with severity-graded issues (error / warning / info) - JSON parse failures, content-type mismatches, missing required fields, malformed app IDs.

Quick Facts

  • Fetches https://{domain}/.well-known/apple-app-site-association (iOS Universal Links) and https://{domain}/.well-known/assetlinks.json (Android App Links).
  • iOS Universal Links: Apple parses AASA on app install. Required for tapping a https://example.com link to open your app instead of Safari.
  • Android App Links: Google verifies assetlinks.json on app install. Required for tapping a https://example.com link to open your app instead of Chrome.
  • Validates: JSON syntax, Content-Type header (must be application/json), AASA appID format (TEAMID.bundle.id), assetlinks package_name format (com.example.app), and required fields.
  • Cached at the U2L edge for 5 minutes. Repeat checks on the same domain return instantly.
  • Useful for: pre-launch QA on Universal Link / App Link config, diagnosing 'my app doesn't open from links' bugs, post-deploy verification.
  • For deeper iOS-only validation (path matching, components syntax, deeper rules), see /tools/universal-link-validator.

How to test deep links

One step. Domain in, validation out.

  1. 1

    Enter the domain

    Type the domain hosting your AASA / assetlinks.json files (the apex domain, not the app's bundle URL). The tester fetches both files in parallel.

  2. 2

    Read iOS + Android validation

    Two panels: iOS (AASA) and Android (assetlinks). Each shows whether the file was found, JSON parsed correctly, and any errors / warnings. Severity-graded.

  3. 3

    Inspect raw JSON if needed

    Each panel exposes the raw JSON for deep inspection. Useful when the validator's structured analysis isn't enough.

What is a Deep Link Tester?

Deep Link Tester is a tool that fetches and validates the deep-link configuration files for a domain. Mobile apps can claim ownership of specific URLs (https://example.com/orders/123) so taps on those links open the app instead of the browser. iOS calls this 'Universal Links'; Android calls it 'App Links'. Both require a JSON config file hosted at a specific path on your domain.

iOS Universal Links require an apple-app-site-association file at https://example.com/.well-known/apple-app-site-association (or, legacy, at the root). The file declares which app IDs handle which URL paths. Apple downloads and parses this file when your app is installed; tapping a matching URL on the device opens the app.

Android App Links require an assetlinks.json file at https://example.com/.well-known/assetlinks.json. The file declares which Android package + signing-cert fingerprint handles URLs on this domain. Google verifies this file via the Digital Asset Links protocol when your app is installed.

Both files are notoriously easy to misconfigure. JSON syntax errors silently break the whole flow (Apple / Google fall back to opening the browser). Missing Content-Type: application/json triggers warnings (Apple is strict). Malformed appID prefixes (missing the 10-char team ID) fail validation. The U2L Deep Link Tester catches all of these classes of issue in one view.

How does a Deep Link Tester work?

When you submit a domain, the U2L API runs three parallel fetches: AASA at /.well-known/, AASA at root (legacy iOS 9-12 path), and assetlinks.json at /.well-known/. Each fetch has a 6-second timeout. The first AASA found is used; if both .well-known/ and root return content, .well-known/ wins.

For each file, the tester parses the JSON and validates structure. AASA validation: must have applinks.details array; each detail must have appIDs (modern, iOS 13+) or appID (legacy); appIDs must match TEAMID.bundle.id format; paths or components must be defined.

Assetlinks validation: must be a JSON array of statements; each statement must have a relation array including 'delegate_permission/common.handle_all_urls'; target must have namespace 'android_app', a package_name (reverse-DNS format), and a sha256_cert_fingerprints array with at least one fingerprint.

Issues are graded by severity: error (the deep link will definitely fail), warning (works but suboptimal), info (advisory). Both panels render side by side; you can also expand the raw JSON for any field-level deep dive.

Use Cases

How marketers, businesses, and developers use deep link tester.

Pre-launch app deep-link QA

Before submitting your iOS / Android app to the stores, run the tester against your production domain. Catch AASA / assetlinks misconfigs before they hit users.

'My app doesn't open from links' debugging

User reports tapping a deep link opens the browser instead of the app. Tester confirms whether AASA / assetlinks is accessible and parseable - usually the fix is here.

Post-deploy CDN config verification

After moving CDN providers, AASA / assetlinks may serve different headers or cache differently. Tester verifies they still serve correctly post-cutover.

Multi-app or multi-team handoff

Domain with multiple iOS apps (work + personal apps from different teams) needs all team prefixes in AASA. Tester surfaces all declared appIDs in one view.

Marketing-domain deep-link integration

Marketing sites adding deep-link support so emails / ads open the app. Tester verifies the integration before mass-distribution.

Cross-platform app launch readiness

Launching iOS + Android simultaneously. Tester confirms both files are live and valid - one missing breaks the launch on that platform.

Vendor / SaaS due diligence

Evaluating a SaaS vendor's mobile-app integration. Quick deep-link check on their domain reveals app-integration hygiene.

Compliance / security audit

SOC 2 / ISO audits often check mobile-app security configs. AASA / assetlinks validity is publicly verifiable evidence (no app-internal access needed).

Periodic deep-link health monitoring

Quarterly checks on production domains. CDN cache changes, JSON format drift, content-type regressions all happen silently; periodic tests catch them.

Cross-domain Universal Link strategy

App handling URLs on multiple domains (example.com + example.io + cdn.example.com). Test each domain's AASA / assetlinks separately.

Deep Link Tester vs Alternatives

Side-by-side feature and pricing comparison with the top alternatives.

FeatureU2LApple's AASA validatorBranch.io testermanual curl
Free, no signupAccount
iOS AASA + Android assetlinksiOS onlyManual
Severity-graded issuesLimited
Browser-only (no install)
Edge-cached responses5 min
Raw JSON expansionNative
AASA at .well-known + root (legacy)Manual

Deep Link Tester vs Apple's official AASA validator

Apple's developer portal includes an AASA validator at branch.io's hosted version (and Apple's CLI tool aasa-validator). Free, official, deep iOS-specific validation.

U2L's tester adds Android assetlinks alongside iOS AASA in a single view. For deep iOS-only debugging, Apple's tools win on depth. For 'is my deep-link config alive on both platforms?', U2L is faster and shows both.

Deep Link Tester vs Branch.io's deep-link diagnostic

Branch.io is the enterprise-grade deep-linking platform. Their diagnostic tool tests AASA + assetlinks, plus deferred-deep-linking validation, attribution debugging, and full deep-link analytics. Free tier; paid tiers $99-$2000+/mo for advanced features.

U2L's tester is a focused, free subset: just AASA + assetlinks validation. For full deep-linking platforms with deferred-deep-linking, Branch wins. For 'check my AASA / assetlinks are valid', U2L is enough.

Best Practices

Host AASA at /.well-known/, not the legacy root path

Apple supports /.well-known/apple-app-site-association (modern) and /apple-app-site-association (legacy iOS 9-12). New deployments should use /.well-known/ exclusively. Easier to manage; better aligned with web conventions.

Set Content-Type: application/json

Apple requires the AASA Content-Type header to be application/json. Without it, parsing may fail silently. CDNs (Cloudflare, Fastly) sometimes send text/plain by default; configure explicitly.

Use modern AASA format (appIDs array, components)

iOS 13+ supports appIDs array (multiple apps per detail) and components (richer path matching with case-sensitivity, percent-encoding). Modern format = better forward compat. Legacy format (appID + paths) still works but lacks new features.

Validate appID format: TEAMID.bundle.id

The 10-char team-ID prefix is required. ABCDE12345.com.example.app is correct; com.example.app alone is wrong. Apple silently rejects malformed appIDs.

Pin assetlinks SHA-256 fingerprints to your release cert

Android assetlinks lists allowed signing-cert fingerprints. Use your production signing key's fingerprint (not debug keystore). Mismatch = App Links won't activate.

Test on real devices, not just the validator

AASA / assetlinks passing validation is necessary but not sufficient. Test the actual deep-link tap on a real iPhone and a real Android phone before declaring done.

Keep AASA / assetlinks under 100 KB

Apple has a 128 KB hard limit; Google has a similar practical cap. Keep your file size reasonable - don't bloat with unnecessary path entries.

Re-test after CDN / hosting changes

Migrating CDNs (Cloudflare to Fastly, Vercel to Netlify) can change cache headers or content-type. Re-test AASA / assetlinks after every infra change.

Common Mistakes to Avoid

Wrong Content-Type header

Serving AASA as text/plain or text/html instead of application/json. Apple rejects silently. Configure your server / CDN to set application/json explicitly.

JSON syntax errors

Trailing commas, single quotes, missing brackets. Apple / Google reject the entire file on any parse error. Always validate JSON syntax before deploying.

Missing TEAMID prefix in appID

Writing 'com.example.app' instead of 'ABCDE12345.com.example.app'. The 10-char team-ID prefix is required. Apple silently rejects.

Debug keystore SHA-256 in assetlinks.json

Using the debug keystore's fingerprint instead of the production release cert's. App Links won't activate on Play Store builds.

AASA served from a redirect

Apple does not follow redirects when fetching AASA. The file must be served directly with a 200 OK status. 301 / 302 redirects break the fetch.

Forgetting to deploy on subdomains

If your app handles m.example.com URLs, AASA must be hosted at m.example.com - the apex domain's AASA doesn't apply. Each subdomain needs its own file.

Not testing after CDN cache changes

CDNs can serve stale AASA / assetlinks for hours after a deploy. Force-purge the cache; re-test to confirm the new file is live.

Technical Specifications

iOS AASA paths checked/.well-known/apple-app-site-association (modern) and /apple-app-site-association (legacy)
Android assetlinks path/.well-known/assetlinks.json
Required Content-Typeapplication/json
AASA appID formatTEAMID.bundle.id (10-char team prefix + reverse-DNS bundle)
Assetlinks package_name formatReverse-DNS (com.example.app)
Required assetlinks relationdelegate_permission/common.handle_all_urls
Required assetlinks fieldstarget.namespace=android_app, package_name, sha256_cert_fingerprints
Cache TTL5 minutes at the Cloudflare edge
Per-file fetch timeout6 seconds
Companion tool/tools/universal-link-validator for iOS-deeper analysis

Industry-Specific Use Cases

Mobile app developers

Pre-launch deep-link QA, post-deploy verification, debugging 'my app doesn't open' bug reports.

Mobile-first product teams

Marketing campaigns linking to in-app screens. Tester confirms the deep-link layer is solid before campaign launch.

DevOps and SRE

Post-deploy AASA / assetlinks verification. CDN config validation. Ensures infra changes don't break deep-linking silently.

Mobile QA and test engineering

Pre-release deep-link smoke tests. Combined with on-device testing for full coverage.

Mobile growth and engagement

Email / push / share-link funnels rely on Universal Links / App Links to land users in the right in-app screen.

Multi-app / multi-team domains

Companies with multiple apps sharing a domain (work suite + personal apps) need all teams' prefixes in AASA. Tester surfaces all in one view.

Frequently Asked Questions

What's the difference between Universal Links and App Links?

Universal Links are Apple's iOS mechanism for tapping a https:// URL to open your app. App Links are Google's Android equivalent. Both serve the same purpose; both require a JSON config file at /.well-known/ on your domain.

Where should I host AASA / assetlinks.json?

Apple AASA: https://{domain}/.well-known/apple-app-site-association (modern) or https://{domain}/apple-app-site-association (legacy iOS 9-12, still supported). Android assetlinks: https://{domain}/.well-known/assetlinks.json. Both must be on the apex / subdomain that handles deep links.

Does AASA need to be JWT-signed?

No, not since iOS 14 (2020). Apple removed the JWT-signing requirement; AASA is now plain JSON. Older guides may still mention JWT signing; ignore that for new deployments.

Why must Content-Type be application/json?

Apple's AASA parser rejects files with non-JSON content types (text/plain, text/html). Configure your server / CDN to set application/json explicitly. Otherwise the file fetches but doesn't parse.

What's the appID format for AASA?

TEAMID.bundle.id - 10-char Apple team identifier + dot + reverse-DNS bundle ID. Example: ABCDE12345.com.example.app. The team ID is found in your Apple Developer account; the bundle ID is in your Xcode project.

What's the package_name format for assetlinks?

Reverse-DNS package name as declared in your Android app's build.gradle: com.example.app. This is the same value as your app's applicationId in Gradle.

How do I get the SHA-256 fingerprint for assetlinks?

Use keytool: keytool -list -v -keystore your-release-key.keystore. The 'SHA-256:' line is the fingerprint. Use the production release keystore, not the debug keystore.

What if my AASA / assetlinks file is found but invalid?

Apple / Google fall back to opening the URL in the browser, not your app. Users tap the link, get the website, never see the app. Validates the importance of catching JSON / format issues before deploying.

Does the tester run actual deep-link taps?

No - it only validates the config files. To verify actual deep-link behavior, install your app on a real device and tap a matching URL. The tester is necessary but not sufficient for full deep-link verification.

Why doesn't my AASA work even when validation passes?

Several other failure modes: app's Associated Domains entitlement missing, app not signed with the right team ID, AASA cached on the device from before deploy (uninstall and reinstall to refresh). Most issues are config in the app, not the AASA file.

Does the tester support multi-domain configs?

Tests one domain at a time. For apps handling URLs on multiple domains, run the tester separately for each. The U2L API can be hit programmatically (1 req/sec recommended).

What's the difference vs /tools/universal-link-validator?

Deep Link Tester: cross-platform iOS + Android in one view. Universal Link Validator: iOS-only deeper analysis (path matching, components syntax, deeper rules). They share the same backend; different rendering.

Can the tester check my staging / dev environment?

Only public domains. Internal staging URLs (staging.internal, *.local) are blocked by SSRF protection. Use Apple's local CLI validator (aasa-validator) or curl from inside your network for private domains.

Is there an API I can call programmatically?

Yes. GET https://u2l.ai/api/tools/deep-link-validator?domain=example.com returns JSON. Cached for 5 minutes. No auth required. Be polite - 1 request per second per domain.

Will the tester see CDN-injected headers correctly?

Yes. The fetch goes through to the CDN-served file just like Apple / Google would fetch it. Content-Type, cache headers, and HTTP status all reflect the CDN config.

What if my AASA serves different content per-region?

Apple may fetch from a US-based CDN POP; the tester fetches from Cloudflare. If your AASA varies by geography, you may see different validation than what Apple sees. Check from multiple regions if region-specific configs are critical.

How often does Apple / Google re-fetch AASA / assetlinks?

Apple fetches AASA at app install and re-fetches periodically (hours to days). Google fetches assetlinks at app install and on-demand. Changes to your files take effect with a delay; budget for this in deploy planning.

Should I use the modern AASA components or legacy paths?

Modern components (iOS 13+) are richer: case-sensitivity flags, percent-encoding controls, exclude rules. Legacy paths still work for backward compat. New deployments should use components; legacy can be added alongside for older iOS versions.

Key Terms

Universal Links
iOS mechanism for tapping a https:// URL to open the app instead of Safari. Requires apple-app-site-association (AASA) JSON file hosted on the domain.
App Links
Android mechanism for tapping a https:// URL to open the app instead of Chrome. Requires assetlinks.json file hosted at /.well-known/ on the domain.
AASA
apple-app-site-association. The JSON file declaring which iOS app IDs handle which URL paths. Located at /.well-known/apple-app-site-association.
assetlinks.json
The JSON file declaring which Android packages + signing-cert fingerprints handle URLs on a domain. Located at /.well-known/assetlinks.json.
Team ID
Apple's 10-character identifier for your developer team. Found in your Apple Developer account. Required as the prefix in AASA appIDs (TEAMID.bundle.id).
Bundle ID
iOS app's unique identifier in reverse-DNS format (com.example.app). Set in Xcode. Combined with Team ID forms the full appID for AASA.
package_name
Android app's unique identifier in reverse-DNS format (com.example.app). Set in build.gradle's applicationId. Matches the Bundle ID convention.
SHA-256 fingerprint
The cryptographic hash of your Android app's signing certificate. Listed in assetlinks.json's sha256_cert_fingerprints array. Use the production release keystore, not debug.

Want continuous deep-link monitoring?

Sign up free for U2L Pro to schedule daily deep-link health checks across multiple domains, receive alerts when AASA / assetlinks regresses, and audit all your apps' configs from one dashboard.

Sign up free