Traqio.

SDKs

JavaScript core and API reference

@traqio/core is the engine behind the React Native, Expo and Capacitor SDKs: its init options, methods, queue, storage and the native bridge, documented once.

@traqio/core is Traqio's platform-neutral JavaScript engine: the persisted offline queue, the batching and retries, the SKAdNetwork conversion-value driver, the Apple Ads token report and deep-link resolution. It has no React Native, Expo or browser dependency; everything platform-specific arrives through a native bridge. @traqio/react-native (and its alias @traqio/expo) and @traqio/capacitor re-export it with their bridge, so this page is the API reference of all three.

Install#

npm install @traqio/core

Only for a direct integration. On React Native, Expo or Capacitor, install the platform package instead — it depends on the core at an exact version.

API reference#

The SDK is a singleton, Traqio. Calls made while init is still resolving are queued; calls made before init is called at all are ignored — except setConsent, which is kept and written once storage is available. Initialise first.

init(options)#

import { Traqio } from "@traqio/core";

await Traqio.init({
  sdkKey: "YOUR_SDK_KEY",
  endpoint: "https://api.traqio.app", // origin only — the SDK appends the paths
  userId: currentUserId,              // optional, settable later with setUserId
  storage,                            // { getItem, setItem } — see "Storage"
  native,                             // a NativeBridge; omit and there is no attribution
});
InitOptions
interface InitOptions {
  sdkKey: string;
  endpoint: string;
  storage?: { getItem(key: string): Promise<string | null>; setItem(key: string, value: string): Promise<void> };
  native?: NativeBridge;
  userId?: string;
  appVersion?: string;
  collectContext?: boolean; // default true — model, OS, locale; never an advertising id
  testAds?: boolean;        // AdMob test ad units: logged, never counted as revenue
  skan?: boolean;           // iOS: drive SKAdNetwork conversion values (default true)
  appleAds?: boolean;       // iOS: report the AdServices token (default true)
  deepLinking?: boolean;    // default true
  consent?: boolean;        // the user's answer to YOUR consent prompt, when known at launch
  collectAdvertisingId?: boolean; // default false — send the IDFA / GAID with the install (never prompts)
}

Idempotent: a second call does nothing. On first launch it reports the install once — on Android with the Play Install Referrer, waiting up to three launches if Google Play is momentarily unavailable — then resolves the deferred deep link, records the app open, fetches the SKAdNetwork mapping and reports the Apple Ads token on iOS. endpoint is the origin only: https://api.traqio.app.

track(name, props?)#

Traqio.track("signup");
Traqio.track("purchase", {
  value: 9.99,
  currency: "EUR",
  transactionId: "2000000812345678", // the store's id for this purchase
  store: "app_store",                // defaults to the platform's store
});
PropTypeMeaning
valuenumberRevenue declared by the app — the SDK does not verify it against a receipt.
currencystringISO 4217 code.
transactionIdstringThe store's id for the purchase (StoreKit transactionId, Play orderId). Keys the event like RevenueCat does, so one purchase reported by both is counted once.
storestringapp_store · play_store · mac_app_store · amazon · stripe. Defaults to the platform's store.

On iOS every valued event also moves the SKAdNetwork conversion value. Names that Meta and TikTok can optimise on are listed in Event names.

trackAdRevenue(ad)#

// In AdMob's paid-event callback, once per impression:
Traqio.trackAdRevenue({
  valueMicros: 21500,         // the AdValue in micros — 0.0215 of the currency; never pre-round it
  currency: "USD",            // ISO 4217, as AdMob reports it
  precision: "estimated",     // AdMob's precisionType
  adUnitId: "ca-app-pub-0000000000000000/0000000000",
  adFormat: "rewarded",
  adSourceName: "AdMob Network", // the mediation source that filled it, when known
});

Impressions have their own queue (up to 1,000, sent in batches of 100) and a batch id persisted with it, so a crash between sending and the answer cannot count the same revenue twice. With testAds: true they are logged by the server and never counted. See AdMob.

setUserId(id)#

Attaches your own user id to everything sent from then on — use the same value you give RevenueCat as app_user_id. Call it after sign-in. See Identity.

const unsubscribe = Traqio.onDeepLink(({ deepLink, code, deferred, via }) => {
  if (deepLink) router.push(deepLink);
});

await Traqio.handleUrl(url);           // hosts other than React Native: a URL opened the app
await Traqio.getDeferredDeepLink();    // this install's deferred link, or null
await Traqio.getInstallReferrer();     // Android: the raw Play Install Referrer

onDeepLink returns its unsubscribe function. Each link has deepLink (the destination set on the link, or null), code (the link's slug), deferred and via (referrer, ip_match or link). React Native wires Linking itself; other hosts call handleUrl.

setConsent, forgetMe#

await Traqio.setConsent(userAgreed);   // sharing with ad networks — not measurement

const ok = await Traqio.forgetMe();    // erase this device and user on the server, then go silent
if (!ok) showError();                  // nothing changed on either side — let the user retry

setConsent is read at send time, so events queued before a “no” leave under the “no”. forgetMe is irreversible on both sides: the server deletes the device's and the user's data, and the SDK goes silent for good on this install. See Privacy.

flush, appOpened#

Traqio.flush();      // send the queue now (React Native does it on background)
Traqio.appOpened();  // the app came back to the foreground (React Native does it for you)

An app open is reported at init and on each return to the foreground after at least 30 minutes away — the convention GA4, Adjust and AppsFlyer share. It is what retention on day n is computed from.

Read-only properties#

  • Traqio.forgotten — true once forgetMe() has been honoured.
  • Traqio.skanMapping — the conversion-value mapping in force on this device, once fetched (iOS).

Storage#

Storage is what makes the install fire exactly once and the queue survive a kill. The core takes any object with async getItem / setItem; on React Native it uses AsyncStorage automatically when the app has it. Without storage it warns at launch and reports the install again at every start.

The native bridge#

interface NativeBridge {
  platform: "ios" | "android";
  getInstallReferrer(): Promise<InstallReferrerResult>;   // Android; never rejects
  getContext?(): Promise<{ deviceModel?: string; osVersion?: string }>;
  updateConversionValue?(fine: number, coarse?: "low" | "medium" | "high", lockWindow?: boolean): void; // iOS
  getAttributionToken?(): Promise<string | null>;         // iOS 14.3+, Apple Ads
  getAdvertisingId?(): Promise<string | null>;            // only with collectAdvertisingId; never prompts
}

The platform packages implement it. Without a bridge, the core sends events but has no referrer and no SKAdNetwork — events, not attribution.

Advertising id (opt-in)#

Off by default: the SDK sends no IDFA or GAID. Turn on collectAdvertisingId only if you buy from networks that attribute by the advertising id — Unity Ads and AppLovin match their click to your install on it. It is sent with the install and never used as its identity.

Traqio.init({
  sdkKey: "YOUR_SDK_KEY",
  endpoint: "https://api.traqio.app",
  native: getNativeBridge(),
  collectAdvertisingId: true, // off by default
});
  • iOS: the SDK never shows the App Tracking Transparency prompt — ask for it yourself beforeinit, and link AdSupport. The IDFA is read only if the user already allowed tracking.
  • Android: add com.google.android.gms:play-services-ads-identifier and thecom.google.android.gms.permission.AD_ID permission to your app; the SDK declares neither.
  • Declare the advertising id in your App Store privacy details and Google Play Data safety form.

What it sends#

RequestWhen
POST /ingestThe install (once), then event batches of up to 20. Queue capped at 500 events.
POST /ingest/sessionAn app open — not queued: a failed one is retried by the next open.
POST /ingest/ad-revenueAdMob impression batches of up to 100.
POST /ingest/adservicesiOS: the Apple Ads attribution token.
GET /skan/mapping/<sdkKey>iOS: the conversion-value mapping.
POST /deeplink/deferred · /deeplink/openDeep-link resolution.
POST /privacy/forgetforgetMe().

Every request carries the SDK key, the first-party device id and — once set — your user id and the consent answer. No advertising id, unless you set collectAdvertisingId: the install then carries it. These are the SDK's own routes, not a public server-to-server contract; for reading data from your servers, use the public API.

Frequently asked questions#

Can I use @traqio/core on its own?
Yes, but what you get alone is event ingestion, not attribution: attribution needs the platform evidence — the Google Play Install Referrer, SKAdNetwork — that only a native bridge can read. Apps on React Native, Expo or Capacitor should install their platform package, which includes the core and its bridge.
Are tracking calls blocking or can they throw?
Neither. track() and trackAdRevenue() only append to an in-memory queue persisted to storage; sending happens in the background, in batches, with exponential backoff up to five minutes. Network and HTTP errors are swallowed by design, which is also why a mistyped endpoint fails silently.

Last updated October 22, 2026