Skip to content
Tolinku
Tolinku
Sign In Start Free
Deep Linking · · 6 min read

Google Play Install Referrer for Deferred Deep Links

By Tolinku Staff
|
Tolinku industry trends dashboard screenshot for deep linking blog posts

The Google Play Install Referrer API is Android's built-in mechanism for passing data through an app install. When a user clicks a link that redirects to the Play Store, the referrer string you append to the Play Store URL is recorded by Google and made available to your app on first launch.

This is fundamentally different from how iOS works. Apple has no equivalent mechanism. On Android, the referrer gives you a deterministic, first-party signal for install attribution without relying on advertising IDs or probabilistic fingerprinting. Understanding how it works, where it can fail, and how to validate the data it returns makes your deferred deep linking implementation significantly more reliable.

How the Referrer Gets There

The flow starts with a redirect URL. When a user clicks a Tolinku deep link before your app is installed, Tolinku redirects them to the Play Store with the referrer parameter included:

https://play.google.com/store/apps/details
  ?id=com.yourcompany.yourapp
  &referrer=utm_source%3Dtolinku%26utm_medium%3Dlink%26tolk_click_id%3Dabc123

The referrer value is URL-encoded. In decoded form it is:

utm_source=tolinku&utm_medium=link&tolk_click_id=abc123

Google Play records this string server-side when the user arrives at the listing. If the user installs the app, Google associates the referrer with that install. On first launch, your app can query the Install Referrer API to retrieve it.

The official Play Install Referrer documentation covers the complete API surface.

Setting Up InstallReferrerClient

Add the library to your build.gradle.kts (app module):

dependencies {
    implementation("com.android.installreferrer:installreferrer:2.2")
}

The library handles the connection to the Play Store service. The basic setup:

import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerStateListener
import com.android.installreferrer.api.ReferrerDetails

class ReferrerManager(private val context: Context) {

    private var client: InstallReferrerClient? = null

    fun fetchReferrer(callback: (ReferrerDetails?) -> Unit) {
        client = InstallReferrerClient.newBuilder(context).build()

        client?.startConnection(object : InstallReferrerStateListener {

            override fun onInstallReferrerSetupFinished(responseCode: Int) {
                when (responseCode) {
                    InstallReferrerClient.InstallReferrerResponse.OK -> {
                        val details = try {
                            client?.installReferrer
                        } catch (e: RemoteException) {
                            null
                        }
                        callback(details)
                        client?.endConnection()
                    }
                    InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> {
                        // Play Store does not support this API on this device
                        callback(null)
                    }
                    InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> {
                        // Play Store service is not available
                        callback(null)
                    }
                }
            }

            override fun onInstallReferrerServiceDisconnected() {
                // Service disconnected; connection will be retried automatically
                // in most cases. Log this for debugging.
            }
        })
    }
}

Always call endConnection() after retrieving the data. Leaving the connection open consumes resources and may interfere with subsequent queries.

Parsing the Referrer String

The installReferrer property on ReferrerDetails returns the raw, URL-encoded referrer string. Parse it using Android's Uri class:

import android.net.Uri

fun parseReferrer(rawReferrer: String): Map<String, String> {
    val uri = Uri.parse("https://example.com/?$rawReferrer")
    val params = mutableMapOf<String, String>()
    uri.queryParameterNames.forEach { key ->
        uri.getQueryParameter(key)?.let { value ->
            params[key] = value
        }
    }
    return params
}

For a referrer of utm_source=tolinku&utm_medium=link&tolk_click_id=abc123&utm_campaign=spring, this returns:

mapOf(
    "utm_source" to "tolinku",
    "utm_medium" to "link",
    "tolk_click_id" to "abc123",
    "utm_campaign" to "spring"
)

Extract the Tolinku click ID (tolk_click_id) and send it to the attribution server to retrieve the original deep link data.

UTM Parameters

Google Analytics and most analytics platforms recognize the standard UTM parameters: utm_source, utm_medium, utm_campaign, utm_content, and utm_term. Tolinku populates these automatically when you create links with campaign parameters.

Beyond UTM parameters, you can include any custom parameters in the referrer. Keep in mind the 4096-character length limit for the referrer string. In practice, standard campaign parameters plus a click ID are well within this limit.

A full referrer string from a Tolinku link might look like:

utm_source=facebook_ads
&utm_medium=cpc
&utm_campaign=q1_retargeting
&utm_content=video_ad_v2
&tolk_click_id=clk_9f2a3b4c5d
&tolk_link_id=lnk_referral_spring

Timing: When is the Referrer Available?

The referrer is available immediately on first launch in most cases, but there is a subtlety. The Play Install Referrer API connects to the Play Store's service process via IPC. If the Play Store app is updating or has not fully started, the connection may take a moment.

The onInstallReferrerSetupFinished callback fires asynchronously. Do not block the main thread waiting for it. Your app should show a loading state or a default screen while the referrer query resolves, then route the user based on the result.

Implement a timeout to avoid leaving users on a loading screen indefinitely if the service is slow:

class ReferrerManagerWithTimeout(private val context: Context) {

    fun fetchReferrer(
        timeoutMs: Long = 3000,
        callback: (ReferrerDetails?) -> Unit
    ) {
        val handler = Handler(Looper.getMainLooper())
        var called = false

        val timeoutRunnable = Runnable {
            if (!called) {
                called = true
                callback(null)
            }
        }

        handler.postDelayed(timeoutRunnable, timeoutMs)

        val manager = ReferrerManager(context)
        manager.fetchReferrer { details ->
            handler.removeCallbacks(timeoutRunnable)
            if (!called) {
                called = true
                callback(details)
            }
        }
    }
}

Three seconds is a reasonable default. Adjust based on your app's startup time constraints.

Additional Fields on ReferrerDetails

ReferrerDetails provides more than just the referrer string:

val details: ReferrerDetails = client.installReferrer

val referrerString = details.installReferrer         // The URL-encoded referrer
val clickTimestamp = details.referrerClickTimestampSeconds   // Unix timestamp of click
val installTimestamp = details.installBeginTimestampSeconds  // Unix timestamp of install begin
val googlePlayInstant = details.googlePlayInstantParam       // Whether opened via Instant App

The click and install timestamps are useful for server-side validation. If the gap between click and install exceeds your expected match window (for example, 30 days), you may want to treat the attribution as suspect and fall back to organic. Understanding the full install attribution flow helps contextualize how these timestamps fit into the broader matching process.

Server-Side Validation

Never trust the referrer string without server-side verification. A user can modify the referrer string before it reaches your app by sideloading a modified APK or by other means.

The validation flow:

  1. Your app receives the referrer and extracts the tolk_click_id.
  2. Your app sends the click ID to Tolinku's attribution API.
  3. Tolinku's server looks up the click record by that ID, checks that the click is recent and not already attributed to another install, and returns the verified deep link data.
  4. Your app uses the returned data for routing.

If the click ID is not found, has already been used, or was created outside the valid attribution window, the server returns an error and the install is treated as organic. This prevents click ID stuffing and referrer manipulation.

Tolinku's Android SDK handles this validation automatically when you use resolveDeferred(). The SDK fetches the referrer, extracts the click ID, validates it server-side, and returns the verified deep link data in a single call.

Reliability Considerations

The Play Install Referrer API is reliable in typical conditions, but several factors can affect it:

Non-Play Store installs. The referrer API only works for apps installed through Google Play. Sideloaded APKs, manufacturer pre-installs, and enterprise MDM deployments do not go through the Play Store and will not have a referrer.

Browser referrer stripping. Some Android browsers strip parameters from the Play Store redirect URL. This is more common with certain in-app browsers (some social media apps open links in an internal WebView that modifies outgoing URLs). The Tolinku link server handles some of this with redirect chain normalization, but it cannot overcome all browser-level stripping.

Device compatibility. The API requires Google Play Services. Devices that ship without Google Play (Huawei phones post-2019, Amazon Fire tablets, some Chinese OEM devices) do not support the API. Fall back to fingerprinting for these devices.

Referrer not found. If a user installs through a Play Store search (not through a link), the installReferrer value will be "organic" or an empty string. Handle this case and treat it as an organic install.

val rawReferrer = details.installReferrer
if (rawReferrer.isNullOrBlank() || rawReferrer == "organic") {
    // Organic install, no deferred link to resolve
    showDefaultOnboarding()
    return
}

Testing

Use ADB to simulate a referrer without going through the full Play Store install flow:

adb shell am broadcast \
  -a com.android.vending.INSTALL_REFERRER \
  -n com.yourcompany.yourapp/.ReferrerReceiver \
  --es "referrer" "utm_source=test&tolk_click_id=test_click_001"

This approach works for development testing. For full integration testing, use the Play Store's referrer testing tool or test with real installs via internal testing tracks.

Putting It All Together

The Play Install Referrer API gives Android deferred deep linking a reliability advantage over iOS. Because the referrer travels through Google's infrastructure, it is not subject to the match-window uncertainty of fingerprinting or the permission walls of advertising IDs.

For the full picture of how the referrer fits into the broader attribution flow, see Install Attribution Flow: From Ad Click to First Open. For the complete Android SDK integration, see the Android implementation guide and the SDK documentation.

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.