Get started
Quickstart: your first attributed install
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
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.
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 Gonpm install @traqio/react-native @react-native-async-storage/async-storage cd ios && pod install// app/build.gradle.kts dependencies { implementation("io.khufu.traqio:traqio-android:0.1.0") }// Package.swift .package(url: "https://github.com/khufuio/traqio-ios", from: "0.1.0")flutter pub add traqioInitialize it once at launch#
Call
initas early as possible in your app's startup, with your SDK key and the endpointhttps://api.traqio.app— the origin only, no path.// 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, });// 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, });class App : Application() { override fun onCreate() { super.onCreate() Traqio.init(this, sdkKey = "YOUR_SDK_KEY", endpoint = "https://api.traqio.app") } }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) } } } }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.
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 installand 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.// 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 });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 });Traqio.setUserId(user.id) // after sign-in — same id as RevenueCat's app_user_id Traqio.track("signup") Traqio.track("purchase", 9.99, "EUR")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")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: subscription renewals and refunds then reach the right install without an app release.
Next#
- Connect Meta and TikTok to read spend and see ROAS per campaign.
- On iOS, publish a conversion-value mapping before your first campaign — without one, SKAdNetwork postbacks carry nothing to decode.
- Read 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.