How to Send OTP in React Native (Expo) — 2026
React Native OTP tutorial using Expo and StartMessaging. Includes secure storage, auto-fill (Android SMS Retriever / iOS keychain), and a Node backend pattern.
Expo + React Native is a popular stack for Indian consumer apps. This tutorial wires StartMessaging via a small Node backend, with auto-fill and secure session storage.
Overview
- Backend: Express + StartMessaging.
- App: phone screen → OTP screen.
- Android SMS Retriever for auto-fill.
- Expo SecureStore for the JWT token.
Setup
npx create-expo-app otp-rn
cd otp-rn
npx expo install expo-secure-store expo-otp-input
npm install zustand
Login Screens
// App.tsx
import { useState } from 'react';
import { TextInput, Button, View } from 'react-native';
import { otp } from './src/otpService';
export default function App() {
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [requestId, setRequestId] = useState<string|null>(null);
return requestId === null ? (
<View><TextInput value={phone} onChangeText={setPhone} placeholder="+919876543210" />
<Button title="Send OTP" onPress={async () => setRequestId((await otp.send(phone)).requestId)} />
</View>
) : (
<View><TextInput value={code} onChangeText={setCode} keyboardType="number-pad" />
<Button title="Verify" onPress={() => otp.verify(requestId, code)} />
</View>
);
}
OTP Service
// src/otpService.ts
const BASE = 'https://your-backend.example.com';
export const otp = {
async send(phoneNumber: string) {
const r = await fetch(\`\${BASE}/auth/send-otp\`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phoneNumber }),
});
return r.json();
},
async verify(requestId: string, otpCode: string) {
const r = await fetch(\`\${BASE}/auth/verify-otp\`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ requestId, otpCode }),
});
return r.json();
},
};
OTP Auto-Fill
See our auto-fill guide for the SMS Retriever API setup. The SMS body must end with a Google-defined hash so the OS can attribute it.
Secure Token Storage
import * as SecureStore from 'expo-secure-store';
await SecureStore.setItemAsync('session', token);
FAQ
Flutter equivalent in our Flutter guide.
StartMessaging Team
StartMessaging Team