# Quickstart: your first attributed install

URL: https://traqio.app/docs/quickstart
Last updated: 2026-10-14

From an empty account to an install attributed to its ad in about 30 minutes: create the app, add the SDK, make a tracking link, install through it.

This guide takes an app from nothing to a first install that Traqio attributes to an ad. It uses Android for the attributed install, because Android is the platform where attribution can be proven on the spot: the Google Play Install Referrer carries Traqio's click id from the ad to the app. Everything except the last check works the same on iOS.

> **Early access** Expo and React Native install from npm with the commands below. The Android, iOS and Flutter packages are not on their public registries yet: write to hello@traqio.app to receive the build for your platform; each SDK page says how to add it to the project until the registry command works.

## Steps

### Create your app in the console

Sign up at traqio.app — free, no card. The console opens on **Add your app**: give it a name, then its **bundle id** (App Store), its **package name** (Google Play), or both. One app in Traqio covers both stores; reports combine them and can split them.

The bundle id and the package name are what installs are matched against, so they must be exactly the ones your store listings use.

### Copy the SDK key

Once the app exists, the console shows its **SDK key** (later: your product → Integrations → SDK). The key is public by design — it ships inside your app and identifies it, nothing more.

### Install the SDK

Pick your platform. The other SDKs — Capacitor, Kotlin Multiplatform, .NET MAUI, Unity — have the same three steps on their own pages, listed in the [SDK overview](https://traqio.app/docs/sdks).

Expo:
```bash
npx expo install @traqio/expo @react-native-async-storage/async-storage
npx expo prebuild --clean
npx expo run:android   # or: npx expo run:ios — a development build, not Expo Go
```

React Native:
```bash
npm install @traqio/react-native @react-native-async-storage/async-storage
cd ios && pod install
```

Android:
```kotlin
// app/build.gradle.kts
dependencies {
    implementation("io.khufu.traqio:traqio-android:0.1.0")
}
```

iOS:
```swift
// Package.swift
.package(url: "https://github.com/khufuio/traqio-ios", from: "0.1.0")
```

Flutter:
```bash
flutter pub add traqio
```

### Initialize it once at launch

Call `init` as early as possible in your app's startup, with your SDK key and the endpoint `https://api.traqio.app` — the origin only, no path.

Expo:
```ts
// app/_layout.tsx — once, at module level, before the first screen renders
import { Traqio, getNativeBridge } from "@traqio/expo";
import Constants from "expo-constants";

Traqio.init({
  sdkKey: "YOUR_SDK_KEY",
  endpoint: "https://api.traqio.app",
  native: getNativeBridge(), // Install Referrer on Android, SKAdNetwork + Apple Ads on iOS
  appVersion: Constants.expoConfig?.version,
});
```

React Native:
```ts
// index.js — before AppRegistry.registerComponent
import { Traqio, getNativeBridge } from "@traqio/react-native";
import { version } from "./package.json";

Traqio.init({
  sdkKey: "YOUR_SDK_KEY",
  endpoint: "https://api.traqio.app",
  native: getNativeBridge(),
  appVersion: version,
});
```

Android:
```kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Traqio.init(this, sdkKey = "YOUR_SDK_KEY", endpoint = "https://api.traqio.app")
    }
}
```

iOS:
```swift
import SwiftUI
import TraqioSDK

@main
struct MyApp: App {
    init() {
        Traqio.start(sdkKey: "YOUR_SDK_KEY", endpoint: "https://api.traqio.app")
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { Traqio.handleUrl($0) }
                .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { Traqio.handleUserActivity($0) }
        }
    }
}
```

Flutter:
```dart
import 'package:flutter/widgets.dart';
import 'package:traqio/traqio.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Traqio.init(sdkKey: 'YOUR_SDK_KEY', endpoint: 'https://api.traqio.app');
  runApp(const MyApp());
}
```

> **The endpoint must be exactly this** The SDK swallows network errors by design (it queues and retries), so a mistyped host produces no error anywhere: the app looks healthy and the console stays empty. If nothing arrives in the next step, check the endpoint first.

### See the first signal arrive

Run the app once on a device or an emulator. In the console, open your app → **Integrations → Live events**: the install appears within seconds, exactly as it was received. A development build reports its install as **organic** — that is expected, there was no ad.

Nothing after a minute? The setup screen's **It's not arriving** panel says whether any request reached Traqio for this key, and the **Send a test event** button proves the pipe from the console side. Test events are never billed and never appear in reports.

### Create a tracking link

Open **Links → New link**. Give it a label (“Meta / launch / video A”), the network, and the network's own campaign id — and, if you know them, the ad set and ad ids. Those ids are what joins a click to the spend the network reports. Copy the link's **click URL**; it looks like `https://api.traqio.app/c/launch`, or uses your own domain once you have set one up.

The click URL is what goes in the ad's destination. How links resolve, the impression URL, templates and QR codes are in [Tracking links](https://traqio.app/docs/concepts/tracking-links).

### Install through the link

On an Android phone signed into a Google account that can see your app on Google Play (a production listing, or an internal or closed testing track), uninstall the app, tap the click URL, install from the Play Store and open the app.

In Live events, a **Click** row appears first, then an **Install** marked **Deterministic**, with the link's network and campaign. That install is now counted in the campaign's reports and, once spend is connected, in its ROAS.

> **Why not a debug build?** The Install Referrer is written by the Play Store, so only an install the Play Store performed after the click carries it. adb install and IDE runs never do, and show as organic.

### Track a revenue event

Track the events your campaigns should optimise on, with the names Traqio maps onto each network's standard events (`purchase`, `signup`, `subscribe`…). A purchase carries its value, its currency and — on the SDKs that accept it — the store's transaction id, so the same purchase reported by RevenueCat is counted once.

Expo:
```ts
// after sign-in — the SAME id you give RevenueCat (Purchases.logIn)
Traqio.setUserId(user.id);

Traqio.track("signup");

Traqio.track("purchase", {
  value: 9.99,
  currency: "EUR",
  transactionId: purchase.transactionId, // the store's id: StoreKit transactionId, Play orderId
});
```

React Native:
```ts
Traqio.setUserId(user.id); // after sign-in — same id as RevenueCat's app_user_id

Traqio.track("purchase", { value: 9.99, currency: "EUR", transactionId: purchase.transactionId });
```

Android:
```kotlin
Traqio.setUserId(user.id)                 // after sign-in — same id as RevenueCat's app_user_id
Traqio.track("signup")
Traqio.track("purchase", 9.99, "EUR")
```

iOS:
```swift
Traqio.setUserId(user.id)   // after sign-in — same id as RevenueCat's app_user_id
Traqio.track("signup")
Traqio.track("purchase", value: 9.99, currency: "EUR")
```

Flutter:
```dart
Traqio.setUserId(user.id); // after sign-in — same id as RevenueCat's app_user_id
Traqio.track('signup');
Traqio.track('purchase', value: 9.99, currency: 'EUR');
```

Set the **same user id** on Traqio and on RevenueCat, and connect the [RevenueCat webhook](https://traqio.app/docs/integrations/revenuecat): subscription renewals and refunds then reach the right install without an app release.

## Next

- [Connect Meta](https://traqio.app/docs/integrations/meta) and [TikTok](https://traqio.app/docs/integrations/tiktok) to read spend and see ROAS per campaign.
- On iOS, publish a [conversion-value mapping](https://traqio.app/docs/concepts/ios-attribution#mapping) before your first campaign — without one, SKAdNetwork postbacks carry nothing to decode.
- Read [Events and revenue](https://traqio.app/docs/concepts/events-and-revenue) before you name your events: an off-vocabulary name is stored and reported, but optimises nothing on Meta or TikTok.

## Frequently asked questions

**Why does my test install show as organic?**
On Android the attribution travels in the Google Play Install Referrer, which only exists for installs made through the Play Store after a click on your Traqio link. An APK installed with adb, a build run from the IDE or an install that did not follow a click has no referrer, so the install is reported as organic. Test with a build from a Play testing track.

**Can I test iOS attribution the same way?**
Not instantly. Apart from Apple Ads, iOS attribution comes from SKAdNetwork postbacks that Apple sends at least 24 hours after the conversion window closes, aggregated per campaign and withheld below Apple's privacy thresholds. The SDK side can be verified at once — the install appears in Live events — but the attribution itself arrives later.

**Is the SDK key a secret?**
No. The SDK key identifies the app and ships inside it, where anyone can read it. The secret credentials — the RevenueCat webhook header and API keys — are different values that never go into the app.
