Skip to main content
Prefer to let your AI coding agent do this? Install the Linkrunner skill and Claude Code, Cursor, GitHub Copilot, or Windsurf will wire up the native bridges and deep links for you:
Then ask your agent to “integrate Linkrunner”. See Linkrunner Agent Skills.
Linkrunner does not have a dedicated Unity SDK. This guide walks you through integrating the native Android and iOS SDKs into your Unity project using platform bridge plugins.

Prerequisites

  • Unity 2021.3 LTS or newer
  • Android: Android 5.0+ (API 21), Gradle 8.0+
  • iOS: iOS 15.0+, Xcode 14.0+, Swift 5.9+
  • A Linkrunner project token — get it from Dashboard → Documentation
Important assumptions in this guide:
  1. iOS requires a Swift bridging layer. The Linkrunner iOS SDK (LinkrunnerKit) is a pure Swift module — it does not inherit from NSObject and has no @objc annotations. Since Unity’s native plugin system uses C/Objective-C, we provide a Swift wrapper file (LinkrunnerUnityBridge.swift) that exposes @_cdecl C-callable functions which internally call the Swift SDK’s async methods.
  2. Android uses a Java-friendly callback wrapper. The Linkrunner Android SDK provides LinkrunnerJava, a callback-based wrapper around the Kotlin SDK. This avoids Kotlin coroutine interop issues (Result<T> mangling, Continuation type mismatches, Kotlin version conflicts) that prevent Java callers from using the suspend-based API directly.
  3. iOS SPM dependency must be re-added each time Unity regenerates the Xcode project. See the Automation Tips section for a partial workaround.
  4. The bridge code is reference code, not a drop-in package. You may need to adjust method signatures or imports based on your Unity version, Xcode version, and SDK version updates.

Architecture Overview

The integration uses Unity’s native plugin system:
  • Android: A Java bridge class calls LinkrunnerJava (the SDK’s callback-based Java API) and communicates results back to Unity via UnitySendMessage.
  • iOS: A Swift bridge file wraps the Linkrunner iOS SDK’s async methods into C-callable functions (via @_cdecl), which Unity calls through [DllImport("__Internal")].
  • C#: A LinkrunnerSDK.cs wrapper provides a unified cross-platform API.

Android Setup

Step 1: Add the SDK Dependency

In your Unity project, create or edit the file Assets/Plugins/Android/mainTemplate.gradle (or your custom Gradle template) and add:
Make sure Maven Central is included in your repositories. In Assets/Plugins/Android/settingsTemplate.gradle:
If you’re using Unity 2022.2+ with the Gradle template system, you may need to add the dependency in unityLibrary/build.gradle instead. Check Unity’s documentation for your version.

Step 2: Permissions

Add the following to your Assets/Plugins/Android/AndroidManifest.xml:
If your app targets children and you need to disable advertising ID collection, remove the AD_ID permission:
Disabling AAID collection is not recommended unless absolutely necessary. The GAID is a primary signal for Google Ads attribution and install matching, so disabling it reduces attribution accuracy. Only disable it if your app is built for children or families and must comply with Google Play’s Family Policy.

Step 3: Create the Java Bridge

Create Assets/Plugins/Android/LinkrunnerBridge.java:
The bridge uses LinkrunnerJava, a callback-based wrapper included in the Android SDK. It handles all Kotlin coroutine execution internally — no Kotlin imports, no BuildersKt.runBlocking, and no background thread management needed in your bridge code. Callbacks are invoked on a background IO thread, which is safe for UnitySendMessage.

iOS Setup

Step 1: Add the SDK

After building your Unity project for iOS and opening the generated Xcode project:
  1. In Xcode, select FileAdd Package Dependencies…
  2. Enter the repository URL:
  3. Select the latest version (4.1.0+)
  4. Click Add Package and choose the LinkrunnerKitStatic library
You’ll need to add the SPM dependency each time you regenerate the Xcode project from Unity. Consider using a post-build script to automate this — see the Automation Tips section.

Step 2: Info.plist Configuration

Add to your Info.plist (can also be done via Unity’s Assets/Plugins/iOS/Info.plist additions):

Step 3: Create the Swift Bridge

The Linkrunner iOS SDK is a pure Swift module — it does not inherit from NSObject and has no @objc annotations, so it cannot be called directly from Objective-C. We use a Swift bridge file with @_cdecl to expose C-callable functions that Unity can invoke via [DllImport("__Internal")]. Create Assets/Plugins/iOS/LinkrunnerUnityBridge.swift:
Swift files in Unity iOS plugins: Unity does not natively compile .swift files in Assets/Plugins/iOS/. After Unity generates the Xcode project, you must manually add LinkrunnerUnityBridge.swift to the Xcode project’s UnityFramework target and ensure:
  1. The file is added to the Compile Sources build phase of the UnityFramework target
  2. A bridging header exists (Xcode usually prompts to create one when adding the first Swift file)
  3. SWIFT_VERSION is set to 5.0+ in the UnityFramework build settings
Alternatively, you can automate this with a Unity PostProcessBuild script — see the Automation Tips section.

Google Integrated Conversion Measurement (Optional)

Integrated Conversion Measurement (ICM) recovers Google App Campaign installs on iOS that Google cannot attribute because there is no click identifier and no IDFA to match on. Google’s On-Device Measurement (ODM) SDK turns the click context into an encrypted signal that never leaves the device, and Linkrunner sends it with the install. See Google ICM for how it works. Set this up if you run Google App Campaigns for your iOS app. Requires LinkrunnerKit 4.1.0 or later and io.linkrunner:android-sdk:4.1.0 or later.
Google keeps ODM inactive for users in the European Economic Area, the United Kingdom, and Switzerland, so ICM recovers nothing for that traffic. Elsewhere, Google reports improved coverage for iOS 14+ users.
ICM also needs an iOS link ID configured in your Google Ads integration. Google has nowhere to send the conversion without one. See Prerequisites.
1

Add Google's On-Device Measurement SDK (iOS)

Linkrunner does not bundle this SDK, so apps that skip ICM carry none of its weight. In the generated Xcode project, select FileAdd Package Dependencies…, enter:
Select the GoogleAdsOnDeviceConversion product and add it to the same target you added LinkrunnerKitStatic to (UnityFramework).Like the LinkrunnerKit dependency, this has to be re-added each time Unity regenerates the Xcode project. Handle it in the same post-build script.
2

Add the -ObjC linker flag

In Build SettingsOther Linker Flags on the target that links Google’s SDK (UnityFramework), add:
Without it, ICM silently does nothing and your build still succeeds. Linkrunner finds Google’s class through the Objective-C runtime, so nothing references it at link time, and the linker drops it from Google’s static library. -lc++ is applied for you by Google’s Package.swift.
3

Report consent

Call SetConsent with your consent values before Initialize, and again whenever the user changes their choice:
Each signal takes "granted", "denied", or "unknown". Anything left "unknown" is dropped from the payload rather than reported as a denial. SetConsent works on both iOS and Android, using the bridge methods added in the Java bridge and Swift bridge above.Google treats these as required whenever their value is known. hasConsentForDataUsage decides whether Google may use the conversion at all, hasConsentForAdsPersonalization decides whether it may feed audiences and remarketing, and isEEA tells Google which rules apply. Set them from your app’s real consent state rather than hardcoding them. For users outside the EEA, the UK, and Switzerland, report isEEA as denied and leave the other two unset. See Send Consent.

Verifying your setup

Initialize with debug mode on and look for this line in the Xcode console:
odm_available=false with odm_fetch_result=unavailable means Google’s SDK is not linked. Check the -ObjC flag first, because a missing flag strips the class with no build warning.

C# Wrapper

Create Assets/Scripts/LinkrunnerSDK.cs in your Unity project:

Usage

Scene Setup

  1. Create an empty GameObject in your first scene
  2. Name it LinkrunnerCallbackHandler (must match exactly)
  3. Attach the LinkrunnerSDK.cs script to it

Initialization (Required)

Call Initialize as early as possible — typically in your startup scene:
Find your project token at: Dashboard → Documentation

User Identification (Required)

Call Signup as soon as the user is identified — whether through signup or login. This is the moment Linkrunner ties the install (and any future events) to a user identifier.
Call HandleDeeplink when your app is opened via a deeplink — both cold start (app was closed) and warm start (app was in background):
Linkrunner sends the updated deeplink back after processing. For Linkrunner campaign links, use deeplink from OnDeeplinkHandled as the resolved destination instead of the original tracking URL.
The is_linkrunner field indicates whether the deeplink was created through Linkrunner. Use this to determine if you should apply Linkrunner-specific attribution logic.
For Unity deeplink handling, you’ll need to implement platform-specific code to capture the deeplink URL:
Create a custom UnityPlayerActivity to capture deeplinks:
Update your AndroidManifest.xml to use this activity and add intent filters for your deeplink scheme.

Set User Data on App Open

Call every time the app opens and the user is logged in:
SetUserData is optional and is not a replacement for Signup. Always call Signup first as soon as the user is identified (signup or login). Use SetUserData afterwards only when additional user details become available later — for example, when the user adds a phone number, email, or completes their profile after identification.

Get Attribution Data

The result arrives as a JSON string on the OnAttributionData event. With the reference bridge code in this guide, the shape differs by platform. iOS
Android

Track Events

When tracking revenue-related events, the amount field must be a number (not a string) for ad network revenue optimization to work correctly.

Capture Payment

paymentId is required and must be unique for each payment. It is used for idempotent deduplication, so retries cannot double count revenue. Payment types: FIRST_PAYMENT, SECOND_PAYMENT, WALLET_TOPUP, FUNDS_WITHDRAWAL, SUBSCRIPTION_CREATED, SUBSCRIPTION_RENEWED, ONE_TIME, RECURRING, DEFAULT Payment statuses: PAYMENT_INITIATED, PAYMENT_COMPLETED, PAYMENT_FAILED, PAYMENT_CANCELLED

Remove Payment (Refunds)

Push Token

Privacy Controls


Function Placement Guide


Automating iOS Dependency with a Post-Build Script

Since Unity regenerates the Xcode project on each build, you can automate the SPM dependency addition using a Unity Editor script: Create Assets/Editor/LinkrunnerPostBuild.cs:
Unity’s PBXProject API does not natively support adding SPM packages. After the Xcode project is generated, you will need to add the LinkrunnerKit SPM dependency manually in Xcode, or use a third-party tool like unity-spm to automate it.

Testing

  1. Enable debug mode: LinkrunnerSDK.Initialize(token, debug: true)
  2. Create a test campaign at Dashboard → Create Campaign
  3. Uninstall the app from your test device
  4. Click the campaign link on the device (opens in browser)
  5. Install and open the app build within 3 minutes
  6. Verify in the dashboard that click count, install count, and signup count increase
  7. Call GetAttributionData() to confirm attribution is returned
For detailed testing steps, see the Integration Testing Guide.

Troubleshooting

Android

  • ProGuard/R8 issues: Add to your ProGuard rules:
  • Duplicate classes: If another plugin includes Kotlin stdlib, use Gradle’s exclude to avoid conflicts.

iOS

  • Swift file not compiling: Unity does not automatically compile .swift files. After generating the Xcode project, add LinkrunnerUnityBridge.swift to the UnityFramework target’s Compile Sources build phase manually.
  • “Use of unresolved identifier ‘LinkrunnerSDK’”: The LinkrunnerKit SPM package hasn’t been added to the Xcode project. Add it via File → Add Package Dependencies.
  • Bridging header issues: When Xcode prompts to create a bridging header after adding the first Swift file, accept it. Ensure SWIFT_VERSION is set to 5.0 or higher in UnityFramework build settings.
  • Linker errors: Ensure you selected LinkrunnerKitStatic (not the dynamic variant) when adding the SPM package.
  • ATT dialog not showing: The NSUserTrackingUsageDescription key must be present in Info.plist. The SDK handles requesting permission automatically during initialization.

General

  • Callbacks not received: Verify the GameObject is named exactly LinkrunnerCallbackHandler and has the LinkrunnerSDK.cs script attached. It must exist in the scene when native code calls UnitySendMessage.
  • Editor testing: All SDK calls are no-ops in the Unity Editor and log to the console instead. Test on actual Android/iOS devices.