X3 App tracking

Every app install. With its source.

Where your users come from, who signs up and what they buy. In one profile with your website.

  • iOS · Android · React Native · Flutter
  • No fingerprinting
  • Consent your way

01The problem

  • 01

    The store eats the click.

    Between the ad and the first open sits the store. The campaign does not make it through.

  • 02

    Logins without a source.

    Whoever signs up in the app is a stranger. Even if they were a lead on your website yesterday.

  • 03

    Purchases without a person.

    Subscriptions run through the App Store and Google Play. Your campaigns never learn who buys.

What the app store swallows.

Your ad works. But the trail breaks in the store.

02How it works

Install attribution flowNine steps from the ad to the account: click on the ad, page view on the landing page, tap on get the app through an X3 link with a click token, redirect to the store, install, first open with the Play referrer or the Apple Ads token, sign-up with identify, an aggregated Apple postback copy and finally the conversion to Meta with the fbclid from the web journey.AdMeta, GoogleLanding pageWeb SDKStoreApp Store, Google PlayNordlicht appX3 SDKX3via nordlicht.app/n31Click with utm_* and fbclid2Page view: session and journey3Tap “Get the app”: the X3 link issues a click token4Redirect: Android with referrer, iOS to the App Store5Installand first open6First open reports the sourcePlay referrer · Apple Ads token7Sign-up: identify()User ID hash · email hash8Apple postback copy, aggregated, after 24 to 48 h9“Subscription” conversion to Meta, with the web fbclidAndroid: the click token finds the web sessioniOS: Apple Ads exact, otherwise open for nowno IP matching, no fingerprintingSame email hash as in the web journeyThe iOS install becomes “Via login” afterwards
  1. AdtoLanding pageClick with utm_* and fbclid
  2. Landing pagetoX3Page view: session and journey
  3. Landing pagetoX3Tap “Get the app”: the X3 link issues a click token
  4. X3toStoreRedirect: Android with referrer, iOS to the App Store
  5. StoretoNordlicht appInstalland first open
  6. Nordlicht apptoX3First open reports the sourcePlay referrer · Apple Ads tokenAndroid: the click token finds the web sessioniOS: Apple Ads exact, otherwise open for nowno IP matching, no fingerprinting
  7. Nordlicht apptoX3Sign-up: identify()User ID hash · email hashSame email hash as in the web journeyThe iOS install becomes “Via login” afterwards
  8. StoretoX3Apple postback copy, aggregated, after 24 to 48 h
  9. X3toAd“Subscription” conversion to Meta, with the web fbclid

From click to account.

Android is exact, through the Play referrer. iOS through Apple Ads, or at login at the latest.

03Accuracy

Every number shows its accuracy.

Android delivers the campaign through the Play referrer. iOS shows Apple Ads exactly, the rest per campaign. At login you see the journey, if the person is known.

What is realistic on iOS and Android
SituationiOSAndroid
X3 link on your website, then the storeVia loginwhen the web journey carries an identity, otherwise aggregatedExact (Play referrer)the referrer carries UTMs and the click token
Apple Ads campaignExact (Apple Ads)campaign down to the keyword, no ATT neededdoes not exist on Android
Meta app campaignAggregatedApple postbacks per campaign, per person via loginExact (Play referrer)Meta Install Referrer inside the Play referrer
Google app campaignAggregatedApple postbacks per campaign, per person via loginExact (Play referrer)gclid inside the Play referrer
Store search, word of mouthUnknownno source until a login links itOrganicPlay reports the install as organic
Match a login to an existing leadVia loginthrough the email hash or user ID hashVia loginthrough the email hash or user ID hash
Purchase with user data to ad platformsonly with ATT permission, otherwise without user datawith the “Ad measurement” consent

04One profile

Identity stitchingOne person, five touchpoints: Meta instant form on 3 Oct, web session on 5 Oct, iPhone app with sign-up on 5 Oct, App Store purchase on 7 Oct and iPad app on 20 Oct. Email hash, user ID hash and account token connect everything into one lead profile with one journey. The Meta subscription conversion goes out with the fbclid from the web session.Meta instant form3 OctLead · email hashWeb session5 Octfbclid · campaign autumnPlan by email: email hashiPhone app5 OctInstall · sign-upUser ID hash · email hashApp Store purchase7 OctSubscription · account tokeniPad app20 OctLogin · user ID hashEmail hashEmail hashUser ID hashAccount tokenLead profileone journey · via login3 OctInstant form, source Meta5 OctWebsite, campaign autumn5 OctApp installed (iOS)5 OctAccount created7 OctSubscribed, €59.99to 26 Oct12 logins, 2 devicesMeta conversion “Subscription”sent with the fbclid
  1. Meta instant form3 OctLead · email hash
  2. Email hashWeb session5 Octfbclid · campaign autumnPlan by email: email hash
  3. Email hashiPhone app5 OctInstall · sign-upUser ID hash · email hash
  4. Account tokenApp Store purchase7 OctSubscription · account token
  5. User ID hashiPad app20 OctLogin · user ID hash
Lead profileone journey · via login
  • 3 OctInstant form, source Meta
  • 5 OctWebsite, campaign autumn
  • 5 OctApp installed (iOS)
  • 5 OctAccount created
  • 7 OctSubscribed, €59.99
  • to 26 Oct12 logins, 2 devices
Meta conversion “Subscription” sent with the fbclid
Sample data

One person. One profile.

Login connects everything, without fingerprinting. App usage lands on the lead you already know.

  • Only hashes. At login, email and user ID leave the device only as SHA-256.
  • No lead from a login. A lead appears only when you want one.
  • Every device. iPhone, iPad and browser end up in one journey.
Login and accounts in the docs

05Purchases and conversions

Purchase flowThe app reports the purchase with X3.purchase as a hint. X3 holds it until App Store Server Notifications, Google Play RTDN, RevenueCat or your server confirm the same order id. Then the purchase counts and, only with the ad measurement consent, goes to Meta, Google Ads, TikTok and LinkedIn. iOS without ATT permission: Meta and TikTok without user data, Google Ads and LinkedIn are skipped.Nordlicht appX3.purchase(…)Hint with the order id1X3 holds the purchaseuntil the order id is confirmedWaitingCONFIRMATIONApp Store Server NotificationsGoogle Play RTDNRevenueCatYour serverForwarded to your existing URL2confirmedPurchase countsGoal, revenue, lead profile3AD PLATFORMSonly with “Ad measurement”MetaGoogle AdsTikTokLinkedIniOS without ATT permission: Meta and TikTok without user data,Google Ads and LinkedIn are skipped.
  1. Nordlicht appX3.purchase(…)Hint with the order id
  2. X3 holds the purchaseuntil the order id is confirmedWaiting
  3. Confirmation
    • App Store Server Notifications
    • Google Play RTDN
    • RevenueCat
    • Your server
    Forwarded to your existing URL
  4. Purchase countsGoal, revenue, lead profile
  5. Ad platformsonly with “Ad measurement”MetaGoogle AdsTikTokLinkedIniOS without ATT permission: Meta and TikTok without user data, Google Ads and LinkedIn are skipped.

Only purchases that really happened.

The app reports the purchase, the store confirms it. Only then does it count and go to your ad accounts.

  • Straight from the store. Store notifications come to X3 and are verified cryptographically.
  • Purchase and person. The account token links both: appAccountToken at Apple, obfuscatedAccountId at Google.
  • Leads from the app. X3.lead() sends an inquiry just like a form on your website.
Purchases in the docs

06Recordings

Recording pipelineOn the device: read the screen, mask, wireframe diff with taps, buffer and upload through your domain, only with consent. At X3, same as on the web: PII check on the server, storage in the EU, player with a phone frame and the recording on the lead profile.ON THE DEVICEAT X3, SAME AS ON THE WEBRead the screenUIKit, SwiftUI,Compose, React NativeMaskinput never, textand images maskedWireframe diffplus taps, rage tapsand dead tapsBuffergzip, at most 8 MB,optionally Wi-Fi onlyUploadthrough your domain,only with consentHTTPS, your domainPII checka second safeguardon the serverStorage in the EUretention as setin your projectPlayerwith a phone frame,screen instead of URLOn the leadrecording in the visitand the lead profile
On the device
  1. Read the screenUIKit, SwiftUI, Compose, React Native
  2. Maskinput never, text and images masked
  3. Wireframe diffplus taps, rage taps and dead taps
  4. Buffergzip, at most 8 MB, optionally Wi-Fi only
  5. Uploadthrough your domain, only with consent
HTTPS, your domain
At X3, same as on the web
  1. PII checka second safeguard on the server
  2. Storage in the EUretention as set in your project
  3. Playerwith a phone frame, screen instead of URL
  4. On the leadrecording in the visit and the lead profile

See sessions. Never what's typed.

A wireframe instead of video, light and masked. It plays in the same player as your website.

  • Typed input is never recorded, not even passwords or card data.
  • Text and images are masked by default.
  • A visible recording indicator in the app is on by default.
  • Screenshots only for screens you allow in code.
  • Pauses in low power mode.
Recordings in the docs

08Privacy

What X3 never does.

No fingerprinting, no advertising IDs. Only what you allow gets measured.

Never

  • Fingerprinting or IP matching between app and web
  • IDFA, GAID or the device name
  • Typed text, clipboard, contacts or location
  • Third-party tracking domains: only your domain or X3

Always

  • A random install ID, never backed up, only a hash at X3
  • Email and user ID from identify() only as SHA-256
  • Privacy manifest and store details ready to use
  • Erase per user: by user ID, email or install ID
Store details in the docs

09App stacks

For every app stack.

Swift, Kotlin, React Native, Expo and Flutter. Data runs through your own domain.

Choose a code sample
import X3Kit

X3.configure(key: "pk_3x_…", options: X3Options(
  consent: X3ConsentOptions(mode: .optIn),
  host: URL(string: "https://nordlicht.app/n3")!))
X3.identify(userId: user.id, email: user.email)
import io.x3growth.sdk.*

X3.configure(this, "pk_3x_…", X3Options(
  consent = X3ConsentOptions(mode = X3ConsentMode.OPT_IN),
  host = "https://nordlicht.app/n3"))
X3.identify(userId = user.id, email = user.email)
import { X3 } from "@x3growth/react-native";

X3.configure("pk_3x_…", {
  consent: { mode: "opt_in" },
  host: "https://nordlicht.app/n3" });
X3.identify(user.id, { email: user.email });
import 'package:x3growth/x3growth.dart';

await X3.configure('pk_3x_…', const X3Options(
  consent: X3ConsentOptions(mode: X3ConsentMode.optIn),
  host: 'https://nordlicht.app/n3'));
X3.identify(user.id, email: user.email);

Here in opt-in mode: X3 measures only after consent, through the ready-made dialog or X3.consent().

SDK architectureWrappers for React Native, Expo and Flutter sit on two native cores, X3Kit in Swift for iOS 15 and later and io.x3growth:sdk in Kotlin for Android from API 24. They use system APIs such as AdServices, AdAttributionKit and the Play Install Referrer, never IDFA, GAID or fingerprinting. Data goes to X3 as JSON batches through your first-party proxy, Apple and Google send postbacks and store notifications directly. X3 processes everything as on the web and sends conversions to Meta, Google Ads, TikTok and LinkedIn.WRAPPERS@x3growth/react-nativeExpo module, hooksExpo config pluginInfo.plist, manifestx3growth (Flutter)Plugin for iOS and AndroidNATIVE CORESX3Kit · SwiftiOS 15+CoreReplayUIQueue · consent · batchesio.x3growth:sdk · KotlinAPI 24+sdkreplaycomposeQueue · consent · batchesSYSTEM APISIOSAdServices · AdAttributionKitSKAdNetwork · StoreKit 2 · ATTANDROIDPlay Install ReferrerNEVERIDFA · GAID · fingerprintingJSON batches, gzip, HTTPSnordlicht.app/n3 · your first-party proxy/v1/m/* · /go/* · /.well-known/appattribution · /.well-known/skadnetworkApple and GooglePostbacks · store notificationsX3, same as on the webSessions · journeys · leads · goals · purchases · recordings · dashboard · MCPMetaGoogle AdsTikTokLinkedIn
Wrappers
  • @x3growth/react-nativeExpo module, hooks
  • Expo config pluginInfo.plist, manifest
  • x3growth (Flutter)Plugin for iOS and Android
Native cores
  • X3Kit · SwiftiOS 15+CoreReplayUI
  • io.x3growth:sdk · KotlinAPI 24+sdkreplaycompose
System APIs
  • iOSAdServices · AdAttributionKit
  • SKAdNetwork · StoreKit 2 · ATT
  • AndroidPlay Install Referrer
  • NeverIDFA · GAID · fingerprinting
JSON batches, gzip, HTTPS
nordlicht.app/n3 · your first-party proxy/v1/m/* · /go/* · /.well-known/appattribution · /.well-known/skadnetwork
Apple and GooglePostbacks · store notifications
X3, same as on the webSessions · journeys · leads · goals · purchases · recordings · dashboard · MCP
MetaGoogle AdsTikTokLinkedIn

Does it work on iOS without ATT permission?

Yes. Apple Ads are exact, other campaigns you see aggregated. Per person it becomes exact at login, if the person is known.

Does X3 use fingerprinting?

No, never. No IP matching, no IDFA, no GAID.

Who decides on consent?

You, per app: always on, opt-in or opt-out. You clarify the legal basis, X3 implements your choice.

When does a purchase count?

When the App Store, Google Play, RevenueCat or your server confirms it. Only then does it go to your ad accounts.

What do recordings capture?

A wireframe of your screens, not a video. Typed input never, text and images masked.

What does app tracking cost?

It runs on the same plans as your website. Screen views count like page views, recordings like on the web.

How much work is the setup?

A few lines of code cover the basic measurement. The dashboard wizard shows you when the first data arrives.

Where are the docs?

In the developer docs: quickstart, consent and reference. You find them at intelligence.x3growth.io/docs/apps.

10Get started

Find out where they come from.

Free forever, no credit card. App and website in one project.