Deeplinkly

Glossary/Implementation artifacts

SHA-256 Certificate Fingerprint

Definition

A SHA-256 certificate fingerprint is the SHA-256 hash of an app signing certificate, written as 32 colon-separated hexadecimal bytes, used to prove that a specific build was signed by a specific key.

Android uses it to decide whether the app asking to handle a domain's links is the app the domain authorised. It is the value in sha256_cert_fingerprints in assetlinks.json, and getting it from the wrong key is the single most common cause of App Links that verify perfectly on a developer's machine and fail for every user who installed from Google Play.

What it looks like and how to get it

Thirty-two bytes, uppercase hex, colon-separated — 95 characters in total. Anything shorter is a SHA-1 fingerprint (20 bytes), which Digital Asset Links does not accept.

Four ways to produce the fingerprint
# 1. From a keystore you hold
keytool -list -v -keystore release.jks -alias upload | grep SHA256

# 2. From every variant Gradle knows about, in one shot
./gradlew signingReport

# 3. From a built artifact — the certificate that actually signed it
apksigner verify --print-certs app-release.apk | grep SHA-256

# 4. From the debug keystore Android Studio generates
keytool -list -v -keystore ~/.android/debug.keystore \
  -alias androiddebugkey -storepass android -keypass android | grep SHA256

apksigner prints it without colons

apksigner outputs a continuous lowercase hex string while keytool outputs uppercase colon-separated bytes. Digital Asset Links wants the colon-separated form. Both represent the same 32 bytes, so reformat rather than assuming you read the wrong key.

Method 3 is the one to trust when something is broken, because it reports what signed the artifact rather than what a configuration file claims should have signed it.

Play App Signing changes the answer

This is the part that catches nearly everyone. With Play App Signing — the default for every app that ships an AAB — you sign the upload with your upload key, Google re-signs the distributed APKs with the app signing key, and the fingerprint users' devices see is Google's, not yours.

Which fingerprint each build carries, and where to find it.
BuildSigned withFingerprint source
Local debug buildDebug keystore~/.android/debug.keystore, alias androiddebugkey
Local release APKYour release keystorekeytool -list -v -keystore release.jks
Internal testing / Play trackGoogle's app signing keyPlay Console → Test and release → Setup → App integrity
Production from PlayGoogle's app signing keySame page as above
App Bundle you uploadedYour upload keyOnly proves who uploaded it; devices never see it

The symptom is unmistakable once you know it

App Links verify on a locally built release APK and fail for everyone who installed from Play. That is the upload key in assetlinks.json where the app signing key belonged. Copy the App signing key certificate SHA-256 from Play Console → Test and release → Setup → App integrity, not the upload certificate below it.

The fix is to list every fingerprint that can legitimately sign a build users run. Extra entries cost nothing — verification succeeds if any listed fingerprint matches.

/.well-known/assetlinks.json
[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.shop",
      "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",
        "7B:14:12:6C:1A:99:2E:5B:57:B1:0F:D8:D1:C2:24:9A:8D:4C:03:5F:9E:B7:22:A1:44:8E:D0:6C:19:33:F0:2B"
      ]
    }
  },
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.shop.debug",
      "sha256_cert_fingerprints": [
        "A1:9F:3C:22:B8:07:41:6E:5D:90:AC:11:74:33:2F:88:5B:C0:DE:47:19:6A:B3:52:E8:0D:71:CC:34:96:1F:AA"
      ]
    }
  }
]

The first statement lists two fingerprints — Google's app signing key and your own release key — so both a Play install and a directly distributed APK verify. The second covers the .debug package produced by applicationIdSuffix.

Where else the fingerprint is required

Other systems that key on the signing certificate, and which one they want.
SystemFingerprintNotes
Android App LinksSHA-256 of the app signing keyIn assetlinks.json; SHA-1 not accepted
Google Sign-In / Firebase AuthSHA-1 and SHA-256Register every variant's key or sign-in fails per build type
Google Maps SDKSHA-1Restricts the API key to a package plus certificate
Smart Lock / Credential ManagerSHA-256Uses the common.get_login_creds relation in the same file
Google Play IntegritySHA-256Verifies the signing certificate server-side

Key rotation adds a fingerprint, it does not replace one

If you rotate the app signing key through Play, devices with older installs continue to present the previous certificate. Keep both fingerprints in assetlinks.json — removing the old one breaks App Links for every user who has not updated.

Verifying the pair end to end

Two commands: what the device holds, and what the domain publishes. They have to agree.

Compare device and domain
# What the installed app is signed with (path from pm list packages -f)
adb shell pm list packages -f com.example.shop
adb pull /data/app/.../base.apk /tmp/base.apk
apksigner verify --print-certs /tmp/base.apk | grep SHA-256

# What the domain authorises, as Google's verifier reads it
curl -sS "https://digitalassetlinks.googleapis.com/v1/statements:list\
?source.web.site=https://example.com\
&relation=delegate_permission/common.handle_all_urls"

If the hashes match and links still open the browser, verification is not the problem — check the intent filter and the verification state instead.

AASA & assetlinks.json generator

Paste your package name and one or more SHA-256 fingerprints and it produces a correctly shaped assetlinks.json, including extra statements for debug package suffixes. Everything runs in your browser, so your fingerprints are not uploaded anywhere.

Open the aasa & assetlinks.json generator

Frequently asked questions

How do I get the SHA-256 fingerprint for assetlinks.json?
If the app ships through Google Play, take it from Play Console under Test and release, then Setup, then App integrity: the App signing key certificate's SHA-256 value. For a locally signed build, run keytool -list -v against the keystore, or apksigner verify --print-certs against the built APK, which reports the certificate that actually signed that artifact.
Why do my App Links work locally but fail from the Play Store?
Because Play App Signing re-signs your upload with Google's app signing key, so builds downloaded from Play carry a different certificate than the release APK you built locally. If assetlinks.json contains only your upload or release fingerprint, verification fails for every Play install. List both fingerprints in sha256_cert_fingerprints.
Can assetlinks.json contain more than one fingerprint?
Yes, and it usually should. sha256_cert_fingerprints is an array and verification succeeds if any entry matches the installed app's certificate. Listing the Play app signing key, your own release key, and a debug key alongside a statement for the debug package name covers every build a developer or user might install.
Does Digital Asset Links accept a SHA-1 fingerprint?
No. Digital Asset Links requires SHA-256, which is 32 bytes written as 95 characters with colon separators. A SHA-1 fingerprint is 20 bytes and will simply not match, producing a verification failure that looks identical to having no statement at all. Other Google services such as Maps and Google Sign-In do still use SHA-1, which is why both values circulate.
What happens to App Links if I rotate my signing key?
Devices that installed before the rotation continue to present the old certificate until the user updates, so both fingerprints must be listed in assetlinks.json during the transition. Removing the previous fingerprint immediately breaks verification for everyone still on an older install, and the failure is silent — their links quietly start opening the browser.

Related terms

  • assetlinks.jsonassetlinks.json is a Digital Asset Links statement file hosted at a domain's /.well-known/ path that authorises a named Android app, identified by package name and signing certificate fingerprint, to handle that domain's URLs.
  • Android App Link VerificationAndroid App Link verification is the process by which Android confirms, at install time, that a domain named in an app's intent filter publishes an assetlinks.json file authorising that app to handle its URLs.
  • Bundle IdentifierA bundle identifier is the reverse-DNS string, such as com.example.shop, that uniquely identifies an iOS app to the operating system and the App Store.
  • Validating assetlinks.jsonValidating assetlinks.json means confirming four separate things: that Android can fetch the file, that it parses as a valid statement list, that it names the fingerprint of the shipped build, and that verification passed on a device.