Android Deferred Deep Links

Complete guide to implementing Android deferred deep links using Google Play Install Referrer API. Includes code examples, best practices, and testing strategies.


Android deferred deep linking enables your app to deliver personalized onboarding experiences by capturing user intent before installation and applying it after the app is first launched. The Install Referrer API is Google's recommended mechanism for implementing this functionality, providing a secure and reliable way to pass attribution data from pre-install clicks to post-install app sessions.

This guide covers everything you need to know about configuring Android deferred deep links using the Install Referrer API, including implementation strategies, best practices, and common pitfalls to avoid.

Understanding the Install Referrer API

The Google Play Install Referrer API allows apps to retrieve referral content that initiated an app installation from Google Play. When a user clicks a link before your app is installed, the referrer information is stored by Google Play and made available to your app after installation.

Key advantages of the Install Referrer API include:

  • Security: Direct communication with Google Play Store eliminates broadcast vulnerabilities

  • Reliability: More accurate than legacy broadcast receivers with guaranteed delivery

  • Persistence: Referrer data remains available for up to 90 days after installation

  • Fraud Prevention: Includes click timestamp and install begin timestamp for attribution validation

Prerequisites for Implementation

Before implementing deferred deep linking with Install Referrer, ensure you have:

  • Android app published on Google Play Store or in testing tracks

  • Minimum SDK version 14 (Ice Cream Sandwich) or higher

  • Google Play Services installed on target devices

Step 1: Add Install Referrer Library Dependency

Add the Google Play Install Referrer library to your app's build.gradle file:

dependencies { 
  implementation 'com.android.installreferrer:installreferrer:2.2' 
}

This library provides the necessary APIs to query install referrer information from Google Play.

Step 2: Create the Referrer Client

Implement the Install Referrer connection in your main Activity or Application class. Here's a complete implementation:

import android.os.Bundle
import android.os.RemoteException
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerStateListener
import com.android.installreferrer.api.ReferrerDetails

class MainActivity : AppCompatActivity() {

    private lateinit var referrerClient: InstallReferrerClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setupInstallReferrer()
    }

    private fun setupInstallReferrer() {
        referrerClient = InstallReferrerClient.newBuilder(this).build()

        referrerClient.startConnection(object : InstallReferrerStateListener {

            override fun onInstallReferrerSetupFinished(responseCode: Int) {
                when (responseCode) {
                    InstallReferrerClient.InstallReferrerResponse.OK -> {
                        // Connection established
                        handleReferrerDetails()
                    }

                    InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> {
                        // API not available on the current Play Store app
                        Log.w(TAG, "Install Referrer not supported")
                    }

                    InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> {
                        // Connection couldn't be established
                        Log.w(TAG, "Install Referrer service unavailable")
                    }
                }
            }

            override fun onInstallReferrerServiceDisconnected() {
                // Try to restart the connection on the next request
                Log.d(TAG, "Install Referrer service disconnected")
            }
        })
    }

    private fun handleReferrerDetails() {
        try {
            val response: ReferrerDetails = referrerClient.installReferrer
            val referrerUrl = response.installReferrer
            val referrerClickTime = response.referrerClickTimestampSeconds
            val appInstallTime = response.installBeginTimestampSeconds
            val instantExperienceLaunched = response.googlePlayInstantParam

            // Hit smler endpoint to mark as conversion
            processDeferredDeepLink(referrerUrl)

        } catch (e: RemoteException) {
            Log.e(TAG, "Error retrieving referrer details", e)
        } finally {
            referrerClient.endConnection()
        }
    }

    companion object {
        private const val TAG = "MainActivity"
    }
}

You can read more about tracking conversion to know when and how to track a conversion

Create a utility function to parse the referrer string and extract your deep link destination:

You can see an example of how to do it in our github flutter sdk

Step 4: Handle First Launch Detection

Critical to deferred deep linking is ensuring the experience only triggers on the first launch after installation. Implement robust first-launch detection using SharedPreferences or a more sophisticated solution:

class FirstLaunchManager(private val context: Context) {

    private val prefs =
        context.getSharedPreferences("deep_link_prefs", Context.MODE_PRIVATE)

    companion object {
        private const val KEY_FIRST_LAUNCH = "is_first_launch"
        private const val KEY_INSTALL_TIME = "install_timestamp"
        private const val KEY_REFERRER_PROCESSED = "referrer_processed"
    }

    fun isFirstLaunch(): Boolean {
        // Check if this is truly the first launch
        val isFirst = prefs.getBoolean(KEY_FIRST_LAUNCH, true)
        val referrerProcessed = prefs.getBoolean(KEY_REFERRER_PROCESSED, false)
        return isFirst && !referrerProcessed
    }

    fun markReferrerProcessed() {
        prefs.edit()
            .putBoolean(KEY_FIRST_LAUNCH, false)
            .putBoolean(KEY_REFERRER_PROCESSED, true)
            .putLong(KEY_INSTALL_TIME, System.currentTimeMillis())
            .apply()
    }

    fun shouldRetryReferrerFetch(): Boolean {
        val installTime = prefs.getLong(KEY_INSTALL_TIME, 0)
        val daysSinceInstall =
            (System.currentTimeMillis() - installTime) / (1000 * 60 * 60 * 24)

        // Retry if within 90 days and not yet processed
        return daysSinceInstall < 90 &&
            !prefs.getBoolean(KEY_REFERRER_PROCESSED, false)
    }
}

Best Practices for Install Referrer Implementation

Timing Considerations

The Install Referrer API should be called as early as possible in your app's lifecycle, but with important considerations:

  • Don't block the UI: Fetch referrer data asynchronously to avoid delaying app launch

  • Implement timeouts: Set a maximum wait time (2-3 seconds) for referrer retrieval

  • Cache results: Store referrer data locally after first retrieval to avoid repeated queries

  • Handle delays gracefully: Some devices may have delayed Google Play connections

Testing Your Implementation

Testing deferred deep links requires special procedures since they only work on first install:

  1. Use Internal Testing Track: Publish your app to Google Play's internal testing track

  2. Generate Test Links: Create Play Store links with test referrer parameters

  3. Test Device Preparation: Completely uninstall the app before each test

  4. Click Test Link: Click your test link on the device

  5. Install and Launch: Complete installation and observe first launch behavior

  6. Verify Logs: Check logcat for referrer retrieval and parsing logs

For easier testing during development, create a debug mode that simulates first launch:

// Debug utility for testing 
fun simulateFirstLaunch() { 
  if (BuildConfig.DEBUG) { 
    getSharedPreferences("deep_link_prefs", Context.MODE_PRIVATE).edit().clear().apply() 
  } 
}

Published with LeafPad