Skip to content
InfluToDocs

Install the SDK

Add InfluTo to a React Native or Expo app

Install the InfluTo SDK in a React Native or Expo app, detect referred installs, accept typed codes, and send purchases through RevenueCat or the stores.

@influto/react-native-sdk adds creator attribution to a React Native or Expo app. It tells you whether an install came from a creator's link or code, lets people type a creator's code, and gets each purchase to InfluTo through RevenueCat or straight from the App Store and Google Play. Plan for an afternoon; most of it goes into the purchase side.

Package @influto/react-native-sdk (UI components: @influto/react-native-sdk/ui)
Latest version 1.7.0
Registry npm
Requires React Native 0.60+ and React 16.8+, @react-native-async-storage/async-storage 2.x
Works with Expo (managed and bare) and bare React Native, iOS and Android
Source github.com/influto/influto-react-native (MIT)

Install

Terminal
npm install @influto/react-native-sdk
# AsyncStorage is a native module — install it in the app too
npm install @react-native-async-storage/async-storage

AsyncStorage holds the SDK's local state. Install it in your app as well, so autolinking picks up its native module. In a bare React Native project, run pod install in ios/ afterwards.

On Expo there is no config plugin to add: the SDK is plain JavaScript on top of AsyncStorage, so it runs in Expo Go, development builds and production builds alike.

The SDK also uses these packages when your app already has them. You don't import anything for this:

Package What the SDK does with it
react-native-purchases Sets the RevenueCat attributes influto_code and influto_referral when a referral is found or a code is applied
expo-iap or react-native-iap Captures store purchases on store-direct apps (expo-iap is used if both are installed)
react-native-device-info Adds the device brand and model to install tracking

Store libraries contain native code, so test purchases in a development build rather than Expo Go.

Initialize

TSX
import InfluTo from '@influto/react-native-sdk';

// Call once at startup (e.g. in App.tsx)
await InfluTo.initialize({
  apiKey: 'YOUR_API_KEY',
  debug: __DEV__,
});
// RevenueCat apps: nothing else to wire — if react-native-purchases is
// installed, the SDK sets the influto_code subscriber attribute itself.

Call initialize once, as early as possible, and wait for it before calling anything else. If it hasn't succeeded, checkAttribution and reportPurchase throw "not initialized" and the other methods return empty results.

initialize throws when it fails — a wrong key, no network. Catch it, log it, and carry on: the next launch tries again. A typical startup, in order:

App.tsx
import { useEffect } from 'react';
import Purchases from 'react-native-purchases';
import InfluTo from '@influto/react-native-sdk';

export default function App() {
  useEffect(() => {
    (async () => {
      Purchases.configure({ apiKey: REVENUECAT_API_KEY }); // RevenueCat apps: configure it first
      try {
        await InfluTo.initialize({
          apiKey: process.env.EXPO_PUBLIC_INFLUTO_API_KEY!,
          appVersion: '1.4.0',
          debug: __DEV__,
        });
      } catch (error) {
        console.warn('InfluTo initialize failed', error); // retried on the next launch
        return;
      }
      const attribution = await InfluTo.checkAttribution();
      await InfluTo.identifyUser(await Purchases.getAppUserID());
    })();
  }, []);
  // …
}

The API key starts with it_ and is on Setup & SDK; one key works for development and production. Keep it out of committed source — for example in a gitignored .env read through Expo's EXPO_PUBLIC_ variables.

Option Type Default What it does
apiKey string required The app's SDK key (it_…)
debug boolean false Logs [InfluTo] lines to the console
appVersion string "unknown" Your app version, sent with the startup call
autoCapture boolean true Store-direct apps: report purchases from expo-iap / react-native-iap automatically. Set false if you call reportPurchase yourself
oneTimeProductIds string[] none Your Android one-time and consumable product IDs, so captured purchases are validated as one-time purchases

Detect referred users

TSX
const attribution = await InfluTo.checkAttribution();
if (attribution.attributed) {
  // User came from a referral — show a special offer / extended trial.
  // The SDK also sets the RevenueCat attributes influto_code + influto_referral.
  console.log('Referred by', attribution.referralCode);
}
Field Meaning
attributed true when the install came from a creator's link or code
referralCode The creator's code, uppercase
attributionMethod ip_device_match (link-click matching) or manual_entry (a code the user applied)
clickedAt When the link was clicked, or the code applied
message A short explanation, for logs

Attribution is decided once per install and stored on the device; later calls return the stored answer without a request. Only a failed request is retried, on the next call. A reinstall starts over.

checkAttribution is fail-soft: on a network or server error it returns attributed: false and stores nothing. Link-click matching only counts taps from the last 72 hours — see attribution. To show referred users a better offer, see Reward referred users.

Identify the user

Call identifyUser as soon as you know who the user is, with the same ID your purchases are keyed on — for RevenueCat, the app user ID:

TSX
await InfluTo.identifyUser(await Purchases.getAppUserID());

It matters for three things: InfluTo uses it to credit a RevenueCat purchase when the influto_code attribute didn't make it, checkAccess uses it for free-access codes, and reportPurchase sends it by default. Call it once per sign-in, ideally in the user's first session — not on every render.

Track events

TSX
await InfluTo.trackEvent({
  eventType: 'paywall_viewed',
  appUserId: userId,
  properties: { placement: 'onboarding' },
});

Events show in the Integration log (under Setup & SDK) and help you read the funnel. They never create conversions or commission — only validated purchases do. Every call gets an event ID, so an accidental double call counts once. For trial_started, subscription_purchased and subscription_renewed the ID is derived from the event, user and properties, so the same event counts once even across launches; include something that changes per occurrence (a transaction ID, say) in properties when the event can repeat. For your own once-only events, pass eventId yourself.

Let users type a code

TSX
// Validate, then apply a code the user typed
const result = await InfluTo.applyCode('FITGURU30');
if (result.valid && result.applied) {
  // Unlock the offer
}

// Or drop in the ready-made UI:
import { ReferralCodeInput } from '@influto/react-native-sdk/ui';
<ReferralCodeInput onApplied={(result) => {/* ... */}} />

// Free-access codes (INFLU-… or your comp codes): redeem with
// setReferralCode(code) after identifyUser (or pass appUserId) — grantsAccess
// === true means unlock premium now — and gate premium on (await InfluTo.checkAccess()).hasAccess.

applyCode(code, appUserId?) validates the code and applies it if it's valid. Codes are trimmed and uppercased for you. An invalid code comes back with valid: false and an error_code: INVALID_FORMAT, CODE_NOT_FOUND, CODE_EXPIRED or NETWORK_ERROR. If you build your own field, write your own copy: message and influencer can contain the creator's personal name.

The ready-made field is ReferralCodeInput from @influto/react-native-sdk/ui:

Prop Default Notes
onApplied(result) — The code was valid and applied
onValidated(result) — After every validation, valid or not
onSkip() — The skip button was pressed
appUserId identified user The user to bind the code to; free-access codes need one
autoPrefill / autoValidate true / false Pre-fill the code from a link-attributed install, and validate it on mount
validateOnBlur / showSkipButton true / true
showCampaignName / showReferrerName false / false Show a creator's name only with their consent
colors, fonts, labels, style — Theming and translated labels

More on the UX: Let users enter a referral code. All props: UI components.

Purchases

InfluTo only pays commission on purchases it has verified with the store. Choose exactly one path per platform — see Choose a validation path.

RevenueCat

With react-native-purchases installed, there's nothing to wire in code: when checkAttribution finds a referral, or a code is applied, the SDK sets influto_code (the code) and influto_referral (the string "true") on the RevenueCat subscriber. Then connect the webhook — see RevenueCat.

Store-direct

Install expo-iap or react-native-iap. When the app is set to store-direct in Settings → Validation and autoCapture isn't false, initialize starts listening for new purchases and back-fills existing ones. Each purchase is reported once; without an IAP library, capture quietly does nothing. You can also drive it yourself with enableAutoPurchaseCapture({ backSync, oneTimeProductIds }), disableAutoPurchaseCapture() and syncExistingPurchases().

To report purchases yourself instead, set autoCapture: false and call reportPurchase after each successful purchase:

TSX
// Store-direct only (no RevenueCat). With expo-iap or react-native-iap installed,
// purchases are captured automatically on store-direct apps. To report
// manually instead, pass the store-signed proof:
await InfluTo.reportPurchase({
  platform: 'ios',                 // or 'android'
  signedTransaction: jwsString,    // iOS: StoreKit 2 JWS
  // purchaseToken: token,         // Android: Play Billing purchaseToken
});
  • reportPurchase throws on failure. The error message includes the HTTP status, for example API request failed: 503 - ….
  • 503: the exchange rate was briefly unavailable — retry later. Reports are idempotent.
  • 400: the platform isn't set to store-direct yet. 409 (Android one-time products): the purchase isn't in the PURCHASED state yet.
  • Android one-time and consumable products need productId, plus price and currency from the product details. Captured purchases only carry a price when the IAP library puts one on the purchase, and a one-time purchase without a price is recorded at $0 — report those yourself.

Set-up, credentials and testing: Store-direct.

Free-access codes

Free-access codes give a user premium without a purchase. Redeem one with setReferralCode(code, appUserId) after identifyUser, or pass the user ID — a code with no user is refused. The result tells you what happened: grantsAccess, freeAccess, entitlement and expiresAt. applyCode doesn't return these flags; after it, result.campaign?.campaign_type === 'FREE_ACCESS' tells you the code was a free-access code.

Gate premium on your store entitlement or InfluTo's answer:

TSX
const premium = entitlementActive || (await InfluTo.checkAccess()).hasAccess;

checkAccess(appUserId?) uses the identified user when you don't pass one, caches a positive answer for 5 minutes, never caches a negative one, and returns hasAccess: false on errors. See Free access codes.

Verify

After the first successful initialize, Setup & SDK shows "SDK connected" with the platform and SDK version it last saw. With debug: true the SDK logs each step, and the Integration log lists your events and purchases. For the full end-to-end test and the integration status checklist, see Verify the integration.

To test attribution again on the same device, clearAttribution() forgets the stored attribution, code and user ID. It's for testing only — a reinstall gives a cleaner start.

React Native notes

  • AsyncStorage must be in your app's own dependencies, or its native module isn't linked.
  • Order matters for RevenueCat: configure react-native-purchases, then initialize, then checkAttribution.
  • Initialize once. Put it at the app root, not in a screen that mounts repeatedly, and don't call identifyUser from a render path.
  • Expo Go runs the SDK, but not store libraries. Auto-capture does nothing there, which is safe.
  • Android one-time products: list them in oneTimeProductIds, and report them yourself if your IAP library doesn't expose the price.