Handling Deep Links

Handle Superwall deep links for paywall previews and web checkout redemption.

Beta

The KMP SDK is in beta and its API may change between releases.

Superwall uses deep links for two things: previewing paywalls on a real device, and redeeming web checkout codes. Both flow through one call.

Pass the URL to Superwall

val handled = Superwall.handleDeepLink(url)

It returns whether the SDK recognized and handled the link, so you can fall through to your own routing when it did not:

fun onDeepLink(url: String) {
    if (Superwall.handleDeepLink(url)) return
    myRouter.navigate(url)
}

handleDeepLink is guard-exempt, so you can call it before Superwall.configure without hitting SuperwallError.NotConfigured. That is deliberate: cold-starting from a deep link is its primary use, and it would be useless if you had to sequence it behind configuration.

It takes a String, not a platform URL type, so it is callable from commonMain.

Wiring it up per platform

The SDK takes a plain String, so the only platform-specific part is getting the URL from the OS to your shared code.

Android, from the activity that receives the intent:

// androidMain
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    intent?.data?.let { Superwall.handleDeepLink(it.toString()) }
}

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    intent.data?.let { Superwall.handleDeepLink(it.toString()) }
}

Declare your intent filter in AndroidManifest.xml as you would for any deep link.

iOS, from your App or AppDelegate:

// SwiftUI
.onOpenURL { url in
    Superwall.shared.handleDeepLink(url: url.absoluteString)
}

Register your URL scheme with the OS as usual: an intent-filter on Android, a URL type in your Xcode target on iOS. Superwall does not do that part for you.

Web checkout redemption

When a user buys on the web and returns to your app, the redemption arrives as a deep link. Observe the outcome through the delegate:

import com.superwall.sdk.kmp.models.redemption.RedemptionResult

class MyDelegate : SuperwallDelegate {
    override fun willRedeemLink() {
        showSpinner()
    }

    override fun didRedeemLink(result: RedemptionResult) {
        hideSpinner()
        when (result) {
            is RedemptionResult.Success -> unlock(result.redemptionInfo)
            is RedemptionResult.Error -> showError(result.error)
            is RedemptionResult.ExpiredCode -> showExpired(result.info)
            is RedemptionResult.InvalidCode -> showInvalid()
            is RedemptionResult.ExpiredSubscription -> showExpiredSubscription()
        }
    }
}

Every case carries the code that was redeemed.

willRedeemLink and didRedeemLink are analytics hooks: they arrive on a background thread on Android. The spinner calls above need a main-thread hop on Android. See Platform differences.

SuperwallDelegate.handleSuperwallDeepLink reports links of the form yoursubdomain.superwall.app/app-link/..., broken into path components and query parameters:

override fun handleSuperwallDeepLink(
    fullURL: String,
    pathComponents: List<String>,
    queryParameters: Map<String, String>,
) {
    // Route based on pathComponents
}

This hook is iOS only. superwall-android has no equivalent delegate method, so it is never invoked on Android.

Superwall.handleDeepLink(url) itself works on both platforms. Only this structured callback is missing. On Android, parse the URL yourself in the activity that receives it.

Paywall previews

Deep links are also how you preview a paywall on a real device from the dashboard. Point the link at your app and pass it to handleDeepLink.

On Android, previews need the SDK's debug activities declared in your own manifest. The KMP library declares the paywall activity but not the debug ones. See Platform differences for the snippet. This path is not yet verified end-to-end on KMP.

How is this guide?

On this page