Quickstart
Create a working Forwarded flow — from link creation to session claim — in under 30 minutes.
1. Create a workspace and register your app
Go to the dashboard and create a workspace. A workspace scopes your Forwarded Links, sessions, API keys, apps, and webhooks. Choose a slug for your workspace — it becomes the subdomain of your public links (e.g. acme.forwarded.link).
Navigate to Apps and register your iOS or Android app. For iOS: provide the App Store ID (numeric), bundle identifier (e.g. com.example.myapp), and the URL scheme you'll register in your Info.plist. For Android: provide the package name (e.g. com.example.myapp) from your build.gradle.
The App ID returned by registration (app_01JABCDEF) is used when configuring the SDK. Keep it alongside your API key — both are shown in the dashboard.
2. Create a Forwarded Link
Navigate to Forwarded Links and click Create. Choose your registered app. Add a slug (e.g. welcome-offer or refer-a-friend). The public URL will be workspace.forwarded.link/slug.
Attach a JSON payload — the context you want to receive in your app. Keep it under 8KB. Do not include secrets, passwords, payment data, or PHI. Include only the identifiers your app needs to route its UI.
Configure the landing page title, description, and call-to-action text. The Forwarded-hosted page is what mobile users see before tapping the Smart App Banner or following the Play Store link. Publish the link.
// Example payloads by use case
{ "type": "subscription_offer", "campaign_id": "launch_2026", "offer_id": "three_months_free", "paywall_id": "partner_v1" }
{ "type": "referral", "referrer_id": "user_nhan_01", "referral_code": "NHAN50", "reward_type": "seven_day_trial" }
{ "type": "invite", "team_id": "team_acme", "invite_id": "inv_01JABCDEF", "role": "member" }
{ "type": "qr_campaign", "event_id": "nrf_2026", "booth_id": "booth_42" }3. Install the SDK
For iOS, add the Forwarded Swift package via Xcode → File → Add Package Dependencies. Use the repository URL for packages/sdk-ios. Add the Forwarded library to your app target and import it in your App entry point.
For Android, add the Forwarded Kotlin library and the Play Install Referrer client to your app module's build.gradle dependencies block.
// iOS — Package.swift (if integrating manually)
.package(url: "https://github.com/forwarded/sdk-ios", from: "0.1.0")
// Android — app/build.gradle
dependencies {
implementation 'ai.forwarded:sdk-android:0.1.0'
implementation 'com.android.installreferrer:installreferrer:2.2'
}4. Configure the SDK
Call Forwarded.configure() exactly once, before any call to resolvePending(). The best place is your @main App init() in SwiftUI, or applicationDidFinishLaunching() in AppDelegate. On Android, call it in your main Activity's onCreate().
Pass your API key (use a test key during development — fwd_test_xxx) and your App ID. In development, the SDK connects to your local server. In production it connects to api.forwarded.link.
// iOS — SwiftUI @main App
import Forwarded
@main
struct MyApp: App {
init() {
Forwarded.configure(ForwardedConfig(
apiKey: "fwd_test_xxx",
appId: "app_01JABCDEF"
))
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in Forwarded.handleOpenURL(url) }
}
}
}
// Android — MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Forwarded.configure(this, ForwardedConfig(
apiKey = "fwd_test_xxx",
appId = "app_01JABCDEF"
))
Forwarded.handleIntent(intent)
Forwarded.fetchInstallReferrer(this)
}5. Resolve and claim
On first app launch, call resolvePending() after configure(). The SDK reads any pending session token from the install referrer, app-argument, or incoming URL, validates it with the Forwarded API, and returns the payload. The call returns null if no pending session exists — handle this gracefully.
After the user creates an account or logs in, call claim() with their user ID. This permanently binds the resolved session to that user. Use an idempotency key based on the user ID to make retries safe.
// iOS (Swift)
let session = await Forwarded.resolvePending()
if let payload = session?.payload {
if let paywallId = payload["paywall_id"] as? String {
router.navigate(.partnerPaywall(id: paywallId))
}
}
// After login or signup:
try await Forwarded.claim(
externalUserId: currentUser.id,
idempotencyKey: "claim-\(currentUser.id)"
)
// Android (Kotlin)
lifecycleScope.launch {
val session = Forwarded.resolvePending()
session?.payload?.let { payload ->
val paywallId = payload["paywall_id"] as? String
if (paywallId != null) showPaywall(paywallId)
}
// After login:
Forwarded.claim(
externalUserId = currentUser.id,
idempotencyKey = "claim-${currentUser.id}"
)
}6. Inspect in the dashboard
Open the Forwarded dashboard and navigate to Sessions. Sessions appear in real time as they are created, opened, resolved, and claimed. Each session shows the platform (iOS / Android), the forwarding mechanism, the determinism tier, the full payload, and the complete event timeline.
Use this view to verify your integration is working before shipping. The mechanism field tells you exactly how context arrived. If a session is stuck in CREATED and never moves to OPENED, the user likely did not tap the Smart App Banner or the referrer was not delivered.