Skip to content
InfluToDocs

Reference

Referral code input components

The ready-made referral code fields for React Native, SwiftUI, Jetpack Compose, Flutter and React — props, defaults, theming, privacy and building your own.

Every InfluTo SDK ships a ready-made field where users type a creator's referral code or a free-access code. It prefills the code when a referral link brought the user, checks it with InfluTo, and applies it. Use it as is, or build your own field on validateCode and applyCode — see the last section and the referral code guide.

Which component

Platform Component Import Where it ships
React Native / Expo ReferralCodeInput import { ReferralCodeInput } from '@influto/react-native-sdk/ui' In @influto/react-native-sdk
iOS (SwiftUI) InfluToReferralCodeInput import InfluTo In the Swift package (iOS 16+)
Android (Jetpack Compose) InfluToReferralCodeInput import to.influ.sdk.ui.InfluToReferralCodeInput Separate artifact to.influ:android-sdk-ui (Material 3)
Flutter ReferralCodeInput import 'package:influto/influto.dart' In influto
Web (React) ReferralCodeInput, useInfluToAttribution import { ReferralCodeInput } from '@influto/web/react' In @influto/web (needs React 17+)

All of them need initialize to have finished first.

How they behave

React Native iOS, Android, Flutter Web (React)
Prefill getPrefilledCode() on mount (autoPrefill) Same (autoPrefill) Same (prefill)
Checks the code When the field loses focus, and on the button While the user types: from 3 characters, 450 ms after the last keystroke On submit
Applies the code As soon as a check finds it valid (setReferralCode) When the user taps Apply (applyCode); the button is enabled only for a valid code On submit (applyCode)
Callbacks onValidated, onApplied, onSkip onValidated, onApplied onCodeApplied, onInvalid
Input Uppercased, up to 20 characters Uppercased; letters, digits, - and _ (Flutter: up to 20) Uppercased

When a code is rejected, the components show the result's error text — the server's English message, such as "Code not found or inactive", or the SDK's "Network error or invalid response" — and fall back to your invalid label only when there's none (Android shows "This code has expired" for an expired code). For fully localized messages, build your own field and map error_code yourself.

Privacy defaults

By default each component shows only the field and whether the code is valid. Two props, both false by default, add more:

  • showCampaignName — shows the campaign's name (React Native also shows its description).
  • showReferrerName — shows the creator's personal name ("Referred by …"). Turn it on only if your creators agreed to be named.

React Native shows them once the code is valid (which is also when it's applied); iOS, Android and Flutter after the user taps Apply; web in the success message. The raw validateCode result always carries the creator's name in influencer.name and in message — keep those off screen in your own UI too.

React Native

TSX
import { ReferralCodeInput } from '@influto/react-native-sdk/ui';

<ReferralCodeInput
  appUserId={userId}
  labels={{ title: 'Got a code?', validateButton: 'Apply' }}
  colors={{ primary: '#111827' }}
  onApplied={(result) => {
    if (result.campaign?.campaign_type === 'FREE_ACCESS') refreshPremium();
  }}
  onSkip={() => navigation.navigate('Paywall')}
/>
Prop Type Default What it does
appUserId string identified user Passed to setReferralCode. Free-access codes need a user.
autoPrefill boolean true Fills in the code when the install is attributed.
autoValidate boolean false Checks (and so applies) a prefilled code on mount.
validateOnBlur boolean true Checks the code when the field loses focus. A valid code is applied right away.
showSkipButton boolean true Shows a Skip button — only when onSkip is also set.
showCampaignName boolean false See Privacy defaults.
showReferrerName boolean false See Privacy defaults. Also swaps the success text for the server's "Valid code! Referred by …".
onValidated (result: CodeValidationResult) => void — After every check, valid or not (including network errors).
onApplied (result: CodeValidationResult) => void — After a valid code was applied. Receives the validation result.
onSkip () => void — When the user taps Skip.
colors, fonts, labels, style objects see below Theming.

Codes shorter than 4 characters are rejected in the component with INVALID_FORMAT before any request.

Theming

colors key Default
primary #3B82F6 (button, prefilled hint)
success #10B981
error #EF4444
text #1F2937
textSecondary #6B7280
border #D1D5DB
inputBackground #F9FAFB
background #FFFFFF — accepted but not applied; set style.container.backgroundColor instead
fonts key Default
family System on iOS, Roboto on Android
sizeTitle 18
sizeInput 16
sizeButton 16
sizeMessage 14
labels key Default
title Have a promo code?
subtitle Add the code you received from a creator or friend
placeholder Enter code (e.g., FITGURU30)
validateButton Apply Code
skipButton Skip
validatingMessage Validating code...
validMessage Code applied successfully!
invalidMessage Invalid code. Please try again.
errorMessage Unable to validate code. Check your connection.
prefilledMessage Code detected from your referral link

style takes React Native styles for container, titleContainer, title, subtitle, inputContainer, input, buttonContainer, validateButton, validateButtonText, skipButton, skipButtonText, messageContainer and messageText. They're applied on top of the defaults; the container is a white card with 20 pt padding, rounded corners and a shadow.

iOS (SwiftUI)

Swift
import SwiftUI
import InfluTo

struct CodeStep: View {
    let userID: String?

    var body: some View {
        InfluToReferralCodeInput(
            appUserId: userID,
            title: "Got a code?",
            onApplied: { result in
                if result.campaign?.campaignType == "FREE_ACCESS" { refreshPremium() }
            }
        )
    }
}
Parameter Type Default What it does
appUserId String? identified user Passed to applyCode. Free-access codes need a user.
autoPrefill Bool true Fills in the code when the install is attributed.
autoValidate Bool false Checks a prefilled code right away.
showCampaignName Bool false See Privacy defaults.
showReferrerName Bool false See Privacy defaults.
title String? nil Optional heading above the field.
labels InfluToReferralCodeInput.Labels see below Texts.
onValidated ((CodeValidationResult) -> Void)? nil After every check.
onApplied ((CodeValidationResult) -> Void)? nil After the user taps Apply and the code was recorded (result.applied is true).

Labels has four vars: placeholder (Referral code), apply (Apply), valid (Code applied) and invalid (This code isn't valid):

Swift
var labels = InfluToReferralCodeInput.Labels()
labels.placeholder = "Promo code"
labels.apply = "Use code"

It's built from a standard TextField, Button and system text styles, with green and red for the valid and invalid states. Style the surrounding view with ordinary SwiftUI modifiers.

Android (Jetpack Compose)

build.gradle.kts
dependencies {
    implementation("to.influ:android-sdk:1.1.1")
    implementation("to.influ:android-sdk-ui:1.1.1")
}
Kotlin
import to.influ.sdk.ui.InfluToReferralCodeInput

InfluToReferralCodeInput(
    appUserId = userId,
    title = "Got a code?",
    onApplied = { result ->
        if (result.campaign?.campaignType == "FREE_ACCESS") refreshPremium()
    },
)
Parameter Type Default What it does
modifier Modifier Modifier Applied to the column that holds the field.
appUserId String? identified user Passed to applyCode. Free-access codes need a user.
autoPrefill Boolean true Fills in the code when the install is attributed.
autoValidate Boolean false Checks a prefilled code right away.
showCampaignName Boolean false See Privacy defaults.
showReferrerName Boolean false See Privacy defaults.
title String? null Optional heading.
placeholder String "Referral code" The field's label.
applyLabel String "Apply" Button text.
validMessage String "Code applied" Shown under a valid code.
invalidMessage String "This code isn't valid" Shown when the server gives no error text. An expired free-access code shows "This code has expired".
onValidated (CodeValidationResult) -> Unit {} After every check.
onApplied (CodeValidationResult) -> Unit {} After the user taps Apply and the code was recorded (result.applied is true).

It's built from Material 3 OutlinedTextField and Button, so it follows your MaterialTheme.

Flutter

Dart
import 'package:influto/influto.dart';

ReferralCodeInput(
  appUserId: userId,
  title: 'Got a code?',
  onApplied: (result) {
    if (result.campaign?.campaignType == 'FREE_ACCESS') refreshPremium();
  },
)
Parameter Type Default What it does
appUserId String? identified user Passed to applyCode. Free-access codes need a user.
autoPrefill bool true Fills in the code when the install is attributed.
autoValidate bool false Checks a prefilled code right away.
showCampaignName bool false See Privacy defaults.
showReferrerName bool false See Privacy defaults.
title String? null Optional heading.
placeholder String 'Referral code' The field's label.
applyLabel String 'Apply' Button text.
validMessage String 'Code applied' Helper text under a valid code.
invalidMessage String "This code isn't valid" Shown when the server gives no error text.
onValidated ValueChanged<CodeValidationResult>? null After every check.
onApplied ValueChanged<CodeValidationResult>? null After the user taps Apply and the code was recorded (result.applied is true).

It uses a Material TextField with an outlined border and an ElevatedButton, so it follows your ThemeData.

Web (React)

@influto/web/react works in React and Ionic React apps.

TSX
import { ReferralCodeInput, useInfluToAttribution } from '@influto/web/react';

function CodeStep({ ready, userId }: { ready: boolean; userId?: string }) {
  const { loading, attribution } = useInfluToAttribution(ready);
  if (loading) return null;

  return (
    <>
      {attribution?.attributed && <p>Your creator's offer is applied.</p>}
      <ReferralCodeInput
        appUserId={userId}
        className="code-form"
        onCodeApplied={(code, result) => {
          if (result.campaign?.campaign_type === 'FREE_ACCESS') refreshPremium();
        }}
      />
    </>
  );
}

ReferralCodeInput

Prop Type Default What it does
appUserId string — Passed to applyCode. Without it, free-access codes use the ID from identifyUser.
prefill boolean true Fills in the code when the install is attributed.
showCampaignName boolean false See Privacy defaults.
showReferrerName boolean false See Privacy defaults.
placeholder string 'Referral or access code' Input placeholder.
buttonLabel string 'Apply' Submit button text (shows … while checking).
onCodeApplied (code, result) => void — After the code was applied. result is the applyCode result.
onInvalid (result) => void — When the code was rejected, or valid but couldn't be applied.
className, style string, CSSProperties — On the <form>.
inputClassName, buttonClassName string — On the input and the button.
sdk InfluToWebSDK default instance Use an instance from createInfluTo().

It renders an unstyled <form> with an input, a submit button and, after a submit, a <span role="status"> with Code applied or the error (Invalid code when the server gives none). Style it with your classes, or target the attributes it sets: data-influto-status on the form (idle, checking, valid, invalid) and data-influto-message on the message.

useInfluToAttribution

useInfluToAttribution(enabled = true, sdk = InfluTo) runs checkAttribution() once and returns loading, attribution (an AttributionResult or null), error and refresh(). Pass enabled = false until initialize() has resolved — before that, checkAttribution throws and the hook reports it as error.

Build your own field

For your own design or fully localized messages, use the SDK calls directly: check the code with validateCode while the user types (debounced), and apply it with applyCode when they submit.

TSX
// While typing (debounced): show valid / invalid only
const check = await InfluTo.validateCode(text);
setValid(check.valid);

// On submit
const result = await InfluTo.applyCode(text, userId);
if (!result.applied) showError(result.error_code);
else if (result.campaign?.campaign_type === 'FREE_ACCESS' && (await InfluTo.checkAccess(userId)).hasAccess) unlockPremium();
Swift
// While typing (debounced): show valid / invalid only
let check = await InfluTo.validateCode(text)
isValid = check.valid

// On submit
let result = await InfluTo.applyCode(text, appUserId: userID)
if result.applied != true {
    showError(result.errorCode)
} else if result.campaign?.campaignType == "FREE_ACCESS" {
    let access = await InfluTo.checkAccess(appUserId: userID)
    if access.hasAccess { unlockPremium() }
}
Kotlin
// While typing (debounced): show valid / invalid only
val check = InfluTo.validateCode(text)
isValid = check.valid

// On submit
val result = InfluTo.applyCode(text, userId)
if (result.applied != true) showError(result.errorCode)
else if (result.campaign?.campaignType == "FREE_ACCESS" && InfluTo.checkAccess(userId).hasAccess) unlockPremium()
Dart
// While typing (debounced): show valid / invalid only
final check = await InfluTo.instance.validateCode(text);
setState(() => isValid = check.valid);

// On submit
final result = await InfluTo.instance.applyCode(text, appUserId: userId);
if (result.applied != true) {
  showError(result.errorCode);
} else if (result.campaign?.campaignType == 'FREE_ACCESS' &&
    (await InfluTo.instance.checkAccess(appUserId: userId)).hasAccess) {
  unlockPremium();
}
TypeScript
// While typing (debounced): show valid / invalid only
const check = await InfluTo.validateCode(text);
setValid(check.valid);

// On submit
const result = await InfluTo.applyCode(text, userId);
if (!result.applied) showError(result.error_code);
else if (result.campaign?.campaign_type === 'FREE_ACCESS' && (await InfluTo.checkAccess(userId)).hasAccess) unlockPremium();
  • Uppercase the input and keep only A–Z, 0–9, _ and -, 4–20 characters (code rules). The SDK only trims and uppercases, and the code it stores and writes to RevenueCat is the one you pass — so a stray space or invisible character from a pasted caption must be removed here.
  • Map error_code / errorCode (INVALID_FORMAT, CODE_NOT_FOUND, CODE_EXPIRED, NETWORK_ERROR) to your own localized text. applied can also be false for a valid code, for example a free-access code without a user ID.
  • applyCode binds the code to the user from identifyUser, or the user ID you pass; free-access codes need one.
  • Don't display influencer or message unless your creators agreed to be named.
  • Gate premium on your store entitlement or checkAccess().hasAccess, not on the code result alone.