Package Exports
- @opentech-lab/custom-captcha
- @opentech-lab/custom-captcha/dist/index.esm.js
- @opentech-lab/custom-captcha/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@opentech-lab/custom-captcha) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Custom CAPTCHA – Build Your Own reCAPTCHA-Style Puzzle
A fully customizable CAPTCHA component built for modern web apps. Easily plug it into your forms to stop bots, test user knowledge, or filter out unwanted traffic with your own question sets or image-based puzzles.
Features
- Protect your forms from spam and automation
- Add your own custom questions (text, image, logic, drag-n-drop)
- Puzzle types: multiple choice, image select, drag to match, sentence completion
- Language & culture aware: design puzzles specific to your audience
- Simple integration with React (other frameworks coming soon)
- Lightweight & dependency-free (core)
Getting Started
1. Install
npm install @opentech-lab/custom-captcha2. Import Styles
import '@opentech-lab/custom-captcha/dist/index.css';3. Basic Usage (React)
import { CustomCaptcha } from '@opentech-lab/custom-captcha';
export default function MyForm() {
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
const questions = [
{
type: 'multiple-choice' as const,
question: 'What is the capital of France?',
choices: ['London', 'Berlin', 'Paris', 'Madrid'],
answer: 'Paris',
},
];
return (
<form method="POST" action="/api/submit">
<input type="email" name="email" placeholder="Your email" />
<CustomCaptcha
siteKey="your-site-key-here"
questions={questions}
onSuccess={(token) => {
console.log('CAPTCHA solved:', token);
setCaptchaToken(token);
}}
onError={(error) => {
console.error('CAPTCHA failed:', error);
setCaptchaToken(null);
}}
theme="light"
/>
<button type="submit" disabled={!captchaToken}>
Submit
</button>
</form>
);
}4. Image Selection Example
const imageQuestions = [
{
type: 'image-select' as const,
question: 'Select all images with cars',
images: [
{ src: '/images/car1.jpg', isCorrect: true },
{ src: '/images/bike1.jpg', isCorrect: false },
{ src: '/images/car2.jpg', isCorrect: true },
{ src: '/images/tree1.jpg', isCorrect: false },
],
},
];
<CustomCaptcha
siteKey="your-site-key"
questions={imageQuestions}
onSuccess={(token) => console.log('Success:', token)}
/>5. Next.js SSR Compatibility
This component is fully compatible with Next.js App Router and Pages Router with SSR:
// app/page.tsx (App Router)
import { CustomCaptcha } from '@opentech-lab/custom-captcha';
import '@opentech-lab/custom-captcha/dist/index.css';
export default function HomePage() {
// Component automatically handles SSR with loading fallback
return (
<div>
<h1>Contact Form</h1>
<CustomCaptcha
siteKey="your-site-key"
questions={questions}
onSuccess={(token) => console.log(token)}
/>
</div>
);
}The component renders a loading placeholder during server-side rendering and loads the interactive component after hydration.
CAPTCHA Types
| Type | Description |
|---|---|
multiple-choice |
Ask any text-based question with options |
image-select |
Click on the correct image(s) |
drag-match |
Drag to match items (coming soon) |
sentence-fill |
Fill in blanks in a sentence (coming soon) |
Validation (Backend)
You must validate the token on your server to prevent spoofing.
// Example: Express.js
import { validateCaptchaToken } from '@opentech-lab/custom-captcha/server';
app.post('/api/submit', async (req, res) => {
const { captchaToken } = req.body;
const isValid = validateCaptchaToken(captchaToken, 'your-secret-key');
if (!isValid) {
return res.status(403).json({ error: 'Invalid CAPTCHA' });
}
// proceed with request
});API Reference
CustomCaptcha Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
questions |
CaptchaQuestion[] |
Yes | - | Array of questions (see formats below) |
siteKey |
string |
Yes | - | Unique key for your frontend |
onSuccess |
(token: string) => void |
Yes | - | Callback when CAPTCHA is solved |
onError |
(error: Error) => void |
No | - | Callback on failure |
theme |
'light' | 'dark' |
No | light |
Visual theme |
className |
string |
No | '' |
Additional CSS classes |
Question Types
Multiple Choice Question
{
type: 'multiple-choice';
question: string;
choices: string[];
answer: string; // Must match one of the choices
}Image Select Question
{
type: 'image-select';
question: string;
images: Array<{
src: string;
isCorrect: boolean;
}>;
}Troubleshooting
SSR Issues with Next.js
If you encounter "Cannot read properties of undefined (reading 'ReactCurrentDispatcher')" errors:
- Make sure you're using version
0.0.3or later - Import styles:
import '@opentech-lab/custom-captcha/dist/index.css' - The component automatically handles SSR - no additional configuration needed
TypeScript Issues
For TypeScript projects, use type assertions for question types:
const questions = [
{
type: 'multiple-choice' as const,
// ... rest of question
}
];Advanced Ideas (Coming Soon)
- Time-based interaction analysis (anti-GPT bot)
- reCAPTCHA-style invisible scoring
- Crowd-verified question pools
- Custom image puzzle builder
- Audio CAPTCHA (for accessibility)
Ethics & Safety
This tool is designed for developers building secure and intentional communities. Use ideological or political filters responsibly. Avoid using CAPTCHAs in ways that could be discriminatory or violate local laws.
License
MIT
Contributing
PRs welcome. If you'd like to contribute new puzzle types, translations, or integrations (Vue, Svelte, etc.), feel free to open an issue or fork the repo.
Inspiration
This project was inspired by:
- Google's reCAPTCHA
- The increasing threat of AI-generated misinformation
- The need for user-driven, culturally-aware gatekeeping tools