otpless-headless-js
v1.0.5
Published
OTPless Headless SDK for JS framework.
Maintainers
Readme
OTPless Headless
A lightweight JavaScript SDK wrapper for OTPless Headless that provides seamless OTP authentication with WhatsApp, SMS, and email. Works with React, Vue.js, Next.js, and any JavaScript framework.
Features
- 🚀 Tiny Bundle - Only 3.6KB minified
- 🎯 Framework Agnostic - Works with React, Vue, Next.js, and any JS framework
- 📱 Phone Authentication - SMS OTP with country code support
- 🔄 Loading States - Built-in loading management
- 🎪 Event System - Listen to authentication events
- 🛡️ Type Safe - Full TypeScript support
- 🌐 SSR Ready - Works with Next.js and other SSR frameworks
Demo
Explore the live demo repository to see OTPless Headless in action:
https://github.com/otpless-tech/web-headless-demo
Installation
npm install otpless-headless-js
# or
yarn add otpless-headless-js
# or
pnpm add otpless-headless-jsQuick Start
import { useEffect } from 'react';
import { useOTPless, CHANNELS, EVENT_TYPES } from 'otpless-headless-js';
function MyComponent() {
const { init, initiate, verify, on, loading, ready } = useOTPless();
useEffect(() => {
// Initialize with your OTPless App ID
init('YOUR_APP_ID');
// Listen to a single event
const unsubscribe = on(EVENT_TYPES.OTP_AUTO_READ, (event) => {
const autoOtp = event?.response?.otp ?? '';
console.log('OTP auto-read:', autoOtp);
});
// Listen to multiple events at once
const unsubscribeAll = on({
[EVENT_TYPES.ONETAP]: (event) => {
console.log('Auth success:', event);
},
[EVENT_TYPES.OTP_AUTO_READ]: (event) => {
const autoOtp = event?.response?.otp ?? '';
console.log('OTP auto-read:', autoOtp);
},
[EVENT_TYPES.FAILED]: (event) => {
console.error('Failed:', event.response?.errorMessage);
},
});
return () => {
unsubscribe();
unsubscribeAll();
};
}, [init, on]);
const initiateAuth = async () => {
if (!ready) {
console.log('SDK not ready yet');
return;
}
try {
const result = await initiate({
channel: CHANNELS.PHONE,
phone: '9876543210',
countryCode: '+91',
});
if (result.success) {
console.log('OTP sent successfully:', result);
} else {
console.error('Failed to send OTP:', result.response?.errorMessage);
}
} catch (error) {
console.error('Failed to send OTP:', error);
}
};
const verifyAuth = async () => {
if (!ready) {
console.log('SDK not ready yet');
return;
}
try {
const result = await verify({
channel: CHANNELS.PHONE,
phone: '9876543210',
otp: '123456',
countryCode: '+91',
});
if (result.success) {
console.log('OTP verified successfully:', result);
// User is authenticated - proceed with your app logic
} else {
console.error('OTP verification failed:', result.response?.errorMessage);
}
} catch (error) {
console.error('Verification failed:', error);
}
};
if (!ready) {
return <div>Loading OTPless SDK...</div>;
}
return (
<div>
<button onClick={initiateAuth} disabled={loading}>
{loading ? 'Sending...' : 'Send OTP'}
</button>
<button onClick={verifyAuth} disabled={loading}>
{loading ? 'Verifying...' : 'Verify OTP'}
</button>
</div>
);
}API Reference
useOTPless()
Returns an object with the following properties:
type UseOTPless = () => {
ready: boolean;
loading: boolean;
init(appId: string): Promise<void>;
initiate(request: InitiateRequest): Promise<OTPlessResponse>;
verify(request: VerifyRequest): Promise<OTPlessResponse>;
on(
event: EventType | Record<EventType, Function>,
callback?: Function
): () => void;
off(event: EventType, callback: Function): void;
};| Property | Type | Description |
| --- | --- | --- |
| ready | boolean | Whether the OTPless SDK script is loaded and ready. |
| loading | boolean | True while an operation is in progress (init/initiate/verify). |
| init(appId) | Promise<void> | Initialize the SDK with your App ID. Call this once. |
| initiate(request) | Promise<OTPlessResponse> | Send OTP (e.g., via CHANNELS.PHONE). |
| verify(request) | Promise<OTPlessResponse> | Verify the OTP received by the user. |
| on(event, callback?) | () => void | Subscribe to events. Accepts a single EventType or a map of { [EventType]: handler }. Returns an unsubscribe function. |
| off(event, callback) | void | Remove a previously registered listener. |
Types and Constants
This package exports TypeScript types and enum-like constants for safer usage:
import type { InitiateRequest, VerifyRequest, EventType, OTPlessResponse } from 'otpless-headless-js';
import { CHANNELS, EVENT_TYPES } from 'otpless-headless-js';
// Example usage
const req: InitiateRequest = {
channel: CHANNELS.PHONE,
phone: '9876543210',
countryCode: '+91',
};
const onEvent = (type: EventType) => {
if (type === EVENT_TYPES.FAILED) {
console.error('Operation failed');
}
};Response Type
All OTPless API calls (initiate, verify) resolve to the same response shape:
type OTPlessResponsePayload = {
otp?: string;
token?: string;
[key: string]: any;
};
type OTPlessResponse = {
responseType: string;
response?: OTPlessResponsePayload;
success: boolean;
statusCode: number;
};Example:
const res: OTPlessResponse = await initiate({
channel: CHANNELS.PHONE,
phone: '9876543210',
countryCode: '+91',
});
if (res.success) {
console.log('requestId:', res.response?.requestID);
} else {
console.error('initiate failed:', res.response?.errorMessage);
}Framework-Agnostic Usage
This package works with any JavaScript framework. Here's how to use it without React hooks:
import { otpless, CHANNELS, EVENT_TYPES } from 'otpless-headless-js';
// Initialize
await otpless.init('YOUR_APP_ID');
// Send OTP
await otpless.initiate({
channel: CHANNELS.PHONE,
phone: '9876543210',
countryCode: '+91',
});
// Verify OTP
await otpless.verify({
channel: CHANNELS.PHONE,
phone: '9876543210',
countryCode: '+91',
otp: '123456',
});
// Listen to a single event
const unsubscribe = otpless.on(EVENT_TYPES.OTP_AUTO_READ, (event) => {
console.log('OTP auto-read:', event.response?.otp);
});
// Listen to multiple events at once
const unsubscribeAll = otpless.on({
[EVENT_TYPES.ONETAP]: (event) => console.log('Auth Success:', event),
[EVENT_TYPES.OTP_AUTO_READ]: (event) => console.log('Auto OTP:', event.response?.otp),
[EVENT_TYPES.FAILED]: (event) => console.error('Failed:', event.response?.errorMessage),
});Utility Functions
import { normalizeCountryCode, digitsOnly, redactTokens } from 'otpless-headless-js';
// Normalize country code
normalizeCountryCode('91'); // '+91'
normalizeCountryCode('+1-234'); // '+1234'
// Extract digits only
digitsOnly('98-765-43210'); // '9876543210'
// Redact sensitive data for logging
const safeData = redactTokens({
phone: '9876543210',
otp: '123456',
token: 'secret'
});
// { phone: '9876543210', otp: '***redacted***', token: '***redacted***' }Next.js Usage
'use client'; // Required for client components
import { useOTPless } from 'otpless-headless-js';
export default function AuthPage() {
const { ready, loading, init, initiate, verify } = useOTPless();
// ... rest of your component
{{ ... }}License
MIT
Support
For issues and questions, please visit the GitHub repository or contact [email protected].
