Developer Tutorials

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.

12 May 20269 min read

StartMessaging Team

Engineering

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

  1. Backend: Express + StartMessaging.
  2. App: phone screen → OTP screen.
  3. Android SMS Retriever for auto-fill.
  4. 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.

Ready to Send OTPs?

Integrate StartMessaging in 5 minutes. No DLT registration required.