Skip to content
Tolinku
Tolinku
Sign In Start Free
Android Development · · 7 min read

Android Instant Apps and Deep Linking

By Tolinku Staff
|
Tolinku app links dashboard screenshot for android blog posts

Android Instant Apps (now called Google Play Instant) let users run parts of your app without installing it. A user taps a link, and the relevant module loads instantly, no Play Store visit, no download progress bar, no "Open" button. They're using your app within seconds.

The entire Instant Apps experience is built on deep linking. The URL determines which module to load, what content to show, and how to handle the user's session. Getting deep linking right is the difference between a seamless instant experience and a blank screen.

This guide covers how Instant Apps interact with App Links, how to configure deep linking for instant modules, and how to convert instant users into full installs. For the App Links foundation, see the Android App Links complete guide. For understanding fallback behavior when the app isn't installed, see the deep link fallback behavior guide.

How Instant Apps Work

When a user taps a URL that's associated with an Instant App:

  1. Android checks if the URL maps to an installed app (standard App Links). If yes, the installed app opens.
  2. If not installed, Android checks if the URL maps to an Instant App module on Google Play.
  3. If an instant module exists, Android downloads the module (typically 4-10 MB) and runs it immediately.
  4. If no instant module exists, the URL opens in the browser as normal.

The key insight: Instant Apps use the same URL structure and verification mechanism as regular App Links. The only difference is what happens when the app isn't installed.

User taps URL
    ├─ App installed? → Open app (standard App Links)
    └─ Not installed?
        ├─ Instant module available? → Load instant module
        └─ No instant module? → Open in browser

Prerequisites

Before implementing Instant App deep links:

  1. Your app must be modularized. Instant Apps require Android App Bundles and feature modules. Each instant-enabled feature is a separate module.

    App Links must be verified. Instant Apps use the same Digital Asset Links verification as regular App Links. Your .well-known/assetlinks.json must be valid.

    Target URL must be declared. Each instant module declares which URLs it handles in the manifest.

    Module must be under the size limit. Individual instant feature modules must be under 15 MB (total instant app under 15 MB).

    Module Structure

    A typical Instant App has:

    app/
    ├── base/          (shared code, always loaded)
    ├── feature-main/  (main installable feature)
    ├── feature-product/  (instant-enabled: product detail)
    └── feature-checkout/ (instant-enabled: checkout flow)
    

    Manifest Configuration

    Each instant module declares its URL handling in its own AndroidManifest.xml:

    <!-- feature-product/src/main/AndroidManifest.xml -->
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:dist="http://schemas.android.com/apk/distribution"
        package="com.example.app.feature.product">
    
        <dist:module
            dist:instant="true"
            dist:title="Product Detail">
            <dist:fusing dist:include="true" />
        </dist:module>
    
        <application>
            <activity
                android:name=".ProductDetailActivity"
                android:exported="true">
                <intent-filter android:autoVerify="true"
                               android:order="1">
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.BROWSABLE" />
                    <data
                        android:scheme="https"
                        android:host="yourapp.com"
                        android:pathPattern="/products/.*" />
                </intent-filter>
    
                <meta-data
                    android:name="default-url"
                    android:value="https://yourapp.com/products" />
            </activity>
        </application>
    </manifest>
    

    Key elements:

    • dist:instant="true": Marks this module as instant-enabled.
    • android:autoVerify="true": Required for App Links verification.
    • android:order="1": Priority when multiple filters match. Higher numbers are checked first.
    • default-url: The fallback URL if the module can't handle the specific URL.

    Build Configuration

    In your app-level build.gradle.kts:

    android {
        // Enable Instant Apps
        dynamicFeatures += setOf(
            ":feature-product",
            ":feature-checkout"
        )
    }
    

    In each feature module's build.gradle.kts:

    plugins {
        id("com.android.dynamic-feature")
    }
    
    android {
        // Instant module configuration
    }
    

    Extracting URL Parameters

    When the instant module launches, extract the deep link data from the intent:

    class ProductDetailActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            val uri = intent.data
            if (uri == null) {
                // No deep link data; show default product list
                showProductList()
                return
            }
    
            // Extract product ID from the URL path
            // URL: https://yourapp.com/products/abc123
            val productId = uri.lastPathSegment
    
            // Extract optional query parameters
            // URL: https://yourapp.com/products/abc123?ref=campaign1
            val referralSource = uri.getQueryParameter("ref")
    
            if (productId != null) {
                loadProduct(productId, referralSource)
            } else {
                showProductList()
            }
        }
    }
    

    Sharing State Between Instant and Installed App

    When a user installs the full app after using the instant version, you want to preserve their session. Use the Cookie API to transfer data:

    import com.google.android.gms.instantapps.InstantApps
    
    // In the instant module: save state before install
    fun saveInstantState() {
        val cookie = JSONObject().apply {
            put("user_session", "session_token_here")
            put("cart_items", cartItemsJson)
            put("referral_source", referralSource)
        }
    
        InstantApps.getPackageManagerCompat(this)
            .setInstantAppCookie(cookie.toString().toByteArray())
    }
    
    // In the installed app: retrieve state after install
    fun restoreFromInstant() {
        val cookieBytes = InstantApps.getPackageManagerCompat(this)
            .getInstantAppCookie()
    
        if (cookieBytes.isNotEmpty()) {
            val cookie = JSONObject(String(cookieBytes))
            val session = cookie.getString("user_session")
            val cartItems = cookie.getString("cart_items")
            // Restore the user's session and cart
        }
    }
    

    The cookie is limited to 16 KB, so store only essential state (session tokens, referral attribution, cart contents).

    Converting Instant Users to Full Installs

    The goal of an Instant App is to demonstrate value quickly and motivate the full install. Deep links play a role in this conversion.

    Show an Install Prompt at the Right Moment

    Don't show the install prompt immediately. Let the user experience value first:

    // Show install prompt after the user completes a meaningful action
    fun onProductAddedToCart() {
        if (InstantApps.isInstantApp(this)) {
            // The user found a product they want; now prompt for install
            showInstallPrompt()
        }
    }
    
    fun showInstallPrompt() {
        InstantApps.showInstallPrompt(
            this,
            intent,        // The current intent (preserves deep link data)
            REQUEST_INSTALL,
            "referral_source" // Optional referrer string for Play Store attribution
        )
    }
    

    When the user installs from an instant module, the install intent can carry the original deep link data:

    fun showInstallPrompt() {
        val postInstallIntent = Intent(Intent.ACTION_VIEW).apply {
            data = Uri.parse("https://yourapp.com/products/${currentProductId}")
            setPackage(packageName)
            addCategory(Intent.CATEGORY_BROWSABLE)
        }
    
        InstantApps.showInstallPrompt(
            this,
            postInstallIntent,
            REQUEST_INSTALL,
            null
        )
    }
    

    After installation, the full app opens with the same deep link, and the user lands on the same product they were viewing.

    Your deep link routing logic needs to handle both contexts:

    class DeepLinkRouter : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            val uri = intent.data ?: return finish()
            val isInstant = InstantApps.isInstantApp(this)
    
            when {
                uri.path?.startsWith("/products") == true -> {
                    if (isInstant) {
                        // In instant mode: show product detail (read-only)
                        navigateToProduct(uri.lastPathSegment, readOnly = true)
                    } else {
                        // In installed mode: show full product experience
                        navigateToProduct(uri.lastPathSegment, readOnly = false)
                    }
                }
                uri.path?.startsWith("/checkout") == true -> {
                    if (isInstant) {
                        // Checkout requires full install
                        showInstallPrompt()
                    } else {
                        navigateToCheckout()
                    }
                }
                else -> navigateToHome()
            }
        }
    }
    

    Using ADB

    # Launch an instant module via deep link
    adb shell am start -a android.intent.action.VIEW \
      -d "https://yourapp.com/products/abc123" \
      --es "callerId" "com.google.android.instantapps.supervisor" \
      --es "instantAppPackageName" "com.example.app"
    

    Using Android Studio

    1. Create a run configuration for the instant module.
    2. Set the launch URL in the configuration.
    3. Run on a device with Google Play services.

    Common Test Scenarios

    1. Direct URL tap: Tap the URL in a browser. Should load the instant module.
    2. App already installed: Tap the same URL. Should open the installed app, not the instant module.
    3. Install from instant: Use the instant module, then install. Session state should transfer.
    4. Invalid URL: Tap a URL that doesn't match any module. Should fall back to browser.

    Tolinku deep links work with Instant Apps through the standard App Links mechanism. When a user taps a Tolinku link:

    1. If the app is installed, Tolinku's redirect opens the app via App Links.
    2. If the app is not installed, the redirect falls through to the web fallback or app store.

    To support Instant Apps with Tolinku links, ensure your Tolinku domain's redirect chain leads to a URL that your instant module handles. Configure the web fallback in your route settings to point to the URL associated with the instant module.

    Limitations and Considerations

    Size constraints. Each instant feature module must be under 15 MB. This limits what you can include. Heavy features (video editing, AR, complex maps) may not fit.

    API restrictions. Instant Apps can't access certain APIs: background services, device identifiers, notification posting. Check the restricted API list.

    Geographic availability. Google Play Instant is available in most countries but may not work on all devices (requires Google Play services 11.8+).

    Analytics attribution. Instant App sessions are separate from installed app sessions. Make sure your analytics tool can link instant sessions to subsequent installs.

    For the full App Links setup, see the Android App Links guide. For understanding how links are verified, see verified vs. unverified App Links.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.