Skip to main content
device_data is the object you send on init, attribution-data, and signup. It carries the signals Linkrunner uses to match an install to a click. Most fields are simple lookups. Three need Google Play libraries and do the heavy lifting for attribution. The full client collects all of these for you. This page explains each one so you can trust, trim, or rebuild that collection.

Dependencies

dependencies {
    // Advertising ID (GAID)
    implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
    // App Set ID
    implementation 'com.google.android.gms:play-services-appset:16.0.2'
    // Google Play Install Referrer
    implementation 'com.android.installreferrer:installreferrer:2.2'
}
Going SDK-less does not remove these libraries. They are how Android exposes the advertising ID and the install referrer, so you need them no matter how you call Linkrunner.

Permissions and queries

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />

<!-- Lets you see the Meta apps for the Meta install referrer (Android 11+) -->
<queries>
    <package android:name="com.facebook.katana" />
    <package android:name="com.instagram.android" />
    <package android:name="com.facebook.lite" />
</queries>

What to send

FieldSource on AndroidImportance
gaidAdvertisingIdClientHigh. Google Ads and device matching.
install_ref (and related)Play Install ReferrerHigh. Carries gclid, fbclid, utm_*, Meta referrer.
meta_install_refMeta content providerHigh for Meta ads.
device_idSettings.Secure.ANDROID_IDRecommended. Matching fallback.
device_ipNetwork interfacesRecommended. IP matching fallback.
user_agentWebSettings.getDefaultUserAgentRecommended. Fingerprint matching.
app_version, build_number, bundle_id, application_namePackageManagerRecommended.
manufacturer, brand, device_name, system_versionBuildRecommended.
connectivity, carrierSystem servicesOptional.
appsetid, appsetid_scopeAppSetOptional.
If you send only the basics and skip gaid, install_ref, and meta_install_ref, install registration still works, but paid attribution for Google and Meta will be weak or missing.

Advertising ID (GAID)

The Google Advertising ID is the primary signal for Google Ads and device matching. Read it off the main thread.
fun gaid(context: Context): String? = try {
    val info = AdvertisingIdClient.getAdvertisingIdInfo(context)
    if (info.isLimitAdTrackingEnabled) null else info.id
} catch (e: Exception) { null }
It returns null when the user has limited ad tracking. If your app targets children, do not collect the GAID and remove the AD_ID permission. See the SDK guidance on AAID.

Google Play Install Referrer

The install referrer is the single most valuable attribution signal on Android. It carries the gclid, fbclid, utm_* parameters, and the Meta encrypted referrer from the Play Store click that led to the install.
suspend fun installReferrer(context: Context): JSONObject? = withContext(Dispatchers.IO) {
    suspendCancellableCoroutine { cont ->
        val client = InstallReferrerClient.newBuilder(context).build()
        client.startConnection(object : InstallReferrerStateListener {
            override fun onInstallReferrerSetupFinished(code: Int) {
                try {
                    if (code == InstallReferrerClient.InstallReferrerResponse.OK) {
                        val r = client.installReferrer
                        cont.resume(JSONObject().apply {
                            put("install_ref", r.installReferrer ?: "")
                            put("install_ref_install_version", r.installVersion ?: "")
                            put("install_ref_installBeginTimestampSeconds", r.installBeginTimestampSeconds)
                            put("install_ref_referrerClickTimestampSeconds", r.referrerClickTimestampSeconds)
                            put("install_ref_googlePlayInstantParam", r.googlePlayInstantParam)
                        })
                    } else cont.resume(null)
                } catch (e: Exception) {
                    cont.resume(null)
                } finally {
                    runCatching { client.endConnection() }
                }
            }
            override fun onInstallReferrerServiceDisconnected() {
                if (cont.isActive) cont.resume(null)
            }
        })
        cont.invokeOnCancellation { runCatching { client.endConnection() } }
    }
}
The install referrer is available right after install. Read it once on first launch, send it with init, and cache it. The Play Store keeps it only briefly, so do not delay the first read.

Meta Install Referrer

For Meta (Facebook and Instagram) attribution, query the Meta install referrer from the installed Meta app. It needs your Facebook App ID in the manifest and the <queries> block above.
<application>
    <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="fb1234567890" />
    <!-- If you do not use the Facebook SDK, use this key instead: -->
    <!-- <meta-data android:name="com.linkrunner.FacebookApplicationId" android:value="1234567890" /> -->
</application>
fun metaInstallReferrer(context: Context): JSONObject? {
    val appId = facebookAppId(context) ?: return null
    val providers = listOf(
        "com.facebook.katana.provider.InstallReferrerProvider" to "facebook",
        "com.instagram.contentprovider.InstallReferrerProvider" to "instagram",
        "com.facebook.lite.provider.InstallReferrerProvider" to "facebook_lite",
    )
    for ((authority, source) in providers) {
        if (context.packageManager.resolveContentProvider(authority, 0) == null) continue
        val uri = Uri.parse("content://$authority/$appId")
        context.contentResolver.query(
            uri, arrayOf("install_referrer", "is_ct", "actual_timestamp"), null, null, null
        )?.use { c ->
            if (c.moveToFirst()) {
                val refIdx = c.getColumnIndex("install_referrer")
                val ref = if (refIdx >= 0) c.getString(refIdx) else null
                if (!ref.isNullOrEmpty()) return JSONObject().apply {
                    put("install_referrer", ref)
                    put("source", source)
                    c.getColumnIndex("is_ct").let { if (it >= 0) put("is_ct", c.getInt(it)) }
                    c.getColumnIndex("actual_timestamp").let { if (it >= 0) put("actual_timestamp", c.getLong(it)) }
                }
            }
        }
    }
    return null
}

fun facebookAppId(context: Context): String? = try {
    val meta = context.packageManager
        .getApplicationInfo(context.packageName, PackageManager.GET_META_DATA).metaData
    meta?.getString("com.facebook.sdk.ApplicationId")
        ?: meta?.getString("com.linkrunner.FacebookApplicationId")
} catch (e: Exception) { null }
See Meta Install Referrer for how Linkrunner uses this signal.

Everything else

These are plain system lookups. The full client includes them.
  • device_id: Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
  • device_ip: first non-loopback IPv4 from NetworkInterface.getNetworkInterfaces()
  • user_agent: WebSettings.getDefaultUserAgent(context)
  • manufacturer, brand, device_name, system_version: Build.MANUFACTURER, Build.BRAND, Build.MODEL, Build.VERSION.RELEASE
  • App info: PackageManager.getPackageInfo for app_version and build_number, context.packageName for bundle_id
Need help? Contact support@linkrunner.io