assetlinks.json redirects or has the wrong type

Android rejects assetlinks.json behind a redirect, with a non-200 status or the wrong content type. How to check each host with curl and serve it correctly.

Symptompm get-app-links does not show verified even though the assetlinks.json content looks correct.
Likely causeThe file is served through a 301 or 302, returns a status other than 200, or is not sent as application/json.
FixServe the file directly over HTTPS with a 200 and Content-Type application/json on every host in the manifest.

Short answer: Google requires assetlinks.json over HTTPS, "without any redirects (no 301 or 302 redirects)", served as application/json. Any status other than 200 "is treated as an error, and will result in an empty statement list". Check every host with curl -i and fix the server, not the file.

What is happening

assetlinks.json delivery: how your server returns https://<host>/.well-known/assetlinks.json, which must be a direct 200 over HTTPS with Content-Type: application/json.

The content can be perfect and still fail if delivery is wrong. Google's rules are explicit:

  • The file must be at https://domain.name/.well-known/assetlinks.json. "Statement lists in any other location, or with any other name, are not valid for this site."
  • It must be served over HTTPS, "regardless of whether your app's intent filters declare HTTPS as the data scheme".
  • It must be served as application/json.
  • No 301 or 302 redirects.
  • Each host in the manifest needs its own file.

Why does this happen?

Site-wide rules that suit web pages break this one file. Redirects from the apex to www, from HTTP to HTTPS, or from a trailing slash path are the usual causes.

  • Apex and www: example.com redirects to www.example.com, but the manifest declares example.com.
  • Static host defaults: some hosts send .json files with a different type, or block dot-folders like /.well-known/.
  • Security rules: a WAF or login wall returns a 403 or a challenge page.
  • Wrong path: the file sits at /assetlinks.json or /.well-known/assetlinks without the extension.

How to confirm it

  1. Run curl -i https://example.com/.well-known/assetlinks.json. Check for HTTP/2 200, content-type: application/json and no Location header.
  2. Repeat for every host in your intent filters, including www and other subdomains.
  3. Query Google's view: https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls.
  4. On a device, run adb shell pm get-app-links com.example.app. Only verified means success.

How to fix it

  1. Exclude /.well-known/assetlinks.json from redirect rules on every host.
  2. Publish the file on each host the manifest declares. For a wildcard host like *.example.com, Google says to publish it at the root hostname, example.com.
  3. Set Content-Type: application/json for the file.
  4. Allow /.well-known/ through any firewall, bot or login rules.
  5. Re-verify on a test device:
  • adb shell pm set-app-links --package com.example.app 0 all
  • adb shell pm verify-app-links --re-verify com.example.app
  • wait a few minutes, then adb shell pm get-app-links com.example.app
location = /.well-known/assetlinks.json {
    default_type application/json;
    try_files /.well-known/assetlinks.json =404;
}

Check the file content with Google's Statement List tester at the same time. The iOS version of this problem is AASA redirect or blocked. Repeat curl -I https://example.com/.well-known/assetlinks.json for every host.

FAQ

Common questions

Does Android follow a redirect on assetlinks.json?

No. Google says the file must be accessible without any 301 or 302 redirects. Serve it with a 200 directly at every host.

What content type does assetlinks.json need?

Google requires `application/json`. Check the response header with `curl -i`, since some hosts and CDNs set a different type.

Do I need HTTPS if my app only handles http links?

Yes. Google says the file must be accessible over HTTPS regardless of whether the intent filters declare HTTPS as the data scheme.

How quickly does Android pick up a fixed file?

On Android 14 and lower, Google says updates are usually only picked up when the app is installed or updated. On Android 15 and later, changes can take up to seven days, and you can force a re-check on a test device with adb.

What are UTM parameters?

UTM parameters are tags added to the end of a link, such as utm_source and utm_campaign, that tell analytics tools where a visit came from. They let you see which campaign, channel and ad brought each visitor.

Which UTM parameters are required?

Use utm_source, utm_medium and utm_campaign on every campaign link. utm_term and utm_content are optional and help you compare keywords or ad variants.