Android SDK

Install and integrate the LinkTrail Android SDK — package io.linktrail, minSdk 26, on Maven Central — with configure, onLink, consent and the Install Referrer.

Binary AAR · package io.linktrail · entry point LinkTrail · minSdk 26 · artifact io.linktrail:sdk:0.0.5 on Maven Central.

Before this works, set up three things in the dashboard. Skip one and links fail silently — they open the browser instead of your app. Full flow: Quickstart.

  1. 1Register the app — Apps → Register app, with your package name and every SHA-256 signing fingerprint you ship under, including Play App Signing.
  2. 2Add a link domain — Domains. Or use your free *.linktrail.io subdomain.
  3. 3Create an API key — Settings → API Keys. That is the lt_live_… value below.

Install

The SDK is published to Maven Central, so no custom repository is needed — just add the dependency:

app/build.gradle.ktskotlin
dependencies {
    implementation("io.linktrail:sdk:0.0.5")
}

mavenCentral() is already in the default repositories of every Android project, which also resolves the SDK's transitive dependencies (coroutines, Play Install Referrer, App Set ID). Keep google() alongside it.

Nothing else to configure: the INTERNET permission merges in from the SDK's manifest, and consumer ProGuard/R8 rules are bundled in the AAR — no app-side keep rules needed.

Integrate

import io.linktrail.LinkTrail

// In Application.onCreate(). The API key is required — a blank key throws.
LinkTrail.configure(context = this, apiKey = "lt_live_...")

// One hook — fires for deferred (first-launch) AND re-engagement links:
LinkTrail.shared?.onLink { link, source ->
    router.route(link.path, link.customData)
}

LinkTrail.shared?.onError { error -> /* e.g. LinkTrailError.InvalidApiKey */ }

Consent gating is on by default (requireConsent = true) and is deny-by-default. A fresh install is held until you make a consent decision — nothing is sent until you call setConsent(true) or setConsent(false), and only then does the deferred link route: grant attributes it, deny routes it without recording. Re-engagement links (an already-installed app opening a link) route regardless of consent — that only decides whether the open is recorded. Call setConsent once your consent UI resolves:

// Grant → releases the held install as an attributed install + flushes queued events:
LinkTrail.shared?.setConsent(true)

// Deny → still releases the install to route the deep link, but records nothing; clears the queue:
LinkTrail.shared?.setConsent(false)

// To track at init with no gate, opt out:
LinkTrail.configure(context = this, apiKey = "lt_live_...",
    options = LinkTrailOptions(requireConsent = false))

Forward incoming links from your Activity — both entry points:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    LinkTrail.shared?.handleDeepLink(intent?.data)
}
override fun onNewIntent(intent: Intent) {          // app already running
    super.onNewIntent(intent)
    setIntent(intent)                               // keep getIntent() current
    LinkTrail.shared?.handleDeepLink(intent.data)
}

Every callback API also has a coroutine suspend twin (trackInstallAsync, handleDeepLinkAsync, trackEventAsync). Callbacks are delivered on the main thread.

More

// Custom + revenue events:
LinkTrail.shared?.trackEvent("purchase", value = 59.99, currency = "USD")

// Cached results:
val attribution = LinkTrail.shared?.lastAttribution
val lastLink = LinkTrail.shared?.lastDeepLink

// Attribution hook (fires when an install is attributed):
LinkTrail.shared?.onAttribution { attribution -> /* … */ }

// Defer the install call entirely (send it yourself later):
LinkTrail.configure(context = this, apiKey = "lt_live_...",
    options = LinkTrailOptions(autoTrackInstall = false))
LinkTrail.shared?.trackInstall()

Options & defaults

LinkTrailOptions fieldDefaultNotes
requireConsenttrueDeny-by-default: the deferred install is held until setConsent(true/false), then routes (grant attributes, deny routes-only); re-engagement routes regardless
autoTrackInstalltruefalse = defer the install call entirely; call trackInstall() yourself
logEnabledfalseMaster switch for SDK logging (tag: LinkTrail)
logLevelINFODEBUG · INFO · WARNING · ERROR · NONE
requestTimeoutMillis15 000Per-request network timeout
retryPolicyDEFAULT3 attempts, 500 ms base / 8 s max backoff; DISABLED turns retries off
linkDomainsempty (all hosts)Exact host or subdomain match; see warning under Deep-link setup

Errors are a sealed LinkTrailError: MissingApiKey (thrown synchronously by configure), InvalidApiKey (the backend rejected the key — arrives via onError, not from configure), NotALinkTrailUrl, InvalidUrl, Server, Transport, Decoding, EmptyResponse. Under the hood the SDK also queues failed events offline and retries them after the next successful install call, and handles the Play Install Referrer and App Set ID automatically — there's no API to call. (App Tracking Transparency / SKAdNetwork are iOS-only and have no Android equivalent.)

API surface

APIPurpose
configure(context, apiKey, options)Initialize; deferred install held until a setConsent decision, then routes (re-engagement routes regardless)
setConsent(granted)Grant or revoke the consent gate (see Consent above)
onLink { link, source }Deep link delivered (deferred + re-engagement)
onAttribution { attribution }Install attribution result
onError { error }Failures (invalid key, network…)
handleDeepLink(uri)Forward App Links / custom schemes
trackEvent(name, value, currency)Custom + revenue events
trackInstall(force)Manual install track (with autoTrackInstall = false)
lastAttribution / lastDeepLinkCached last results
trackInstallAsync / handleDeepLinkAsync / trackEventAsyncCoroutine suspend twins

Declare your App Links host (plus an optional custom scheme) in the manifest:

AndroidManifest.xmlxml
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="yourapp.linktrail.io" />
</intent-filter>

The assetlinks.json file is generated and hosted by LinkTrail — it's built from the package name + SHA-256 fingerprints you registered in the dashboard (to change fingerprints, edit the app in the dashboard, not a file). Links opening the browser or Play Store instead of your app? That's almost always App Links verification — see Troubleshooting. And if you set linkDomains, list every link host: re-engagement opens only route for listed hosts, while deferred install links still route — so the bug hides on fresh installs.

Example app: KickFlip — a Jetpack Compose storefront in example/ wired end to end. cd example && ./gradlew :app:installDebug, with your API key in example/local.properties as linktrail.apiKey=lt_live_… (without a key, the built-in deep-link simulator still works offline).