
Security News
/Company News
Securing the Financial Frontier: How Capital One Uses Socket for Open Source Security
Capital One is partnering with Socket to proactively secure its open source supply chain.
react-sms-otp
Advanced tools
React SMS OTP — Twilio alternative for developers. Send + verify OTP codes from React, plus a polished <OtpInput /> ready-to-use UI (separators, RTL, mask, render props, error states). Drop-in <OtpForm /> for full phone-verification flow. useSms8Otp() hoo
Send and verify SMS OTP codes from React — useSms8Otp() hook, <OtpForm /> drop-in, and <OtpInput /> six-box code field. Routes through your own Android phone. No Twilio, no Vonage Verify, no MessageBird Verify. No per-OTP fees. No markups.
import { OtpForm } from 'react-sms-otp';
<OtpForm
apiKey={process.env.NEXT_PUBLIC_SMS8_API_KEY!}
onVerified={(phone) => router.push('/dashboard')}
/>
Get a free API key at sms8.io — 5-day trial, no credit card.
| Twilio Verify / Vonage Verify | react-sms-otp + SMS8 | |
|---|---|---|
| Per-OTP cost | $0.05 – $0.10 each | $0 (flat $29/mo unlimited) |
| A2P 10DLC paperwork | Required for any US OTP volume | Not required — P2P SMS from a real SIM |
| Sender ID | Short code or random LCN | Your real mobile number |
| Reply support | Extra fees, harder to wire up | Built-in — replies sync into your dashboard |
| Setup time | Days (brand registration, A2P review) | Minutes (pair Android, paste API key) |
| Free trial | Pay-as-you-go from message 1 | 5 days unlimited, no card required |
npm install react-sms-otp
# or
pnpm add react-sms-otp
# or
yarn add react-sms-otp
Works with React 17+, including Next.js 13/14/15 (App Router or Pages Router), Remix, Vite, CRA. Server-side calls (route handlers, server actions, edge functions) can use the Sms8Otp class without React.
import { OtpForm } from 'react-sms-otp';
export default function LoginPage() {
return (
<OtpForm
apiKey={process.env.NEXT_PUBLIC_SMS8_API_KEY!}
onVerified={(phone) => {
console.log('Verified:', phone);
// redirect, create session, etc.
}}
/>
);
}
That's the entire phone-verification flow. The form handles phone input → send → 6-box code input → verify → success state. iOS SMS auto-fill and Android SMS Retriever work because the inputs use autoComplete="one-time-code" and inputMode="numeric".
Tip: in production, never expose your API key to the browser. Proxy through your backend (Next.js route handler, Remix loader, Express endpoint) and call the Sms8Otp class from there.
useSms8Otp(opts) hook — full controlimport { useSms8Otp, OtpInput } from 'react-sms-otp';
function CustomLogin() {
const { send, verify, status, error, reset } = useSms8Otp({
apiKey: process.env.NEXT_PUBLIC_SMS8_API_KEY!,
});
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
return (
<>
<input
type="tel"
autoComplete="tel"
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
<button onClick={() => send({ phone })} disabled={status === 'sending'}>
{status === 'sending' ? 'Sending…' : 'Send code'}
</button>
{status === 'sent' && (
<OtpInput
length={6}
value={code}
onChange={setCode}
onComplete={(c) => verify({ phone, code: c })}
/>
)}
{status === 'verified' && <p>Welcome!</p>}
{error && <p style={{ color: 'red' }}>{error}</p>}
</>
);
}
Status values: idle | sending | sent | verifying | verified | error.
<OtpForm /> drop-in component<OtpForm
apiKey="sk_xxx"
phone="+14155550100" // optional, hides the phone input
length={6} // 4 to 8
sendOptions={{
template: 'Your YourApp code: {code}',
expiresIn: 300,
maxAttempts: 5,
deviceId: 10700, // pin a specific paired phone
simSlot: '1', // multi-SIM Android
}}
onVerified={(phone) => { /* success */ }}
onFailed={(error) => { /* retried too many times */ }}
labels={{
phone: 'Mobile number',
sendButton: 'Text me a code',
code: 'Enter the 6 digits',
verifyButton: 'Confirm',
}}
/>
<OtpInput /> ready-to-use OTP input UIA polished N-box OTP input you can drop into any auth flow — even if you already have your own send/verify logic with Twilio, Auth0, Supabase, or Clerk. Use it standalone as a pure UI component.
Features at parity with react-otp-input and more:
inputMode="numeric" + autoComplete="one-time-code" triggers iOS "From Messages" suggestion<OtpInput renderSeparator={(i) => i === 2 ? <span>-</span> : null} />rtl prop swaps direction for Arabic / Hebrewmask shows • instead of digits (useful in shared screens)error prop adds red border, sets aria-invalidrenderInput={(props, state) => ...}inputClassName, focusedClassName, filledClassName, errorClassNamearia-label per box, role="group" on containerOtpInputState, OtpInputProps, OtpRenderInputProps typesBasic usage:
import { OtpInput } from 'react-sms-otp';
<OtpInput
length={6}
value={code}
onChange={setCode}
onComplete={(c) => submitVerify(c)}
/>
With separator (e.g. 123-456 style):
<OtpInput
length={6}
value={code}
onChange={setCode}
renderSeparator={(i) => i === 2 ? <span style={{margin:'0 4px'}}>—</span> : null}
/>
Masked / hidden code:
<OtpInput length={6} value={code} onChange={setCode} mask />
RTL (Arabic, Hebrew):
<OtpInput length={6} value={code} onChange={setCode} rtl />
Error state:
<OtpInput length={6} value={code} onChange={setCode} error={!!verifyError} />
Full custom render with Tailwind / shadcn:
<OtpInput
length={6}
value={code}
onChange={setCode}
renderInput={(props, { focused, error }) => (
<input
{...props}
className={`
w-12 h-14 text-center text-xl font-bold border-2 rounded-lg
${focused ? 'border-indigo-500 ring-2 ring-indigo-200' : 'border-gray-200'}
${error ? 'border-red-500 bg-red-50' : ''}
`}
/>
)}
/>
Works with your own send/verify — drop it into a Clerk, Auth0, Supabase, or custom-backed OTP flow:
const [code, setCode] = useState('');
<OtpInput
length={6}
value={code}
onChange={setCode}
onComplete={async (c) => {
const ok = await yourBackend.verifyCode(phone, c);
if (ok) router.push('/dashboard');
}}
/>
Sms8Otp class — server-side / non-React// app/api/send-otp/route.ts (Next.js App Router)
import { Sms8Otp } from 'react-sms-otp';
export async function POST(req: Request) {
const { phone } = await req.json();
const otp = new Sms8Otp({ apiKey: process.env.SMS8_API_KEY! });
const result = await otp.send({ phone, length: 6 });
return Response.json(result);
}
// Server route handler (Next.js, Remix, etc.)
import { Sms8Otp } from 'react-sms-otp';
const otp = new Sms8Otp({ apiKey: process.env.SMS8_API_KEY! });
export async function sendOtp(phone: string) {
'use server';
return otp.send({ phone, length: 6 });
}
// Client component — call your server action, not SMS8 directly
'use client';
import { useState } from 'react';
import { OtpInput } from 'react-sms-otp';
import { sendOtp, verifyOtp } from './actions';
export function PhoneVerify() {
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [stage, setStage] = useState<'phone' | 'code'>('phone');
return stage === 'phone' ? (
<>
<input value={phone} onChange={(e) => setPhone(e.target.value)} />
<button onClick={async () => { await sendOtp(phone); setStage('code'); }}>
Send code
</button>
</>
) : (
<OtpInput
length={6}
value={code}
onChange={setCode}
onComplete={async (c) => {
const result = await verifyOtp(phone, c);
if (result.verified) router.push('/welcome');
}}
/>
);
}
The <OtpInput /> and <OtpForm /> components both set:
autoComplete="one-time-code" — triggers iOS SMS auto-fill suggestion above the keyboardinputMode="numeric" — shows the number pad on mobilepattern="[0-9]*" — extra hint for older keyboardsFor Android SMS Retriever API (auto-read without user pasting), you need a server-side hash appended to the SMS body. SMS8 supports this via the template option:
<OtpForm
apiKey="sk_xxx"
sendOptions={{
template: '<#> Your YourApp code: {code}\n\nABcd1234efg', // <-- 11-char app hash at end
}}
/>
See Google's SMS Retriever docs for hash generation.
sms8-cli — terminal CLI (same backend)sms8-mcp — MCP launcher for Claude Code / Cursor / Windsurfsms-otp-using-myphone — OTP-focused CLIphone-sms-gateway — phone-as-gateway CLIsend-sms-from-android — Android-first CLIMIT
FAQs
React SMS OTP — Twilio alternative for developers. Send + verify OTP codes from React, plus a polished <OtpInput /> ready-to-use UI (separators, RTL, mask, render props, error states). Drop-in <OtpForm /> for full phone-verification flow. useSms8Otp() hoo
The npm package react-sms-otp receives a total of 34 weekly downloads. As such, react-sms-otp popularity was classified as not popular.
We found that react-sms-otp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
/Company News
Capital One is partnering with Socket to proactively secure its open source supply chain.

Security News
Socket CTO Ahmad Nassri discusses how to keep AI agents from bypassing package blocks, limit credential access, and monitor their actions.

Security News
GPT-6 Astra tried to plant malicious code in simulated open source projects using fake GitHub accounts and deceptive PRs during an assigned CTF challenge.