Package Exports
- @saivarunvaidya/recaptcha-universal-sdk
- @saivarunvaidya/recaptcha-universal-sdk/angular
- @saivarunvaidya/recaptcha-universal-sdk/react
- @saivarunvaidya/recaptcha-universal-sdk/vanilla
- @saivarunvaidya/recaptcha-universal-sdk/vue
Readme
@recaptcha/universal-sdk
Framework-agnostic reCAPTCHA v2 SDK with adapters for React, Angular, Vue, and vanilla JavaScript
๐ฏ Features
- โ Framework-Agnostic Core - Pure TypeScript, zero dependencies
- โ Multiple Framework Adapters - React, Vue, Angular, Vanilla JS
- โ TypeScript First - Full type definitions included
- โ SSR Safe - Works with server-side rendering
- โ Tree-Shakeable - Only import what you need
- โ Production Ready - Comprehensive testing and error handling
- โ Backend Integration - Built-in verification service support
- โ reCAPTCHA v2 - Support for Checkbox and Invisible variants
๐ฆ Installation
npm install @recaptcha/universal-sdkOr with yarn:
yarn add @recaptcha/universal-sdk๐ Quick Start
React
import { useRecaptcha } from '@recaptcha/universal-sdk/react';
function MyForm() {
const { containerRef, token, isReady, verify } = useRecaptcha({
siteKey: 'your-site-key',
clientId: 'react-app',
verifyUrl: 'https://api.example.com/captcha/verify',
options: {
size: 'normal',
theme: 'light',
callback: (token) => console.log('Token:', token)
}
});
const handleSubmit = async () => {
if (token) {
const result = await verify();
console.log('Verified:', result.success);
}
};
return (
<div>
<div ref={containerRef}></div>
<button onClick={handleSubmit} disabled={!token}>
Submit
</button>
</div>
);
}Vue 3
<script setup>
import { useRecaptcha } from '@recaptcha/universal-sdk/vue';
const { containerRef, token, isReady, verify } = useRecaptcha({
siteKey: 'your-site-key',
clientId: 'vue-app',
verifyUrl: 'https://api.example.com/captcha/verify',
options: {
size: 'normal'
}
});
const handleSubmit = async () => {
if (token.value) {
const result = await verify();
console.log('Verified:', result.success);
}
};
</script>
<template>
<div>
<div ref="containerRef"></div>
<button @click="handleSubmit" :disabled="!token">Submit</button>
</div>
</template>Angular
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { RecaptchaService } from '@recaptcha/universal-sdk/angular';
@Component({
selector: 'app-form',
template: `
<div #recaptchaContainer></div>
<button (click)="handleSubmit()" [disabled]="!(token$ | async)">
Submit
</button>
`
})
export class FormComponent implements OnInit, AfterViewInit {
@ViewChild('recaptchaContainer', { static: false }) container!: ElementRef;
token$ = this.recaptchaService.token$;
constructor(private recaptchaService: RecaptchaService) {}
async ngOnInit() {
await this.recaptchaService.init({
siteKey: 'your-site-key',
clientId: 'angular-app',
verifyUrl: 'https://api.example.com/captcha/verify'
});
}
ngAfterViewInit() {
this.recaptchaService.render(this.container.nativeElement);
}
async handleSubmit() {
const result = await this.recaptchaService.verify();
console.log('Verified:', result.success);
}
}Vanilla JavaScript
import { VanillaRecaptcha } from '@recaptcha/universal-sdk/vanilla';
const recaptcha = new VanillaRecaptcha({
siteKey: 'your-site-key',
clientId: 'vanilla-app',
verifyUrl: 'https://api.example.com/captcha/verify',
options: {
size: 'normal',
callback: (token) => {
console.log('Token received:', token);
handleToken(token);
}
}
});
// Initialize
await recaptcha.init();
// Render
const container = document.getElementById('recaptcha-container');
recaptcha.render(container);
// Verify
async function handleToken(token) {
const result = await recaptcha.verify(token);
console.log('Verified:', result.success);
}๐ API Documentation
Core Configuration
interface RecaptchaConfig {
siteKey: string; // Your reCAPTCHA site key
clientId?: string; // Client ID for backend verification
verifyUrl?: string; // Backend verification endpoint
language?: string; // Language code (e.g., 'en', 'es')
options?: {
size?: 'normal' | 'compact' | 'invisible';
theme?: 'light' | 'dark';
badge?: 'bottomright' | 'bottomleft' | 'inline';
tabindex?: number;
callback?: (token: string) => void;
'expired-callback'?: () => void;
'error-callback'?: () => void;
};
}React Hook API
const {
containerRef, // Ref for the container element
execute, // Execute invisible reCAPTCHA
reset, // Reset the widget
getResponse, // Get current token
verify, // Verify token with backend
token, // Current token (reactive)
isReady, // Is reCAPTCHA loaded
isLoading, // Is loading
error, // Error message
widgetId // Widget ID
} = useRecaptcha(config);Vue Composable API
const {
containerRef, // Template ref for container
execute, // Execute invisible reCAPTCHA
reset, // Reset the widget
getResponse, // Get current token
verify, // Verify token with backend
token, // Current token (ref)
isReady, // Is reCAPTCHA loaded (ref)
isLoading, // Is loading (ref)
error, // Error message (ref)
widgetId // Widget ID (ref)
} = useRecaptcha(config);Angular Service API
class RecaptchaService {
token$: Observable<string | null>;
isReady$: Observable<boolean>;
isLoading$: Observable<boolean>;
error$: Observable<string | null>;
async init(config: RecaptchaConfig): Promise<void>;
render(container: HTMLElement, config?: RecaptchaConfig): number;
execute(): void;
reset(): void;
getResponse(): string;
async verify(): Promise<VerifyResponse>;
}Vanilla Class API
class VanillaRecaptcha {
constructor(config: RecaptchaConfig);
async init(): Promise<void>;
render(container: HTMLElement | string): number;
execute(): void;
reset(): void;
getResponse(): string;
async verify(token?: string): Promise<VerifyResponse>;
getToken(): string | null;
isReady(): boolean;
isLoading(): boolean;
getError(): string | null;
}๐ Backend Integration
This SDK is designed to work with a centralized backend verification service:
Verification Request
POST https://api.example.com/captcha/verify
{
"token": "03AGdBq27...",
"clientId": "react-app"
}Verification Response
{
"success": true,
"timestamp": "2024-01-01T12:00:00Z",
"challengeTs": "2024-01-01T11:59:55Z",
"hostname": "example.com"
}See the backend service documentation for implementation details.
๐จ Invisible reCAPTCHA
For invisible reCAPTCHA (no visible widget):
React
const { containerRef, execute, token } = useInvisibleRecaptcha({
siteKey: 'your-site-key',
clientId: 'react-app',
verifyUrl: 'https://api.example.com/captcha/verify'
});
const handleSubmit = () => {
execute(); // Triggers the challenge
};
useEffect(() => {
if (token) {
// Token received, submit form
}
}, [token]);Vue
<script setup>
const { containerRef, execute, token } = useInvisibleRecaptcha({
siteKey: 'your-site-key',
clientId: 'vue-app',
verifyUrl: 'https://api.example.com/captcha/verify'
});
const handleSubmit = () => {
execute();
};
watch(token, (newToken) => {
if (newToken) {
// Token received, submit form
}
});
</script>๐งช Testing
The SDK includes comprehensive unit tests:
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Watch mode
npm run test:watch๐ง Advanced Usage
Custom Script Loading
import { loadRecaptchaScript, renderRecaptcha } from '@recaptcha/universal-sdk';
// Load script with custom language
await loadRecaptchaScript('es');
// Render widget
const container = document.getElementById('recaptcha');
const widgetId = renderRecaptcha(container, {
siteKey: 'your-site-key',
options: { theme: 'dark' }
});Manual Verification
import { verifyRecaptchaToken } from '@recaptcha/universal-sdk';
const result = await verifyRecaptchaToken('token', {
siteKey: 'your-site-key',
verifyUrl: 'https://api.example.com/captcha/verify',
clientId: 'my-app'
});
if (result.success) {
console.log('Verification successful');
}๐ SSR Support
The SDK is SSR-safe and will gracefully handle server-side environments:
// Next.js example
'use client';
import { useRecaptcha } from '@recaptcha/universal-sdk/react';
export default function ContactForm() {
const { containerRef, token } = useRecaptcha({
siteKey: process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY!,
clientId: 'nextjs-app',
verifyUrl: '/api/captcha/verify'
});
// Component implementation
}๐ค Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
๐ License
MIT License - see LICENSE for details.
๐ Links
๐ก Support
- ๐ซ GitHub Issues
- ๐ Documentation
- ๐ฌ Discussions
Built with โค๏ธ for production use