Overview
The Vouch React Native SDK provides email validation and device fingerprinting for React Native applications. It bridges to native iOS (Swift) and Android (Kotlin) SDKs for optimal signal collection and performance.
Package: @vouch/react-native
Platform: iOS 15.0+ & Android 8.0+ (API 26+)
React Native: 0.60.0+
Distribution: npm/yarn/pnpm
Installation
npm install @vouch/react-native
iOS Setup
Install iOS dependencies:
Android Setup
No additional setup required. The SDK includes all necessary native modules.
Permissions
Add internet permission to your AndroidManifest.xml (Android only):
<uses-permission android:name="android.permission.INTERNET" />
No permissions required on iOS. The SDK only needs internet access on Android.
Quick Start
Wrap Your App
Wrap your app with VouchProvider:
import { VouchProvider } from '@vouch/react-native';
export default function App() {
return (
<VouchProvider
projectId="your-project-id"
apiKey="your-client-api-key"
>
<YourApp />
</VouchProvider>
);
}
Validate Email
Use the useValidateEmail hook:
import { useValidateEmail } from '@vouch/react-native';
import { View, TextInput, Button, Text } from 'react-native';
import { useState } from 'react';
function EmailForm() {
const { validate, loading, result } = useValidateEmail();
const [email, setEmail] = useState('');
const handleSubmit = async () => {
const result = await validate(email);
if (result.success && result.valid) {
console.log('✓ Valid email');
} else {
console.log('✗ Invalid email:', result.error);
}
};
return (
<View>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email address"
keyboardType="email-address"
autoCapitalize="none"
editable={!loading}
/>
<Button
title={loading ? 'Validating...' : 'Validate'}
onPress={handleSubmit}
disabled={loading}
/>
{result && (
<Text>{result.success ? '✓ Valid' : `✗ ${result.error}`}</Text>
)}
</View>
);
}
Hooks
useValidateEmail
Hook for email validation with loading and error states:
import { useValidateEmail } from '@vouch/react-native';
import { View, TextInput, Button, Text, ActivityIndicator } from 'react-native';
import { useState } from 'react';
function SignUpForm() {
const { validate, loading, result, error, reset } = useValidateEmail();
const [email, setEmail] = useState('');
const handleValidate = async () => {
const result = await validate(email);
if (result.success && result.valid) {
// Proceed with sign-up
console.log('Valid email:', result.email);
}
};
return (
<View style={{ padding: 20 }}>
<TextInput
value={email}
onChangeText={(text) => {
setEmail(text);
reset(); // Clear previous results
}}
placeholder="Enter your email"
keyboardType="email-address"
autoCapitalize="none"
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
borderRadius: 5,
}}
/>
<Button
title={loading ? 'Validating...' : 'Sign Up'}
onPress={handleValidate}
disabled={loading || !email}
/>
{loading && <ActivityIndicator style={{ marginTop: 10 }} />}
{result && !loading && (
<Text
style={{
marginTop: 10,
color: result.success && result.valid ? 'green' : 'red',
}}
>
{result.success && result.valid
? '✓ Email is valid'
: `✗ ${result.error || 'Invalid email'}`}
</Text>
)}
</View>
);
}
Returns:
Current validation result (null if not validated yet)
Whether a validation request is in progress
Error that occurred during validation
validate
(email: string) => Promise<ValidationResult>
Function to validate an email address
Reset the validation state
useFingerprint
Hook to generate device fingerprint:
import { useFingerprint } from '@vouch/react-native';
import { View, Button, Text, ScrollView } from 'react-native';
function DeviceInfo() {
const { fingerprint, loading, error, generate } = useFingerprint();
return (
<View style={{ padding: 20 }}>
<Button
title={loading ? 'Generating...' : 'Generate Fingerprint'}
onPress={generate}
disabled={loading}
/>
{error && <Text style={{ color: 'red' }}>Error: {error.message}</Text>}
{fingerprint && (
<ScrollView style={{ marginTop: 20 }}>
<Text>Device: {fingerprint.hardware.deviceModel}</Text>
<Text>Screen: {fingerprint.hardware.screenWidth}x{fingerprint.hardware.screenHeight}</Text>
<Text>OS: {fingerprint.system.osVersion}</Text>
<Text>Fonts: {fingerprint.fonts.fonts.length}</Text>
</ScrollView>
)}
</View>
);
}
Returns:
Generated device fingerprint (null if not generated yet)
Whether fingerprint generation is in progress
Error that occurred during generation
generate
() => Promise<Fingerprint>
Function to generate device fingerprint
useVouch
Hook to access the Vouch instance directly:
import { useVouch } from '@vouch/react-native';
function CustomComponent() {
const vouch = useVouch();
const handleCustomValidation = async () => {
const result = await vouch.validate('[email protected]');
console.log(result);
const fingerprint = await vouch.generateFingerprint();
console.log(fingerprint);
};
return (
<Button title="Custom Validation" onPress={handleCustomValidation} />
);
}
Returns: Vouch instance
Advanced Usage
Real-Time Validation
Validate as the user types with debouncing:
import { useValidateEmail } from '@vouch/react-native';
import { View, TextInput, Text } from 'react-native';
import { useState, useEffect, useRef } from 'react';
function RealtimeEmailInput() {
const { validate, loading, result } = useValidateEmail();
const [email, setEmail] = useState('');
const timeoutRef = useRef<NodeJS.Timeout>();
useEffect(() => {
if (!email) return;
// Clear previous timeout
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
// Debounce validation
timeoutRef.current = setTimeout(() => {
validate(email);
}, 500);
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [email]);
return (
<View style={{ padding: 20 }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email address"
keyboardType="email-address"
autoCapitalize="none"
style={{
flex: 1,
borderWidth: 1,
borderColor: result?.valid ? 'green' : '#ccc',
padding: 10,
borderRadius: 5,
}}
/>
{loading && <Text>⏳</Text>}
{result?.valid && !loading && <Text>✓</Text>}
{result && !result.valid && !loading && <Text>✗</Text>}
</View>
{result && !result.valid && !loading && (
<Text style={{ color: 'red', marginTop: 5 }}>
{result.error}
</Text>
)}
</View>
);
}
Custom Options
Configure the SDK with custom options:
import { VouchProvider } from '@vouch/react-native';
export default function App() {
return (
<VouchProvider
projectId="your-project-id"
apiKey="your-client-api-key"
options={{
endpoint: 'https://api.vouch.expert',
version: 1, // Use /v1/ endpoint
fingerprintOptions: {
enableFonts: true,
},
}}
>
<YourApp />
</VouchProvider>
);
}
Integrate with popular form libraries:
import { useValidateEmail } from '@vouch/react-native';
import { View, TextInput, Button, Text } from 'react-native';
import { useState } from 'react';
function RegistrationForm() {
const { validate, loading } = useValidateEmail();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [emailError, setEmailError] = useState<string | null>(null);
const [formSubmitting, setFormSubmitting] = useState(false);
const handleSubmit = async () => {
setFormSubmitting(true);
setEmailError(null);
// Validate email first
const result = await validate(email);
if (!result.success || !result.valid) {
setEmailError(result.error || 'Invalid email');
setFormSubmitting(false);
return;
}
// Proceed with registration
try {
await registerUser(email, password);
console.log('Registration successful');
} catch (error) {
console.error('Registration failed:', error);
} finally {
setFormSubmitting(false);
}
};
return (
<View style={{ padding: 20 }}>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
style={{
borderWidth: 1,
borderColor: emailError ? 'red' : '#ccc',
padding: 10,
borderRadius: 5,
marginBottom: 10,
}}
/>
{emailError && (
<Text style={{ color: 'red', marginBottom: 10 }}>{emailError}</Text>
)}
<TextInput
value={password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
borderRadius: 5,
marginBottom: 20,
}}
/>
<Button
title={loading || formSubmitting ? 'Submitting...' : 'Register'}
onPress={handleSubmit}
disabled={loading || formSubmitting || !email || !password}
/>
</View>
);
}
async function registerUser(email: string, password: string) {
// Your registration logic here
}
API Reference
VouchProvider
Provider component that initializes the Vouch SDK.
<VouchProvider
projectId="your-project-id"
apiKey="your-client-api-key"
options={{
endpoint: "https://api.vouch.expert",
version: 1,
fingerprintOptions: { enableFonts: true },
}}
>
{children}
</VouchProvider>
Props:
Your Vouch client API key
Optional SDK configuration
ValidationResult
Email validation response:
interface ValidationResult {
success: boolean; // Whether the API call was successful
valid?: boolean; // Whether the email is valid
email?: string; // Normalized email address
error?: string; // Error message if validation failed
data?: any; // Complete server response data
statusCode?: number; // HTTP status code
}
Fingerprint
Device fingerprint data:
interface Fingerprint {
hardware: HardwareSignals; // Device hardware info
fonts: FontSignals; // System fonts
system: SystemSignals; // OS info (BrowserSignals on iOS/Android)
storage: StorageSignals; // Storage availability
timestamp: number; // Unix timestamp (ms)
version: string; // SDK version
}
iOS
- No permissions required
- Uses native Swift SDK for fingerprinting
- Font collection takes ~200-1000ms (can be disabled)
- Supports iOS 15.0+
Android
- Requires INTERNET permission
- Uses native Kotlin SDK for fingerprinting
- Font collection takes ~200-1000ms (can be disabled)
- Supports Android 8.0+ (API 26+)
- ProGuard/R8 compatible (rules included automatically)
Error Handling
Always handle validation errors gracefully:
const { validate, loading, result, error } = useValidateEmail();
const handleValidate = async () => {
const result = await validate(email);
if (error) {
// Network or SDK error
console.error('Validation error:', error);
showToast('Validation unavailable, please try again');
return;
}
if (!result.success || !result.valid) {
// Email is invalid
showError(result.error || 'Please check your email');
return;
}
// Email is valid
proceedWithSignup();
};
- Fingerprint Generation: ~100-500ms (first time)
- Email Validation: Instant local validation + network request time
- Font Collection: ~200-1000ms (can be disabled)
The SDK starts fingerprint generation when VouchProvider mounts, so the first validation can reuse the cached fingerprint.
Privacy & Permissions
Data Collection
The SDK collects device fingerprint data for fraud prevention. You must disclose this in:
- Your app’s privacy policy
- App Store privacy nutrition label (iOS)
- Google Play Data Safety form (Android)
- GDPR/CCPA notices (if applicable)
What data is collected:
- Hardware signals: Screen dimensions, CPU cores, memory, device model
- Font signals: System fonts and SHA-256 hash
- System signals: OS version, language, locale, timezone
- Storage signals: Storage availability checks
No personally identifiable information (PII) is collected. All data is technical device and system information.
Best Practices
1. Initialize Early
Place VouchProvider at the top level of your app:
// ✓ Good - Top level
<VouchProvider projectId="..." apiKey="...">
<NavigationContainer>
<App />
</NavigationContainer>
</VouchProvider>
// ✗ Bad - Too deep
<NavigationContainer>
<VouchProvider projectId="..." apiKey="...">
<App />
</VouchProvider>
</NavigationContainer>
2. Handle Errors Gracefully
Don’t block users due to validation failures:
const result = await validate(email);
if (!result.success || !result.valid) {
// Show error but allow retry
showError(result.error || 'Please check your email');
} else {
// Proceed
submitForm();
}
3. Use Debouncing for Real-Time Validation
Avoid excessive API calls:
useEffect(() => {
const timeout = setTimeout(() => {
if (email) validate(email);
}, 500); // 500ms debounce
return () => clearTimeout(timeout);
}, [email]);
Support
For issues and questions: