npm package: @opentech-lab/custom-captcha
Description: A fully customizable CAPTCHA component built for modern web apps
Author: OpenTech Lab
Latest version: 1.0.1

# Custom CAPTCHA – Build Your Own reCAPTCHA-Style Puzzle

A fully customizable CAPTCHA component built for modern React applications, with first-class Next.js support. Easily integrate it into your forms to stop bots, test user knowledge, or filter unwanted traffic using custom question sets and image-based puzzles. 

When activated, the component displays as a centered modal dialog where users answer verification questions. Upon successful verification, it closes automatically and saves the verification status to localStorage. In Next.js applications, verification can also be handled server-side with SSR.

No backend server required – this is a frontend-focused CAPTCHA solution optimized for React and Next.js applications.

## Features

- Protect your website, pages and forms from spam and automation
- Add your own custom questions (text, image, logic, drag-n-drop)
- Puzzle types: multiple choice, single choice, text input, image selection
- Language & culture aware: design puzzles specific to your audience
- Simple integration with React (other frameworks coming soon)
- Lightweight & dependency-free (core)

## Quick Start Guide

This guide will walk you through setting up the Custom CAPTCHA in a React application.

### 1. Installation

First, add the package to your project:

```bash
npm install @opentech-lab/custom-captcha
```

### 2. Usage

#### Setup questions

```ts
import { CaptchaQuestion } from '@opentech-lab/custom-captcha/types';

export const captchaQuestion: CaptchaQuestion[] = [
  {
    id: '1',
    type: 'multiple-choice',
    question: 'What is number?',
    options: ['1', 'abc', '8', 'hello'],
    correctAnswer: ['1', '8'],
  },
  {
    id: '2',
    type: 'single-choice',
    question: 'What is 10 - 4?',
    options: ['5', '6', '7', '8'],
    correctAnswer: ['6'],
  },
  {
    id: '3',
    type: 'text-input',
    question: 'What is the capital of France?',
    correctAnswer: ['Paris'],
  },
  {
    id: '4',
    type: 'images-select',
    question: 'Select all cat images',
    images: [
      { src: '/images/cat1.jpg', answer: true },
      { src: '/images/cat2.jpg', answer: false },
      { src: '/images/cat3.jpg', answer: true },
    ],
    correctAnswer: [], // Not used for images-select, answers are in images array
  },
];
```

#### Configuration Options

```ts
import { CaptchaConfig } from '@opentech-lab/custom-captcha/types';

export const exampleConfig: CaptchaConfig = {
  questions: captchaQuestion,
  title: "Please complete this verification",
  expiryMinutes: 60,
  storageKey: "custom-captcha-verification",
  questionsToSolve: 2, // Only show 2 random questions from the pool
};
```

#### Configuration Properties

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `questions` | `CaptchaQuestion[]` | `[]` | Array of questions for the CAPTCHA |
| `title` | `string` | `"Verification Required"` | Title shown in the CAPTCHA dialog |
| `expiryMinutes` | `number` | `60` | How long verification lasts (minutes) |
| `storageKey` | `string` | `"custom-captcha-verification"` | Local storage key for verification status |
| `questionsToSolve` | `number` | `1` | Number of questions to solve correctly |
| `zIndex` | `number` | `99999` | Z-index for the CAPTCHA overlay |
| `imageObjectFit` | `string` | `"contain"` | How images are fitted in image-select questions |

#### Usage Examples

**Basic Usage (Single Question)**
```tsx
// Shows 1 random question (default behavior)
<CustomCaptcha question={captchaQuestion} />
```

**Limited Questions (Random Selection)**
```tsx
// Shows only 2 random questions from the pool
const config = {
  questions: captchaQuestion,
  questionsToSolve: 2,
  title: "Quick Verification"
};

<CustomCaptcha config={config} />
```

**Full Configuration Example**
```tsx
// Complete setup with all options
const advancedConfig = {
  questions: captchaQuestion,
  title: "Security Check",
  expiryMinutes: 30,
  storageKey: "my-app-captcha",
  questionsToSolve: 3, // User must solve 3 questions correctly
  zIndex: 999999
};

<CustomCaptcha config={advancedConfig} />
```

#### Add in layout

```tsx
import { CustomCaptcha } from '@opentech-lab/custom-captcha';
import { captchaQuestion, exampleConfig } from '@/config/captchaconfig';
// Types can be imported separately if needed
// import { CaptchaQuestion, CaptchaConfig } from '@opentech-lab/custom-captcha/types';

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div>
      {children}
      <CustomCaptcha config={exampleConfig} />
      {/* Alternative: <CustomCaptcha question={captchaQuestion} /> */}
    </div>
  );
}
```

### Key Features

#### Smart Question System
- **`questionsToSolve`**: Specify how many questions users must solve correctly
- Users can retry incorrect answers unlimited times (no attempt limits)
- System presents new random questions until the required number is solved
- If you have 10 questions but set `questionsToSolve: 3`, users need to solve any 3 correctly
- Questions are selected randomly from the pool, avoiding recently solved ones when possible
- Real-time progress tracking: Shows "Progress: 2 / 3 solved" at top and bottom
- Button text changes: "Next" → "Complete" on final question

## 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.