Deeplinkly

Glossary/Android platform

Chrome intent

Definition

A Chrome intent is a URL using the `intent://` scheme, which encodes an Android Intent — its target package, action, extras and a fallback URL — inside a link so that a web page can launch a specific app and specify what should happen when that app is absent.

This is the mechanism that predates App Links and still outlives them in practice, because it does the one thing a verified https:// link cannot: it names the package it wants and carries an explicit instruction for the not-installed case. It is also the single most misapplied piece of Android deep linking, because it works flawlessly in the browser it is named after and does nothing at all in several places teams routinely ship it.

The syntax, and the anchor it has to live in

A complete intent URL, in the element Chrome requires
<!-- Chrome only launches an intent from a user gesture.
     A redirect on page load, a meta refresh, or a JS
     navigation without a click will be blocked silently. -->
<a href="intent://product/42
  #Intent
  ;scheme=myapp
  ;package=com.example.app
  ;S.utm_source=newsletter
  ;S.click_id=abc123
  ;S.browser_fallback_url=https%3A%2F%2Fexample.com%2Fproduct%2F42
  ;end">Open in the app</a>

<!-- Unwrapped, with no whitespace — this is the real value: -->
<!-- intent://product/42#Intent;scheme=myapp;package=com.example.app;S.browser_fallback_url=https%3A%2F%2Fexample.com%2Fproduct%2F42;end -->

Everything before #Intent is the data URI the app receives, with scheme= supplying the scheme that the intent:// placeholder stands in for — so the app above is handed myapp://product/42. Everything after it is the Intent itself, as semicolon-separated key-value pairs terminated by ;end. Android parses this with Intent.parseUri(), which is why the grammar is a framework detail rather than a Chrome invention.

The fragment keys worth knowing, and their types.
KeyMeaningExample
schemeScheme substituted into the data URIscheme=myapp
packageRestrict resolution to one packagepackage=com.example.app
actionIntent action; defaults to VIEWaction=android.intent.action.VIEW
categoryAdded category, repeatablecategory=android.intent.category.DEFAULT
launchFlagsIntent flags, hexlaunchFlags=0x10000000
S.<name>String extraS.click_id=abc123
i.<name>Int extrai.product_id=42
B.<name>Boolean extraB.is_promo=true
l. f. d. s. c. b.Long, float, double, short, char, bytel.ts=1757548800
S.browser_fallback_urlChrome-specific. Where to go if nothing handles the intentURL-encoded https://…

browser_fallback_url must be percent-encoded

It is a string extra inside a semicolon-delimited list, so an unencoded https://example.com/p?id=42 breaks the parse at the first ; or is truncated at the ?. Encode the whole value — https%3A%2F%2Fexample.com%2Fp%3Fid%3D42 — and note that query parameters inside it need a second round of encoding if they themselves contain a URL.

What Chrome strips, and what happens with no app

Chrome does not hand your fragment to Android verbatim. Before launching, it sanitises the parsed Intent: it adds the BROWSABLE category, and it discards the component and selector fields. That is deliberate — without it, any web page could target a non-exported activity inside any installed app by naming its class directly. The practical rule is that package= is honoured and component= is a waste of bytes.

Chrome's behaviour when the intent cannot be handled.
SituationWhat Chrome does
App installed, filter matchesLaunches the app with the data URI and extras
Not installed, browser_fallback_url presentNavigates to the fallback URL
Not installed, no fallback, package= setOpens the Play Store listing for that package
Not installed, no fallback, no package=Nothing visible happens
No user gestureBlocked, regardless of everything above
Fallback is intent:// or javascript:Rejected — the fallback must be a web URL

The fourth row is the failure teams report as "the link does nothing". Chrome has correctly determined that no activity can handle the intent, found no instruction for that case, and stopped. Always set a fallback, and prefer a real web page over a store listing so that desktop, iOS and every unsupported browser land somewhere useful — the same reasoning as a link fallback chain.

The filter the target activity must declare
<!-- The BROWSABLE category is not optional. Chrome adds it to the
     intent, so a filter without it will not match. android:exported
     must be true, and is required explicitly from Android 12. -->
<activity android:name=".DeepLinkActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" android:host="product" />
    </intent-filter>
</activity>

Note that the intent above targets a URI scheme, not a verified domain, so the filter is a scheme filter and no assetlinks.json is involved. That is a feature when you need a link to reach a package you name, and a liability in every other respect — see intent filters for why scheme-only filters are hijackable.

Where it works, and what to use instead

Support for each Android link mechanism by surface.
Surfaceintent://Verified App LinkCustom scheme
Chrome for AndroidYesYesYes
Samsung Internet, Edge, other ChromiumUsuallyYesYes
Firefox for AndroidPartialYesYes
Android WebView in someone else's appOnly if they implement itOnly if they implement itOnly if they implement it
Instagram, Facebook, TikTok in-app browsersUnreliableUnreliableUnreliable
Any browser on iOSNoN/AN/A
DesktopNoN/AN/A

A raw WebView does not handle intent:// at all unless the hosting app overrides shouldOverrideUrlLoading, parses the URL and starts the activity itself. Since the hosting app is usually not yours, treat every embedded browser as a surface where the intent will fail — which is the same conclusion reached from the other direction in deep links in in-app browsers.

Verify the domain first, keep the intent as the escape hatch

A verified App Link is one https:// URL that works in every browser, every in-app WebView that honours the system handler, and as a shareable link that renders a preview. It cannot name a package or declare a fallback, which is precisely when intent:// earns its place: reaching a specific package deterministically, or handling a domain you cannot verify.

Testing both paths from the shell
# The scheme the intent resolves to, sent straight to the package.
adb shell am start -W -a android.intent.action.VIEW   -c android.intent.category.BROWSABLE   -d "myapp://product/42" com.example.app

# What actually resolves an intent URL on the device. Chrome's
# sanitisation is not reproduced here, so this is the upper bound
# of what will work, not a guarantee that Chrome will do it.
adb shell am start -a android.intent.action.VIEW   -d "intent://product/42#Intent;scheme=myapp;package=com.example.app;end"

# Is the package's domain actually verified? If it is, drop the
# intent:// from the happy path and keep it only as a fallback.
adb shell pm get-app-links com.example.app

Deep link debugger

Paste the intent URL or the https link behind it and the debugger resolves the whole chain — redirects, the fallback that would fire, and whether the domain is verified for App Links so you can tell if you still need the intent at all.

Open the deep link debugger

Frequently asked questions

What is an intent:// URL?
It is a URL that encodes an Android Intent inside a link, using the form intent://host/path#Intent;scheme=…;package=…;end. Android parses it with Intent.parseUri, so the fragment can carry an action, categories, typed extras and a target package, and Chrome adds a browser_fallback_url extra that says where to send the user when no installed app can handle the intent.
Why does my intent:// link do nothing in Chrome?
The two common causes are a missing user gesture and a missing fallback. Chrome will not launch an intent from a page-load redirect, a meta refresh or a scripted navigation — it needs a real click. If the gesture is present but the app is absent and you supplied neither browser_fallback_url nor a package to open in the Play Store, Chrome correctly determines there is nothing to do and stops silently.
Does intent:// work on iOS?
No. The intent:// scheme is an Android framework construct parsed by Intent.parseUri, so no browser on iOS can act on it, including Chrome for iOS, which uses the system web engine. iOS equivalents are Universal Links for a verified domain and a custom URI scheme for a named app, and neither supports declaring a fallback URL inside the link itself.
Does Chrome honour the component field in an intent URL?
No. Before launching, Chrome sanitises the parsed Intent by adding the BROWSABLE category and discarding the component and selector fields. This prevents a web page from targeting a non-exported activity inside an arbitrary installed app by naming its class. Use package= to restrict which app can respond; component= will be dropped.
Should I use intent:// or a verified App Link?
Prefer a verified App Link for anything shareable: one https URL that works across browsers, renders a link preview, and cannot be hijacked by another app claiming the same scheme. Keep intent:// for the two cases it uniquely covers — deterministically reaching a package you name, and declaring an explicit fallback URL for the not-installed case on a domain you cannot verify.

Related terms

  • Android App LinkAn Android App Link is an HTTPS URL that opens an Android app directly, without a chooser dialog, because the system has verified through a file on the domain that the app is authorised to handle it.
  • Intent FilterAn intent filter is an element in an Android app's manifest that declares which intents an activity can handle, including the URL patterns that should open it.
  • Custom URI SchemeA custom URI scheme is a non-standard URL protocol, such as myapp://, that an app registers with the operating system so that URLs beginning with it open that app.
  • Link Fallback ChainA link fallback chain is the ordered set of destinations a single link resolves to — the app, the app store, or a web page — depending on the user's platform and whether the app is installed.
  • Deep links in in-app browsersAn in-app browser is an embedded webview inside another app that renders links without handing them to the operating system, which prevents Universal Links and App Links from ever reaching the app that claims the domain.