Chrome on Android supports a special URL scheme, intent://, that lets web pages launch Android apps directly. Unlike custom URL schemes (which show an error if the app isn't installed) and unlike App Links (which require domain verification), intent URLs give you explicit control over what happens: which app to target, what data to pass, and where to send the user if the app isn't installed.
Intent URLs are the most powerful deep linking mechanism available from web pages on Android, but they're also the most complex. This guide covers the syntax, common patterns, fallback behavior, and when to use intent URLs vs. the alternatives.
For the App Links approach, see the Android App Links complete guide. For how Custom Tabs interact with deep links, see the Chrome Custom Tabs guide.
The Intent URL Syntax
intent://
HOST/PATH
#Intent;
scheme=SCHEME;
package=PACKAGE_NAME;
action=ACTION;
category=CATEGORY;
S.key=value;
S.anotherKey=anotherValue;
S.browser_fallback_url=ENCODED_URL;
end
A real example:
intent://product/abc123#Intent;scheme=https;package=com.example.app;S.browser_fallback_url=https%3A%2F%2Fexample.com%2Fproduct%2Fabc123;end
This tells Chrome:
- Try to open
https://product/abc123in the appcom.example.app. - If the app isn't installed, redirect to
https://example.com/product/abc123.
Syntax Breakdown
| Component | Required | Description |
|---|---|---|
intent://HOST/PATH |
Yes | The data URI (host and path) |
scheme= |
Yes | The URI scheme (usually https) |
package= |
No | Target app's package name. Without this, any matching app can handle the intent. |
action= |
No | The intent action (default: android.intent.action.VIEW) |
category= |
No | Additional category (default: android.intent.category.BROWSABLE) |
S.key=value |
No | String extras to pass to the app |
S.browser_fallback_url= |
No | Where to go if the app isn't installed |
String Extras
Pass arbitrary data to the app using S. prefixed key-value pairs:
intent://open#Intent;
scheme=myapp;
package=com.example.app;
S.referral_code=ABC123;
S.campaign=summer_sale;
S.source=email;
S.browser_fallback_url=https%3A%2F%2Fexample.com;
end
The app receives these as string extras in the launching intent:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val referralCode = intent.getStringExtra("referral_code") // "ABC123"
val campaign = intent.getStringExtra("campaign") // "summer_sale"
val source = intent.getStringExtra("source") // "email"
}
Fallback Behavior
With S.browser_fallback_url
If the target app isn't installed (or the package doesn't match any installed app), Chrome navigates to the fallback URL. This is the most important parameter for a good user experience. For a detailed look at how different platforms handle missing-app scenarios, see Deep Link Fallback Behavior Across Platforms.
intent://open#Intent;
scheme=myapp;
package=com.example.app;
S.browser_fallback_url=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.example.app;
end
The fallback URL must be URL-encoded. Common fallback targets:
- Google Play Store listing (for install)
- A web version of the content
- A landing page explaining the app
Without S.browser_fallback_url
If no fallback is specified and the app isn't installed, Chrome navigates to the Google Play Store page for the package name. If the package parameter is also missing, Chrome does nothing (the link silently fails).
Without package
If you omit package, Chrome resolves the intent using the standard Android intent resolution mechanism. Any app that matches the scheme, host, and path can handle it. This is less predictable but useful when you don't want to target a specific app.
Common Patterns
Pattern 1: Open App or Go to Play Store
The most common use case: try to open the app, fall back to the Play Store if not installed.
<a href="intent://open#Intent;scheme=https;package=com.example.app;S.browser_fallback_url=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.example.app;end">
Open in App
</a>
Pattern 2: Deep Link to Specific Content
Open a specific screen in the app, fall back to the web version of that content.
<a href="intent://products/abc123#Intent;scheme=https;package=com.example.app;S.browser_fallback_url=https%3A%2F%2Fexample.com%2Fproducts%2Fabc123;end">
View Product
</a>
Pattern 3: Pass Campaign Data
Include UTM-style parameters for analytics.
<a href="intent://open#Intent;scheme=myapp;package=com.example.app;S.utm_source=email;S.utm_medium=newsletter;S.utm_campaign=spring2026;S.browser_fallback_url=https%3A%2F%2Fexample.com%3Futm_source%3Demail;end">
Open App
</a>
Pattern 4: JavaScript Generation
Generate intent URLs dynamically:
function buildIntentUrl(options) {
const {
host = 'open',
path = '',
scheme = 'https',
packageName,
extras = {},
fallbackUrl,
} = options;
let intentUrl = `intent://${host}${path}#Intent;scheme=${scheme};`;
if (packageName) {
intentUrl += `package=${packageName};`;
}
for (const [key, value] of Object.entries(extras)) {
intentUrl += `S.${key}=${encodeURIComponent(value)};`;
}
if (fallbackUrl) {
intentUrl += `S.browser_fallback_url=${encodeURIComponent(fallbackUrl)};`;
}
intentUrl += 'end';
return intentUrl;
}
// Usage
const url = buildIntentUrl({
host: 'products',
path: '/abc123',
packageName: 'com.example.app',
extras: { referral_code: 'XYZ', campaign: 'email' },
fallbackUrl: 'https://example.com/products/abc123',
});
Intent URLs vs. App Links vs. Custom Schemes
| Feature | Intent URLs | App Links | Custom Schemes |
|---|---|---|---|
| Works from web | Yes (Chrome only) | Yes (all browsers) | Limited |
| Fallback support | Built-in (browser_fallback_url) |
Requires server-side redirect | No built-in fallback |
| Disambiguation dialog | No (targets specific package) | No (if verified) | Yes (if multiple apps register) |
| Cross-browser | Chrome and some Chromium browsers | All browsers | Varies |
| Domain verification | Not required | Required (Digital Asset Links) | Not applicable |
| Data passing | String extras | URL path/query parameters | URL path/query parameters |
| iOS support | No | No (use Universal Links) | Partial |
When to Use Intent URLs
- You need to target a specific app by package name and don't want the disambiguation dialog.
- You need to pass structured data (string extras) beyond what URL parameters support.
- You need a guaranteed fallback when the app isn't installed.
- You're building Android-only web-to-app flows where cross-platform isn't needed.
When to Use App Links Instead
- Cross-browser support is needed (intent URLs only work in Chrome).
- Cross-platform (iOS + Android) is needed.
- SEO matters (App Links use real HTTPS URLs that search engines can index).
- You control the domain and can host the Digital Asset Links file.
When Tolinku Links Are Better
Tolinku deep links abstract away the platform differences. A single Tolinku URL works on iOS (Universal Links), Android (App Links), and web (redirect fallback), without needing to generate platform-specific intent URLs. The platform handles browser detection, app-installed detection, and fallback routing.
Use intent URLs only when you need the specific capabilities they offer (package targeting, string extras) and you're building an Android-only flow.
Security Considerations
Validate Incoming Intent Data
Any app that receives intents from intent URLs should validate the data. For the full intent filter configuration that determines which URLs your app handles, see Android Intent Filters for Deep Links.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val uri = intent.data ?: return
val referralCode = intent.getStringExtra("referral_code")
// Validate: referral codes should be alphanumeric, max 20 chars
if (referralCode != null && !referralCode.matches(Regex("^[a-zA-Z0-9]{1,20}$"))) {
Log.w("DeepLink", "Invalid referral code: $referralCode")
return
}
// Safe to use referralCode
}
Don't Trust the package Parameter
The package parameter in an intent URL tells Chrome which app to launch, but the receiving app shouldn't assume it was launched from a trusted source. Always validate incoming data as if it came from an untrusted external source.
Avoid Sensitive Data in Intent URLs
Intent URLs are visible in browser history, server logs, and potentially to intermediary services. Don't include sensitive data (tokens, passwords, PII) directly in the URL. Instead, pass a short-lived reference ID and resolve the sensitive data server-side.
For setting up App Links with Tolinku, the platform generates correctly formatted deep links that work across all Android browsers and versions, not just Chrome.
Get deep linking tips in your inbox
One email per week. No spam.