Google Play Install Referrer API in 2026: Attribution Data and Connection States
Install attribution is the one measurement every paid install depends on, and on Google Play it comes from a single, small interface: the Install Referrer API. It is not a dashboard feature and it does not email you numbers — it hands your app the referral content that Play recorded at install time, once, and then it is your job to store it and reconcile it. This tutorial walks the whole path: what the API returns, how to connect, how to read the response, the 90-day rule most teams discover too late, and what to do with each connection state.
Everything below is grounded in Google's own reference pages for the Install Referrer API and the Play Install Referrer Client Library, both checked on 2026-10-27.
Step 1 — Know exactly what the API returns before you design around it
The API retrieves referral content recorded by the Play Store app, and the documented payload is narrow and specific:
- the referrer URL of the installed package;
- the timestamp, in seconds, of the referrer click — available both client- and server-side;
- the timestamp, in seconds, of when the installation began — again both client- and server-side;
- the app version at the time of first install;
- whether the user interacted with your app's instant experience in the past 7 days.
Two requirements gate all of it. The API is exposed by the Play Store app on the device, and devices running Play Store 8.3.73 or later have access automatically. You also need a Google Play Console account. Underneath, the API is an AIDL interface; Kotlin and Java developers are expected to use the client library wrapper rather than the raw AIDL.
Design consequence: this is first-install attribution with a click timestamp and an install-begin timestamp. There is no multi-touch chain, no view-through, and no cross-device graph in the response. If your reporting model assumes any of those, the data has to come from somewhere else.
Step 2 — Add the client library
In the app module's build.gradle, add the dependency. The version documented on the client library page is 2.2:
dependencies {
...
implementation "com.android.installreferrer:installreferrer:2.2"
}
If your module is configured for Kotlin DSL, the same coordinate is added with implementation("com.android.installreferrer:installreferrer:2.2"). Nothing else is required — no manifest receiver, no permission, no Play Console toggle. The old broadcast-receiver approach is what this library replaces; do not carry both paths.
Step 3 — Connect to the Play Store app
The connection is asynchronous, and that single fact is where most broken implementations start. The documented sequence is: build a client with InstallReferrerClient.newBuilder(this).build(), call startConnection(), and pass an InstallReferrerStateListener that receives the result.
referrerClient = InstallReferrerClient.newBuilder(this).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerResponse.OK -> { /* connection established */ }
InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> { /* API unavailable on this Play Store app */ }
InstallReferrerResponse.SERVICE_UNAVAILABLE -> { /* connection could not be established */ }
}
}
override fun onInstallReferrerServiceDisconnected() {
/* call startConnection() again before the next request */
}
})
Read the callback contract literally. OK means the connection succeeded and you may proceed. FEATURE_NOT_SUPPORTED means the API is not available on that device's Play Store app — an old or non-standard store build, not a bug in your code. SERVICE_UNAVAILABLE means the connection could not be established at all, which is a timing problem, not a verdict.
Disconnection is expected rather than exceptional: Google's own note is that the client may lose the connection if the Play Store service is updating in the background, and that the client must call startConnection() again to restart it before further requests. So the listener is not a one-shot; treat it as a state machine you drive.
Step 4 — Read the referrer details
Once connected, getInstallReferrer() is a synchronized call that returns a ReferrerDetails object. The fields map one-to-one to the payload listed in Step 1:
val response: ReferrerDetails = referrerClient.installReferrer
val referrerUrl: String = response.installReferrer
val referrerClickTime: Long = response.referrerClickTimestampSeconds
val appInstallTime: Long = response.installBeginTimestampSeconds
val instantExperienceLaunched: Boolean = response.googlePlayInstantParam
Two of these are more useful than they look. referrerClickTimestampSeconds and installBeginTimestampSeconds let you compute the click-to-install delta per campaign — a slow delta usually means the store page, not the ad, lost the user. googlePlayInstantParam tells you whether the install came out of an instant experience in the past 7 days, which is the only instant-attribution signal in the response.
Step 5 — Respect the 90-day window and call it once
This is the sentence that costs teams their historical data: the install referrer information will be available for 90 days and won't change unless the application is reinstalled. Google's guidance that follows is equally direct — to avoid unnecessary API calls, invoke the API only once during the first execution after install.
The 90 days is not a storage licence. It is the window in which the value is still retrievable from Play, so an app that only reads it lazily, on some later session, has a hard deadline. Read it on the first run after install and persist it. Because it does not change unless the app is reinstalled, a refresh loop buys you nothing and only adds calls.
Close the connection when you are done: call endConnection() on the client. Google's reason is explicit — closing the connection avoids leaks and performance problems on the device.
Step 6 — Branch on the response code, do not retry blindly
A first-launch attribution read sits on the critical path of the user's first experience, so the failure policy matters as much as the code. A workable mapping:
- OK — read, persist,
endConnection(). Do not re-read on later launches. - SERVICE_UNAVAILABLE — treat as "not now". Store nothing, do not block the first screen, and retry on a later launch inside the 90-day window.
- FEATURE_NOT_SUPPORTED — the API is not there on this device. Fall back to whatever campaign identifier your own link carries, and record that the read was unsupported so your reporting does not silently count it as organic.
- Disconnected — restart with
startConnection()before the next request; do not assume the client is still alive.
One engineering rule sits above all four: never let attribution block first-run UX, and never let a failed read write a false "organic" attribution row. The difference between "no data" and "organic" is exactly where install reports stop reconciling.
Step 7 — Treat the referrer string as untrusted input
The client library returns the referrer value as a string. It is delivered by the platform, but it is still a value that originated outside your app, so the ordinary hygiene for external input applies: parse it into key-value pairs defensively, cap its length, and never interpolate it into a URL, a deep-link route or a database query unvalidated.
In practice that means: decode the value, split on the documented separators, whitelist the campaign keys you actually recognise, and drop everything else. Then reconcile against your own server-side event before it becomes a billing or revenue input. Attribution data decides which channel gets budget — an unvalidated string should not be able to move money.
If the referrer string is forwarded to ad networks or an MMP, check that your Play Data safety declaration and privacy policy already cover that sharing before the pipeline ships, not after an audit. Attribution plumbing is data collection; the declaration has to describe it.
Step 8 — Write down what the API does not tell you
Most attribution disputes come from expecting the wrong thing from a correct response. From the two reference pages, the honest limits are:
- Devices below Play Store 8.3.73 simply do not have the API — plan the fallback, because
FEATURE_NOT_SUPPORTEDis a real outcome, not an error to log and forget. - The value is fixed at first install and does not change unless the app is reinstalled — so it cannot express a re-engagement, an upgrade or a later campaign touch.
- Retrievability ends after 90 days — anything you did not persist in that window is gone.
- The instant-experience flag covers a 7-day lookback only.
- It is a device-and-account-level signal for installs from Play; it is not a user identity and it will not deduplicate installs across devices.
Put those five limits in the same document as your attribution schema. When a campaign report and a revenue report disagree, the disagreement is usually one of these five statements, not a bug in the client.
Sources: Android Developers — Google Play Install Referrer API (developer.android.com/google/play/installreferrer): payload fields, Play Store 8.3.73+ requirement, AIDL interface, Play Console account requirement. Android Developers — Play Install Referrer Library (developer.android.com/google/play/installreferrer/library, page last updated 2026-10-23): dependency version 2.2, connection flow and response codes, getInstallReferrer() and ReferrerDetails fields, the 90-day availability note, the once-per-install recommendation, and endConnection(). Both checked on 2026-10-27. Google does not publish per-campaign attribution rates or store-side latency figures; none are inferred here.
Running developer accounts at scale? We handle the operational side.
We received your message and will reply within 24 hours.
← Back to edit