Skip to main content
Version: 1.1.x

SDK Usage

Use DetourDelegate in Activity lifecycle

DetourDelegate is the recommended integration for classic Android apps. It wraps coroutine calls to Detour.processLink(...) and returns LinkResult in a callback.

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.swmansion.detour.Detour
import com.swmansion.detour.DetourConfig
import com.swmansion.detour.DetourDelegate
import com.swmansion.detour.models.LinkProcessingMode
import com.swmansion.detour.models.LinkResult

class MainActivity : AppCompatActivity() {
private val detourDelegate = DetourDelegate(
lifecycleOwner = this,
config = DetourConfig(
apiKey = BuildConfig.DETOUR_API_KEY,
appId = BuildConfig.DETOUR_APP_ID,
linkProcessingMode = LinkProcessingMode.ALL,
),
onLinkResult = { result -> handleLinkResult(result) }
)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Detour.initialize(this, detourDelegate.config)
detourDelegate.onCreate(intent)
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
detourDelegate.onNewIntent(intent)
}

private fun handleLinkResult(result: LinkResult) {
// handle result and navigate
}
}

If you want complete, runnable integrations for each navigation style, go to Examples.

LinkResult handling

processLink() / getDeferredLink() return one of:

  • LinkResult.Success: contains url, route, pathname, params, type
  • LinkResult.NotFirstLaunch: deferred flow already consumed in this install/session
  • LinkResult.NoLink: no matching link
  • LinkResult.Error: runtime/integration error

Typical routing pattern:

when (result) {
is LinkResult.Success -> navigateToRoute(result.route, result.params)
is LinkResult.NotFirstLaunch -> Unit
is LinkResult.NoLink -> Unit
is LinkResult.Error -> Log.e("Detour", "Link error", result.exception)
}

Choose linkProcessingMode

DetourConfig.linkProcessingMode controls which link sources are handled:

ValueDeferredApp Links (http/https)Custom scheme
ALL (default)YesYesYes
WEB_ONLYYesYesNo
DEFERRED_ONLYYesNoNo

Use DEFERRED_ONLY when your navigation stack already handles app-link/scheme intents and Detour should only resolve first-install deferred links.

Click limits

When an App Link or Universal Link is processed, the SDK verifies the click against your plan's click limit before delivering the resolved link. While your app is within the limit, links resolve normally. When the limit is exceeded, the link is not delivered — processLink() (and the DetourDelegate callback) returns LinkResult.NoLink.

In that case the SDK logs a [Detour:CLICK_LIMIT_ERROR] message with the limit details (clicksInPeriod, effectiveLimit).

This dedicated [Detour:CLICK_LIMIT_ERROR] flow applies only to App/Universal links. Deferred-link matching and short-link resolution are subject to the same plan limits on the backend, but the SDK does not surface a dedicated limit error for them — when the limit is exceeded the affected link simply fails to resolve (getDeferredLink() returns NoLink, resolveShortLink() returns null) instead of logging a click-limit error. Custom scheme links are handled locally and are not limit-checked.

For the actual per-plan click limits, pay-as-you-go overage, and how to raise them, see Billing & Payments.

Fail-open by design

If the limit check cannot complete because of a network or backend error, the SDK lets the link through so a temporary outage never breaks navigation. Limits are enforced only on an explicit "denied" response from the backend.

Deferred-only manual flow

In DEFERRED_ONLY, you can skip DetourDelegate and call Detour.getDeferredLink() directly:

Detour.initialize(
this,
DetourConfig(
apiKey = BuildConfig.DETOUR_API_KEY,
appId = BuildConfig.DETOUR_APP_ID,
linkProcessingMode = LinkProcessingMode.DEFERRED_ONLY,
)
)

lifecycleScope.launch {
when (val result = Detour.getDeferredLink()) {
is LinkResult.Success -> navigateToRoute(result.route, result.params)
else -> Unit
}
}

See the example-deferred-only app in Examples.

Analytics module

DetourAnalytics is initialized together with Detour.initialize(...).

import com.swmansion.detour.analytics.DetourAnalytics
import com.swmansion.detour.analytics.DetourEventNames

DetourAnalytics.logEvent(
DetourEventNames.Purchase,
mapOf("item" to "subscription_premium", "currency" to "USD"),
)

DetourAnalytics.logRetention("home_screen_opened")

On a cold start, Detour.initialize(...) also logs an app_open retention event once per session — you don't need to call it yourself.

Every request the SDK sends to the Detour backend carries an X-SDK: android/<version> header. It is used for diagnostics and SDK-usage analysis and requires no configuration.