Appearance
Amplitude
Send acquisition properties to Amplitude, including events before signup
Choose your setup based on which events need campaign attribution:
- Events after signup: configure the automatic integration below. Linkrunner sends attribution properties asynchronously after you call
signup. - Install, first-open, or pre-login onboarding events: also send attribution from your app, before tracking the events you want to segment by campaign.
Amplitude does not add newly received user properties to earlier events. A user profile can show the correct campaign while an earlier event still shows (none) when grouped by that property. This applies to user properties as well as event properties. Awaiting Linkrunner signup does not guarantee that the Amplitude update has finished.
How attribution properties work
The automatic integration sends these user properties through Amplitude's Identify API using $setOnce:
lr_campaign: the Linkrunner campaign identifier, such asAXb1c2, rather than the campaign name.lr_ad_network: the ad network source, when available.
$setOnce preserves an existing value. It does not overwrite it on subsequent updates.
If Amplitude receives Onboarding Viewed, then the attribution update, then Purchase, only Purchase inherits the new campaign properties. The order Amplitude receives the requests matters. See Amplitude's Identify API and ingestion ordering.
Configure the automatic integration
Start with the Linkrunner and Amplitude SDKs installed and initialized in your app. Use the API key for the Amplitude project that receives your app's events.
1. Add your Amplitude API key
- In Amplitude, open Settings → Projects → API Keys and copy your project's API Key.
- In the Linkrunner dashboard, open Integrations → Amplitude → Configure and enter the key.
2. Match the user IDs at signup or login
When your app knows the authenticated user ID, set it in Amplitude with setUserId and pass the same value to Linkrunner signup. Amplitude identify updates user properties; it does not replace setUserId.
These fragments belong in your signup/login handler, after both SDKs are initialized. userId is your stable authenticated account ID.
kotlin
import com.amplitude.android.Amplitude
import io.linkrunner.sdk.LinkRunner
import io.linkrunner.sdk.models.request.UserDataRequest
suspend fun identifyAccount(amplitude: Amplitude, userId: String) {
amplitude.setUserId(userId)
LinkRunner.getInstance().signup(
userData = UserDataRequest(id = userId)
).getOrThrow()
}For this setup, omit amplitudeDeviceId / amplitude_device_id. The current automatic integration uses that override as an Amplitude user_id, not a device_id. Passing Amplitude's generated device ID there can update a different profile. For anonymous users, use the app-side setup below.
Do not assign a temporary user ID to anonymous Amplitude users. Keep their existing Amplitude device identity and set the real user ID when they authenticate. Identity merging connects their activity, but does not add missing campaign properties to earlier events. See Amplitude's identity rules.
Send attribution before login
Use this setup when campaign reporting or onboarding decisions depend on events before signup. Amplitude can set user properties on its current anonymous device without an authenticated user ID.
- Initialize both SDKs using the same Amplitude instance and project as your event tracking.
- Call
getAttributionData()from your app's startup analytics code. - If a paid campaign is available, queue an Amplitude Identify with its properties.
- Track your first onboarding event after that Identify operation. Continue calling Linkrunner
signupwhen the user authenticates.
Amplitude's automatic lifecycle or session tracking can emit events during initialization. Configure that tracking before initialization if those events must carry campaign properties, or use a manual onboarding event after the attribution step. The code below does not repair events already emitted by automatic tracking.
Apply the available campaign
These helper fragments assume both SDKs are initialized. Add the helper to your startup analytics module and call it before your first manual Amplitude event. They write user properties for an available INORGANIC campaign only; they leave missing or organic values unset.
true means the SDK accepted the local Identify operation, not that Amplitude has received it. false means no campaign properties were queued. Handle that result using the fallback guidance.
kotlin
import com.amplitude.android.Amplitude
import com.amplitude.core.events.Identify
import io.linkrunner.sdk.LinkRunner
suspend fun applyLinkrunnerAttribution(amplitude: Amplitude): Boolean {
val attribution = LinkRunner.getInstance()
.getAttributionData().getOrNull() ?: return false
val campaign = attribution.campaignData
if (campaign.type != "INORGANIC" || campaign.id.isBlank()) return false
val identify = Identify().setOnce("lr_campaign", campaign.id)
campaign.adNetwork?.takeIf { it.isNotBlank() }?.let {
identify.setOnce("lr_ad_network", it)
}
amplitude.identify(identify)
return true
}From your startup coroutine, call applyLinkrunnerAttribution(amplitude) before amplitude.track("Onboarding Viewed").
Use Amplitude's Android Kotlin, iOS Swift, React Native, or Flutter 4 SDK. Older Amplitude SDKs use different APIs.
For additional properties, map available SDK fields such as campaignData.name to your own user property, for example acquisition_campaign_name. The automatic integration does not send the campaign name. Fetching attribution alone does not navigate the user; your app chooses its onboarding route.
Handle attribution that is not ready
Attribution may not be available on your first request, including when an ad network such as Google has not returned its attribution result yet. Fetching attribution once does not guarantee campaign coverage for every first-open event.
- Choose a bounded wait or retry policy for your app. Do not block onboarding indefinitely.
- On timeout, failure, or no available paid campaign, continue with your fallback onboarding flow. Events sent at this point may have no campaign properties.
- Fetch attribution again at an appropriate later point and apply newly available campaign properties before subsequent events. Do not replay the onboarding event solely to attach attribution.
- Do not set
lr_campaignorlr_ad_networkto permanent placeholders such asunknownororganicusingsetOnce. Those values prevent latersetOncecalls from filling in the campaign.
The helper intentionally does not set an organic label. Use Linkrunner's attribution result to understand acquisition source; missing Amplitude properties alone do not establish that a user is organic. If your app needs to record an unresolved routing decision, use a separate app-defined diagnostic property.
Verify event-level attribution
Use a test account and a campaign test install. Check both the profile and the individual events:
- Open the app before logging in. With the app-side setup and available attribution, inspect the first manually tracked onboarding event in Amplitude. Its user properties should contain the expected
lr_campaignand availablelr_ad_network. - Sign up or log in. Confirm the subsequent event uses the intended account identity and retains the campaign properties.
- Group the onboarding event by
lr_campaignin a chart. Do not use a populated profile alone as proof that the earlier event has the properties. - Test the failure or delayed-attribution path. Confirm onboarding continues, early events can remain unclassified, and later events reflect attribution once available.
For the automatic-only setup, events received before the server-side Identify can lack the campaign properties, including the signup event itself. A later event after the update should reflect them.
Troubleshooting
The profile has attribution, but the chart shows (none)
Inspect the user properties on the specific event, then compare them with a later event on the same profile. The profile displays current properties; charts use the properties attached to each event. Properties sent after the early event do not update it.
(none) means that event has no value for the selected property. It can reflect timing, an unmatched identity, missing configuration, or an organic user. Do not treat the entire (none) bucket as organic.
To analyze earlier activity for users whose campaign is now known, create a cohort using lr_campaign with Most recently, then filter your chart by that cohort. That cohort uses the most recent active event's property value, so the user needs a later active event reflecting the attribution. This does not change historical event properties or recover attribution for users who never receive it. See Amplitude's cohort property clauses.
The properties are missing on later events too
Check that both integrations use the same Amplitude project and that the account ID passed to Linkrunner matches Amplitude's user_id. For the automatic setup, confirm signup is called and the Amplitude API key is configured. For the app-side setup, check the attribution response and whether your Identify runs before the event on the same Amplitude instance.
Does Sync with Amplitude repair earlier events?
No. Sync with Amplitude sends profile property updates for existing users. It does not rewrite historical event properties, and $setOnce does not replace properties that are already set. Use it when adding the integration for existing users, then verify a subsequent event. It is not a historical-event backfill.
Need help? Contact support@linkrunner.io.