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

Android Link Verification Delays and How to Handle Them

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

You've set up your assetlinks.json, configured your intent filters, and published your app. A user installs it. They tap a link to your domain. Instead of your app opening directly, they see the disambiguation dialog: "Open with Chrome or YourApp?"

The App Links verification hasn't completed yet. It can take anywhere from seconds to hours after installation, depending on network conditions, server response times, and the Android version. During this window, your App Links behave like unverified deep links.

This guide covers why verification delays happen, what the user experience looks like during the delay, and strategies to minimize the impact. For the verification process itself, see how Android App Link verification works. For debugging verification failures, see the debugging intent resolution guide.

Why Verification Takes Time

The Verification Flow

When an app is installed (or updated), Android's verification service:

  1. Parses the app's manifest for intent filters with android:autoVerify="true".
  2. Extracts all declared android:host values.
  3. Makes HTTPS requests to https://{host}/.well-known/assetlinks.json for each host.
  4. Validates the response: correct JSON structure, matching package name, matching SHA-256 fingerprint.
  5. Records the verification status for each domain.

Each of these steps can introduce delays.

Common Delay Causes

Network conditions. The verification request is made by the Android system service, which may be queued behind other tasks. On slow or metered connections, the request may be deprioritized or time out.

Server response time. If your assetlinks.json takes more than 5 seconds to respond, Android may treat it as a failure. Slow CDNs, cold starts on serverless endpoints, or overloaded servers all contribute.

Batch processing. Android doesn't verify each app immediately on install. Verification requests are batched and processed periodically. On some devices, this batch runs every few minutes; on others, it may be deferred to a maintenance window.

Multiple domains. Each domain is verified with a separate HTTP request. If you have 5 domains in your intent filters, that's 5 requests. A timeout on any one can delay the entire verification.

Device state. If the device is in Doze mode, battery saver, or has restricted background data, verification requests may be deferred.

What Happens During the Delay

Before Verification Completes

  • Android 12+: Unverified App Links open in the browser by default. The user doesn't see a disambiguation dialog; the link just opens in Chrome. Your app is effectively invisible for those links.
  • Android 11 and below: Unverified links show the "Open with" disambiguation dialog. The user can choose your app or the browser.

After Verification Completes

Links open directly in your app with no dialog or browser involvement.

Verification Persistence

Once verified, the status persists until:

  • The app is uninstalled and reinstalled.
  • The app is updated (triggers re-verification on some Android versions).
  • The user manually resets App Link preferences in settings.
  • The system periodically re-verifies (Android 14+).

Strategies for Handling Delays

Strategy 1: Optimize Server Response Time

The fastest fix. Make your assetlinks.json response as fast as possible:

# Nginx: serve assetlinks.json from memory with long cache
location = /.well-known/assetlinks.json {
    alias /etc/assetlinks/assetlinks.json;
    default_type application/json;
    add_header Cache-Control "public, max-age=3600";

    # Enable gzip for faster transfer
    gzip on;
    gzip_types application/json;
}

Target: under 200ms response time. The file is tiny (typically under 500 bytes), so the bottleneck is usually connection establishment, not transfer.

CDN caching: Serve the file through a CDN (Cloudflare, CloudFront) with edge caching enabled. This puts the file physically closer to the Android verification service.

No redirects: The request to /.well-known/assetlinks.json must return a direct 200 response. Redirects (301, 302) may not be followed by the verification service on all Android versions.

Strategy 2: Use a Web Fallback That Redirects to the App

For the critical first-open experience, don't rely solely on App Links. Use a web page that detects the app and redirects:

<!-- Your landing page at links.yourapp.com/welcome -->
<html>
<head>
    <meta http-equiv="refresh" content="2;url=https://play.google.com/store/apps/details?id=com.example.app">
</head>
<body>
    <script>
        // Try to open the app via intent URL
        const intentUrl = 'intent://welcome#Intent;' +
            'scheme=https;' +
            'package=com.example.app;' +
            'S.browser_fallback_url=' + encodeURIComponent(window.location.href) + ';' +
            'end';

        window.location.href = intentUrl;
    </script>
    <p>Opening app... <a href="https://play.google.com/store/apps/details?id=com.example.app">
        Download from Play Store
    </a></p>
</body>
</html>

If verification hasn't completed and the link opens in the browser, the page attempts to open the app via an intent URL (which doesn't require verification). If the app isn't installed, it falls back to the Play Store.

Tolinku deep links handle verification delays transparently. When a user taps a Tolinku link:

  1. If App Links verification is complete, the app opens directly.
  2. If verification is pending, the Tolinku redirect chain detects the platform and attempts to open the app through alternative mechanisms (intent URLs, JavaScript redirect).
  3. If the app isn't installed, the user is sent to the app store or a web fallback.

This three-layer approach ensures the link works regardless of verification status.

Strategy 4: Test Verification Before Relying on It

In your app's first-run experience, check whether App Links are verified:

// Check if App Links are verified for your domain
fun checkAppLinkStatus(context: Context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val manager = context.getSystemService(DomainVerificationManager::class.java)
        val userState = manager.getDomainVerificationUserState(context.packageName)

        val verifiedDomains = userState?.hostToStateMap
            ?.filter { it.value == DomainVerificationUserState.DOMAIN_STATE_VERIFIED }
            ?.keys ?: emptySet()

        val unverifiedDomains = userState?.hostToStateMap
            ?.filter { it.value != DomainVerificationUserState.DOMAIN_STATE_VERIFIED }
            ?.keys ?: emptySet()

        if (unverifiedDomains.isNotEmpty()) {
            // Verification pending or failed for some domains
            // Consider prompting user to set default app manually
            Log.w("AppLinks", "Unverified domains: $unverifiedDomains")
        }
    }
}

Strategy 5: Prompt Users to Set Default App

If verification fails or is delayed, you can guide users to manually approve your app as the default handler:

// Android 12+: Open the app's default links settings
fun promptDefaultApp(context: Context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val intent = Intent(
            Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
            Uri.parse("package:${context.packageName}")
        )
        context.startActivity(intent)
    }
}

Use this as a last resort. Most users won't navigate system settings, but power users and testers will appreciate the option.

Monitoring Verification in Production

Server-Side Monitoring

Monitor requests to your assetlinks.json endpoint:

# Expected pattern: requests from Android verification service
User-Agent: Mozilla/5.0 (Linux; Android *)

Track:

  • Request volume: Spikes after app releases indicate re-verification.
  • Response codes: Any 4xx or 5xx responses mean failed verifications.
  • Response time: Responses over 5 seconds may timeout.

Client-Side Monitoring

On Android 12+, use the DomainVerificationManager API to check verification status and report it to your analytics:

fun reportVerificationStatus(context: Context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val manager = context.getSystemService(DomainVerificationManager::class.java)
        val userState = manager.getDomainVerificationUserState(context.packageName)

        userState?.hostToStateMap?.forEach { (domain, state) ->
            val statusName = when (state) {
                DomainVerificationUserState.DOMAIN_STATE_VERIFIED -> "verified"
                DomainVerificationUserState.DOMAIN_STATE_SELECTED -> "selected"
                DomainVerificationUserState.DOMAIN_STATE_NONE -> "none"
                else -> "unknown"
            }
            analytics.trackEvent("app_link_status", mapOf(
                "domain" to domain,
                "status" to statusName
            ))
        }
    }
}

This gives you visibility into what percentage of your user base has verified App Links.

Timing Expectations

Scenario Typical Verification Time
Fresh install, good network 10-60 seconds
Fresh install, slow network 1-5 minutes
Fresh install, server timeout Never (fails)
App update 10-60 seconds (re-verification)
Device reboot May re-verify within minutes
Android 14 periodic re-check Every few days

The bottom line: don't assume verification is instant. Design your link flows to work even when verification hasn't completed.

For the full App Links setup, see the Android App Links complete guide. For Tolinku's approach to handling verification across domains, the platform manages asset links files with optimized caching and CDN delivery.

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.