assetlinks.json has the wrong structure

assetlinks.json must be an array of statements with relation and target. Fix a top-level object, empty array or wrong namespace that stops App Links verifying.

SymptomThe assetlinks.json file parses as JSON but App Link verification still fails.
Likely causeThe file is not an array of statements, or a statement is missing target fields such as namespace android_app.
FixRebuild the file as an array of statements, each with relation and a target holding namespace, package_name and sha256_cert_fingerprints.

Short answer: assetlinks.json is a list, so it starts with [. Each statement needs a relation array and a target object with namespace: "android_app", package_name and sha256_cert_fingerprints. A top-level object, an empty array or a web namespace will not verify App Links. Check the live file with Google's Statement List tester.

What is happening

assetlinks.json statement: one object in the file's top-level array that grants a relation (such as delegate_permission/common.handle_all_urls) to a target app, identified by package name and signing certificate fingerprint.

Google's App Links documentation shows the file as an array with one or more statements. If the array is missing, empty, or the target is incomplete, Android finds no statement linking your app to the site.

  • Top-level object: { "relation": ... } without the surrounding [ ].
  • Empty array: [], which declares nothing.
  • Wrong namespace: "namespace": "web" describes a website target, used for other purposes, not an Android app.
  • Misspelt keys: packageName or sha256_fingerprints are ignored.

Why does this happen?

The structure is easy to get wrong when copying one statement from documentation and editing it by hand, or when merging files for several apps.

  • Google says "a website can declare associations with multiple apps within the same assetlinks.json file", which means several objects in one array, not several arrays.
  • Two fingerprints in one statement are equivalent to two statements, so either form works.

How to confirm it

  1. Fetch the file: curl -i https://example.com/.well-known/assetlinks.json.
  2. Check the body starts with [ and each object has relation and target.
  3. Compare it with Google's example: a top-level array, at least one statement, namespace set to android_app and all three target fields. Then test it with Google's Statement List tester.
  4. Call https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls to see which statements Google can read.

How to fix it

  1. Wrap the statements in a top-level array.
  2. Give each statement a relation array containing delegate_permission/common.handle_all_urls.
  3. Set target.namespace to android_app.
  4. Add package_name (the application ID from build.gradle) and sha256_cert_fingerprints (an array).
  5. For several apps, add one statement per app in the same array.
  6. Deploy, then re-verify with adb shell pm verify-app-links --re-verify com.example.app.
[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example",
      "sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
    }
  },
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.lite",
      "sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
    }
  }
]

The Android App Links setup guide shows this structure. If the structure is right, check the relation and package name next.

FAQ

Common questions

Must assetlinks.json start with a square bracket?

Yes. The file is a statement list, which Google's examples always show as a JSON array, even when it holds only one statement.

Can I list several apps in one file?

Yes. Google says a website can declare associations with multiple apps in the same file. Add one statement object per app inside the array.

What is the web namespace for?

A `web` target describes a website rather than an Android app. App Links need a target with the `android_app` namespace.

Can I put two fingerprints in one statement?

Yes. Google says the field supports multiple fingerprints, for example for debug and production builds, and the protocol treats this as equivalent to two statements.

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.