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
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)
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):
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)
dependencies {
implementation("to.influ:android-sdk:1.1.1")
implementation("to.influ:android-sdk-ui:1.1.1")
}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
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.
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.
// 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();// 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() }
}// 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()// 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();
}// 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.appliedcan also be false for a valid code, for example a free-access code without a user ID. applyCodebinds the code to the user fromidentifyUser, or the user ID you pass; free-access codes need one.- Don't display
influencerormessageunless your creators agreed to be named. - Gate premium on your store entitlement or
checkAccess().hasAccess, not on the code result alone.