Get started

Payments and user IDs

Unolink joins every payment to the install it belongs to, and so to the link or ad that install came from. That works however late the payment comes: someone who taps your TikTok ad today and subscribes two weeks from now still counts as a paying user from that ad. Pro plan and up.

How late payments are counted

  • Every event belongs to an install. A payment that arrives a week or a month after the install is added to that same person.
  • Funnels, Journeys and the Report never cut off. A step counts if the person did it at any time, so a late payment still turns them into "Paid".
  • The date range picks people, not events. "Last 7 days" means people who installed in the last 7 days, plus everything they did afterwards. Look at last week's installs again next week and Paid may have gone up: that's late payers arriving, not a mistake.
  • Journeys update themselves. Someone shown as "Left" (no activity for a week) becomes "Completed" when their payment arrives, and the row shows "paid 9 days after install · came back".

Where to see how long people take

  • Report → When people pay: the share of installs paying within a day, 7 days and 30 days, the median wait, and how many came back to pay after a week or more of silence, for everyone and per link. "Within 7 days" only counts installs at least 7 days old, so recent installs don't drag the number down.
  • Journeys: each paying person shows how many days after installing they first paid, and whether they came back after going quiet.
  • Already subscribed: someone who subscribed before this install (a reinstall, a new phone) sends a renewal, not a purchase. Journeys shows them as "Already subscribed · renewed" and counts their money in revenue, but not as Paid: the sale wasn't made by this install or the link it came from.

What your app needs

Payments reach Unolink in one of two ways:

  1. RevenueCat (recommended). Connect its webhook under your app → Settings → RevenueCat. RevenueCat reports purchases, trial conversions, renewals and refunds even when the app isn't open, which is how most late payments happen (a free trial that converts a week later, a renewal next month).
  2. The SDK's purchase() call, sent from inside the app when someone pays there. Fine without RevenueCat, but it can't see anything that happens outside the app.

For RevenueCat's events to find the right install, the app has to tell Unolink who the user is, with RevenueCat's own app user ID. With SDK 0.3.2 or later, one line at launch keeps it current:

// iOS: once at launch, before or after configure
Unolink.connectRevenueCat { Purchases.isConfigured ? Purchases.shared.appUserID : nil }
// Android
Unolink.connectRevenueCat { Purchases.sharedInstance.appUserID }
// React Native
Unolink.connectRevenueCat(Purchases)
// Flutter
Unolink.connectRevenueCat(() => Purchases.appUserID,
    addListener: Purchases.addCustomerInfoUpdateListener,
    removeListener: Purchases.removeCustomerInfoUpdateListener);

It reads RevenueCat's ID at launch, when the app comes back to the foreground and when it changes, and sends it only when it's new (on iOS and Android, also call Unolink.revenueCatUserChanged() after logIn and logOut). Before 0.3.2, or to do it yourself, call setUserId with RevenueCat's ID instead (for example Unolink.setUserId(Purchases.shared.appUserID)) after Purchases.configure, after every Purchases.logIn and Purchases.logOut, and on every launch. Use one or the other, not both. RevenueCat has the code for every platform.

For a guest, RevenueCat's ID is its anonymous ID, so a purchase made before signing up joins the install right away. After logIn, it's the account's ID. Unolink keeps every ID an install has reported, so the guest's purchase stays joined. A payment that arrives before the app has sent the user ID isn't lost: it waits and joins the install as soon as the ID arrives. Without RevenueCat, call setUserId with your own user ID, and null (nil in Swift) on logout.

When someone taps "continue as guest", call Unolink.signUpSkipped() too (SDK 0.3.2 or later, React Native 0.3.1; older SDKs: track("sign_up_skipped")), so the funnel's Continued as guest step counts them. See Guests and accounts.

When a payment can't be joined

  • No RevenueCat and no setUserId, and the person pays outside the app (for example on your website). Nothing tells Unolink about it.
  • They reinstall before paying. A new install is a new person to Unolink, unless the same user ID links them.
  • They pay on another device. Also joined only through the user ID.
  • A guest pays, and the app reports only the account ID. RevenueCat sends the purchase under its anonymous ID, which the app never reported. It still joins, but only with RevenueCat's next event for that customer that lists both IDs (for example the first renewal); until then the person shows as not paid yet. Reporting RevenueCat's own ID joins it right away.

With RevenueCat connected and its ID reported (connectRevenueCat, or setUserId with RevenueCat's ID), all of these are covered.

Privacy: this isn't fingerprinting

  • Fingerprinting means working out which device someone is from its characteristics (IP address, screen, fonts, settings) without asking, usually to follow them across other companies' apps. Apple forbids it, and Unolink never does it.
  • setUserId is your app's own user ID, handed over on purpose by your app. Unolink keeps only a keyed one-way hash of it (HMAC-SHA256 with a key unique to each of your apps), never the ID itself, and uses it for one thing: joining your app's payments to your app's installs. It's never shared with other apps, ad networks or anyone else.
  • Apple's App Tracking Transparency is about linking your app's data with other companies' apps or websites for advertising, or sharing it with data brokers. Joining your own purchases to your own installs is first-party analytics, the same kind RevenueCat or Firebase do, so it needs no tracking prompt.

In App Store Connect's privacy questions, Unolink with setUserId usually comes down to: User ID and Purchases, collected for Analytics, linked to the user, and not used to track. Your own answers depend on everything else your app does, so check them as a whole.