Install the SDK
Add InfluTo to a Capacitor, Ionic, Cordova or web app
Use @influto/web in Capacitor, Ionic, Cordova, PWAs and browsers — capture referral links, accept typed codes, and connect RevenueCat or store purchases.
@influto/web adds creator attribution to any app whose code runs in a WebView or a browser: Capacitor (including Ionic React, Angular and Vue), Apache Cordova, installed PWAs, Trusted Web Activities and plain web apps. It follows the same contract as the native SDKs, and adds web-only ways to pick up a referral exactly: the launch URL, deep links, and the Google Play Install Referrer. Plan for an afternoon; most of it goes into the purchase side.
| Package | @influto/web, with subpaths /capacitor, /cordova, /pwa, /revenuecat and /react |
| Latest version | 1.0.1 |
| Registry | npm |
| Runtimes | Capacitor / Ionic, Cordova, PWAs and TWAs, browsers — any ES2019 browser or WebView |
| Builds | ESM, CommonJS, and a script-tag build |
| Dependencies | None. React 17+ only if you use @influto/web/react |
Install
npm install @influto/web
# Capacitor / Ionic apps (device info, storage, deep links):
npm install @capacitor/device @capacitor/preferences @capacitor/appThe Capacitor plugins are optional but recommended: @capacitor/device for device details, @capacitor/preferences for storage that survives WebView resets, @capacitor/app for deep links. Run npx cap sync after adding them. Missing plugins fall back to browser defaults.
No bundler? Load https://cdn.jsdelivr.net/npm/@influto/web@1/dist/index.global.js with a <script> tag and use window.InfluTo.
Initialize
import InfluTo from '@influto/web';
import { capacitorAdapters } from '@influto/web/capacitor'; // Capacitor / Ionic only
// Call once at startup (Capacitor: after platform ready; PWA: on page load)
await InfluTo.initialize({
apiKey: 'YOUR_API_KEY',
appVersion: '1.2.3',
...(await capacitorAdapters()), // omit in a plain PWA / browser
// RevenueCat apps: revenueCat: revenueCatCapacitor(Purchases) (from '@influto/web/revenuecat')
});Call initialize once, at the app root, and wait for it before calling anything else:
| Runtime | When |
|---|---|
| Capacitor / Ionic | At app start, after the platform is ready — not inside an Ionic page, which can be cached and re-entered |
| Cordova | After deviceready: await whenDeviceReady() from @influto/web/cordova first |
| PWA / browser | On page load |
initialize throws when it fails — a wrong key, no network — with an InfluToApiError (status, body) for API errors. Catch it, log it, and carry on: the next launch tries again. If it hasn't succeeded, checkAttribution and reportPurchase throw "not initialized". It resolves to the app's init result (also available later from getInitResult()). A typical Capacitor startup, in order:
import InfluTo from '@influto/web';
import { capacitorAdapters, listenForCapacitorLaunchUrls } from '@influto/web/capacitor';
import { revenueCatCapacitor } from '@influto/web/revenuecat';
import { Purchases } from '@revenuecat/purchases-capacitor';
export async function startInfluTo() {
await Purchases.configure({ apiKey: 'appl_…' }); // RevenueCat apps: configure it first
try {
await InfluTo.initialize({
apiKey: import.meta.env.VITE_INFLUTO_API_KEY,
appVersion: '1.4.0',
...(await capacitorAdapters()),
revenueCat: revenueCatCapacitor(Purchases),
});
} catch (error) {
console.warn('InfluTo initialize failed', error); // retried on the next launch
return;
}
await listenForCapacitorLaunchUrls(InfluTo); // deep links → referral claim
const attribution = await InfluTo.checkAttribution();
const { appUserID } = await Purchases.getAppUserID();
await InfluTo.identifyUser(appUserID);
}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.local read through your bundler.
| Option | Default | What it does |
|---|---|---|
apiKey |
required | The app's SDK key (it_…) |
debug |
false |
Logs [InfluTo] lines to the console |
appVersion |
"unknown" |
Your app version, sent with the startup call |
runtime |
detected | capacitor, cordova, twa, pwa or browser |
storage, device, http |
localStorage, browser detection, fetch |
Adapters; capacitorAdapters() and cordovaAdapters() fill storage / device / runtime for you |
revenueCat |
none | RevenueCat binding — see Purchases |
captureLaunchCode |
true |
Read influto_code / influto_click from the page URL at startup |
cleanUrl |
true |
Remove the influto_* parameters from the address bar afterwards |
purchaseSource |
none | Store-direct apps: where purchases come from — see Purchases |
autoCapture |
true |
Report purchases from purchaseSource automatically |
oneTimeProductIds |
none | Your Android one-time and consumable product IDs |
Detect referred users
const attribution = await InfluTo.checkAttribution();
if (attribution.attributed) {
// User came from a referral — show a special offer / extended trial.
// With a RevenueCat binding the SDK also sets influto_code + influto_referral.
console.log('Referred by', attribution.referralCode);
}
// Web deep links: referral links send web visitors to your app URL with
// ?influto_code=…&influto_click=… — the SDK claims them automatically.| Field | Meaning |
|---|---|
attributed |
true when the install came from a creator's link or code |
referralCode |
The creator's code, uppercase |
attributionMethod |
link_param (the link carried the code into the app), ip_device_match (link-click matching) or manual_entry (a code the user applied) |
clickedAt, clickId |
When the link was clicked, and which click was claimed |
message |
A short explanation, for logs |
Attribution is decided once per install and stored; later calls return the stored answer. Only a failed request is retried. checkAttribution is fail-soft: on a network or server error it returns attributed: false and stores nothing. In React, useInfluToAttribution(enabled) from @influto/web/react returns { loading, attribution, error, refresh }; pass enabled = false until initialize has resolved.
The web SDK can claim a referral exactly, from the code the link carries, in three ways. A code picked up later re-opens an earlier "organic" answer on the next checkAttribution call; an attributed install keeps its creator. Without a carried code, InfluTo falls back to link-click matching within 72 hours — see attribution.
The launch URL (PWAs and web apps)
Set Settings → General → Web app URL. Referral links send desktop visitors — and phone visitors when your app has no store listing for their platform — to that URL with ?influto_code=…&influto_click=… appended. initialize reads both from the query or a hash-router fragment, stores them, and cleans the address bar.
Deep links (Capacitor and Cordova)
listenForCapacitorLaunchUrls(InfluTo) passes the cold-start URL and every appUrlOpen event to the SDK; it returns a function that removes the listener. In Cordova, or with your own handler, call InfluTo.handleLaunchUrl(url). Call either after initialize and before checkAttribution.
The Play Install Referrer (Android)
Google Play links from InfluTo carry the code and click in Play's referrer parameter. On first launch, read the referrer string with an Install Referrer plugin (@capgo/capacitor-install-referrer or cordova-play-install-referrer) and hand it over after initialize, before checkAttribution:
await InfluTo.captureInstallReferrer(referrer); // the raw referrer string from the plugin
const attribution = await InfluTo.checkAttribution();Identify the user
Call identifyUser(appUserId, properties?) as soon as you know who the user is, with the same ID your purchases are keyed on — for RevenueCat, the app user ID (see the startup example). InfluTo uses it to credit a RevenueCat purchase when the influto_code attribute didn't make it; checkAccess, setReferralCode and reportPurchase use it by default. Call it once per sign-in, ideally in the user's first session — not on every render.
Track events
await InfluTo.trackEvent({ eventType: 'paywall_viewed', appUserId: userId, properties: { placement: 'onboarding' } });Events show on Real-Time Events and never create conversions or commission. 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 in properties when the event can repeat, or pass eventId yourself.
Let users type a code
// Validate, then apply a code the user typed
const result = await InfluTo.applyCode('FITGURU30');
if (result.valid && result.applied) {
// Unlock the offer
}
// React / Ionic React: drop in the ready-made field
import { ReferralCodeInput } from '@influto/web/react';
<ReferralCodeInput onCodeApplied={(code) => {/* ... */}} />
// Free-access codes: (await InfluTo.setReferralCode(code)).grantsAccess → unlock
// premium, 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.
ReferralCodeInput from @influto/web/react is a plain, unstyled form: an input and a button. It pre-fills a link-attributed code and applies the code on submit.
| Prop | Default | Notes |
|---|---|---|
onCodeApplied(code, result) |
— | The code was valid and applied |
onInvalid(result) |
— | The code was rejected |
appUserId |
identified user | The user to bind the code to |
prefill |
true |
Pre-fill from a link-attributed install |
showCampaignName / showReferrerName |
false / false |
Show a creator's name only with their consent |
placeholder, buttonLabel |
'Referral or access code', 'Apply' |
Texts, for translation |
className, style, inputClassName, buttonClassName |
— | Styling |
Angular, Vue or no framework: build the field yourself on applyCode. 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
Pass a binding as revenueCat. When checkAttribution finds a referral, or a code is applied, the SDK sets influto_code (the code) and influto_referral (the string "true") through it. Then connect the webhook — see RevenueCat.
| Your RevenueCat SDK | Binding (from @influto/web/revenuecat) |
|---|---|
@revenuecat/purchases-capacitor 7.5.10+ |
revenueCatCapacitor(Purchases) |
@revenuecat/purchases-js 1.4.0+ (Web Billing) |
revenueCatJs(() => Purchases.getSharedInstance()) |
cordova-plugin-purchases |
revenueCatCordova(window.Purchases) |
| Anything else | A function (attrs) => …, or any object with setAttributes(map) — wrap it in revenueCatBinding(obj) to get retries |
The bindings retry a failed write up to 3 times (options retries, backoffMs, onError). To attach one after initialize, call InfluTo.attachRevenueCat(binding) — before checkAttribution.
Store-direct
Pass a purchase source as purchaseSource. When the app is set to store-direct in Settings → Validation and autoCapture isn't false, initialize starts reporting new purchases and back-fills existing ones, each once.
| Runtime | Purchase plugin | Source |
|---|---|---|
| Capacitor | @capgo/native-purchases |
capgoNativePurchasesSource(NativePurchases, { oneTimeProductIds }) from /capacitor |
| Cordova | cordova-plugin-purchase v13 |
cordovaPurchaseSource(CdvPurchase.store, { oneTimeProductIds }) from /cordova |
| TWA on Google Play | Digital Goods API (Chrome 101+) | digitalGoodsSource({ oneTimeProductIds }) from /pwa |
The Digital Goods API has no purchase event, so call InfluTo.syncExistingPurchases() after each checkout. requestPlayBillingPurchase(itemId) from /pwa runs a Play Billing checkout and returns { purchaseToken }, or null if the user cancelled. You can also drive capture yourself with enableAutoPurchaseCapture(source, { backSync, oneTimeProductIds }) and disableAutoPurchaseCapture().
- iOS needs the StoreKit 2 signed transaction.
capgoNativePurchasesSourcepasses it on; withcordova-plugin-purchase, check that your setup exposes one, or iOS reports fail. - Android one-time products: the Capacitor and Cordova sources don't carry a price, and a one-time purchase without a price is recorded at $0. Report those yourself with
priceandcurrency.digitalGoodsSourcelooks the price up.
To report purchases yourself instead, set autoCapture: false and call reportPurchase:
// Store-direct only (no RevenueCat). Attach a purchase source and purchases are
// captured automatically — TWA/PWA on Play: digitalGoodsSource(); Capacitor:
// capgoNativePurchasesSource(); Cordova: cordovaPurchaseSource(). Or report manually:
await InfluTo.reportPurchase({
platform: 'android', // or 'ios'
purchaseToken: token, // Android: Play Billing purchaseToken
// signedTransaction: jws, // iOS: StoreKit 2 JWS
});- In a browser or PWA, always pass
platform('ios'or'android'); the SDK refuses to guess when it detectsweb. - It throws an
InfluToApiError.503: the exchange rate was briefly unavailable — retry later.400: the platform isn't set to store-direct yet.409: an Android one-time purchase isn't in the PURCHASED state yet. - Android one-time products need
productId, pluspriceandcurrency.
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?); it uses the identified user when you don't pass one, and 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: entitlementActive || (await InfluTo.checkAccess()).hasAccess. checkAccess 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 "Integrated — SDK connected" with the platform, @influto/web and the SDK version it last saw. With debug: true the SDK logs each step, and Real-Time Events 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, clearAttribution() forgets the stored attribution, code and launch code.
Platform notes
Capacitor and Ionic
- With
@capacitor/preferencesinstalled,capacitorAdapters()stores the SDK's state there. WebViewlocalStorageis wiped whenandroidSchemeoriosSchemechanges; pass{ usePreferences: false }to keeplocalStorageanyway. - The reported platform is the native OS (
iosorandroid). - In a web dev build (
ionic serve) the RevenueCat Capacitor plugin is a stand-in, so attribute writes do nothing there. Test on a device.
Cordova
- A fresh Cordova template blocks the API twice: add
<access origin="https://influ.to" />toconfig.xmlandconnect-src https://influ.toto the Content-Security-Policy meta tag. - Start with
await whenDeviceReady()and pass...cordovaAdapters()toinitialize; storage stays inlocalStorage. - RevenueCat has deprecated its Cordova plugin. For a new app, prefer Capacitor.
PWAs, TWAs and web apps
- Set the Web app URL so referral links can hand the code to your app.
- The platform comes from the user agent the same way InfluTo classifies a click: phones are
iosorandroid, everything elseweb. - A TWA on Google Play can sell through Play Billing (
digitalGoodsSource()); web checkout through RevenueCat Web Billing works withrevenueCatJs(). iOS home-screen web apps can't sell in-app purchases, but attribution still works. isStandalone()andhasDigitalGoods()from/pwatell you whether you're running installed and whether Play Billing is available.
Script tag
The script-tag build contains the core SDK only; the subpath helpers need a bundler. Pass revenueCat as a plain function that calls your RevenueCat SDK's setAttributes.