Skip to content

GDPR, WCAG 2.2 AA, and EAA compliant, self-hosted CAPTCHA alternative with PoW mechanism and advanced anti-spam filter.

License

Notifications You must be signed in to change notification settings

altcha-org/altcha

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ALTCHA

ALTCHA is a self-hosted, privacy-first security solution that protects your websites, APIs, and online services from spam and abuse through an innovative proof-of-work mechanism. Unlike traditional CAPTCHAs that depend on intrusive methods like cookies or fingerprinting, ALTCHA delivers robust protection while respecting user privacy.

ALTCHA is fully compliant with:

For more details, visit altcha.org.

Features

  • Frictionless Experience: Uses proof-of-work (PoW) instead of visual puzzles for a seamless user experience.
  • Code Challenge (New in v2): Supports accessible code challenges ("enter code from image") with an audio option.
  • Cookie-Free Design: GDPR-compliant by default—no cookies or tracking.
  • Fully Accessible: Meets WCAG 2.2 AA-level standards and complies with the European Accessibility Act (EAA).
  • Lightweight: Minimal bundle size for fast page loads and optimal performance.
  • Self-Hosted: No dependency on third-party services.

What’s New in v2

Version 2 introduces enhanced accessibility, expanded language support, and integration with ALTCHA Sentinel—a self-hosted anti-spam solution for websites, apps, and services.

Key Improvements in v2

  • Built-in Internationalization (i18n) for 48+ languages
  • Improved RTL (right-to-left) language support
  • Enhanced WCAG accessibility
  • Support for accessible code challenges (image + audio options)

Migrating from v1

Version 2 (v2) is fully compatible with v1, and minimal migration steps are required. However, be sure to test your integration after updating.

  • Translations: v2 introduces a new built-in internationalization (i18n) system. The use of the strings attribute is now discouraged in favor of this new system.
  • ALTCHA Sentinel: Sentinel is a new self-hosted solution that replaces the previous SaaS services and the SpamFilter. We recommend migrating to Sentinel for better compliance, enhanced security, unlimited verifications, and an adaptive Captcha with code-challenge support.

Examples

Explore starter templates for popular frameworks:

Server Integrations

Plugins & CMS

Usage

The ALTCHA widget is distributed as a Web Component and supports all modern browsers.

1. Install ALTCHA

npm install altcha

Import in your main file:

import 'altcha';

Or load via <script> tag:

<script async defer src="/altcha.js" type="module"></script>

CDN:

<script
  async
  defer
  src="https://cdn.jsdelivr.net/gh/altcha-org/altcha@main/dist/altcha.min.js"
  type="module"
></script>

2. Add <altcha-widget> to Your Forms

<form>
  <altcha-widget challengeurl="https://..."></altcha-widget>
</form>

See configuration options or the website integration docs.

3. Integrate with Your Server

Refer to the server documentation for implementation details.

Supported Browsers

ALTCHA works on modern browsers with Web Crypto API support (specifically crypto.subtle - caniuse.com).

Supported:

  • Chrome 67+ (desktop & Android)
  • Edge 79+
  • Firefox 63+ (desktop & Android)
  • Safari 11+ (macOS & iOS)
  • Any browser supporting Web Components + Web Crypto

Not Supported:

  • Internet Explorer 11 (or older)

Bundle Size

ALTCHA is optimized for performance:

Distribution Size (GZIPped)
ALTCHA 29+ kB
ALTCHA with all translations 42+ kB
hCaptcha 48+ kB
reCAPTCHA 270+ kB

When GZIPped, it totals about 29 kB, making ALTCHA’s widget about 90% smaller than reCAPTCHA.

Content Security Policy (CSP)

The default bundle includes styles and workers in a single file. For strict CSP compliance, use scripts from /dist_external. Learn more in the documentation.

Configuration

Required options (at least one is required):

  • challengeurl: Server endpoint to fetch the challenge.
  • challengejson: Preloaded JSON challenge data (avoids HTTP requests).

Additional options:

  • auto: Automatically verify without user interaction (possible values: off, onfocus, onload, onsubmit).
  • credentials: Whether to include credentials with the challenge request (possible values: omit, same-origin, include).
  • customfetch: A custom fetch function for retrieving the challenge.
    Accepts url: string and init: RequestInit as arguments and must return a Response.
  • delay: Artificial delay in milliseconds before verification (defaults to 0).
  • disableautofocus: If true, prevents the code-challenge input from automatically receiving focus on render (defaults to false).
  • expire: Challenge expiration duration in milliseconds.
  • floating: Enable floating UI (possible values: auto, top, bottom).
  • floatinganchor: CSS selector of the "anchor" to which the floating UI will be attached (defaults to the button[type="submit"] in the related form).
  • floatingoffset: Y offset from the anchor element for the floating UI in pixels (defaults to 12).
  • floatingpersist: Whether to "persist" (keep visible) the floating widget after verification (possible values: true | false | focus; defaults to false, meaning the widget will hide).
  • hidefooter: Hide the footer (ALTCHA link).
  • hidelogo: Hide the ALTCHA logo.
  • id: The checkbox id attribute. Useful for multiple instances of the widget on the same page.
  • language: The ISO alpha-2 code of the language to use (the language file be imported from altcha/i18n/*).
  • maxnumber: Max number to iterate to (defaults to 1,000,000).
  • name: Name of the hidden field containing the payload (defaults to "altcha").
  • strings: JSON-encoded translation strings. Refer to customization.
  • refetchonexpire: Automatically re-fetch and re-validate when the challenge expires (defaults to true).
  • verifyurl: URL for server-side verification requests. This option is automatically configured with Sentinel. Override this setting only if using a custom server implementation. Supports fn:function_name format to call a global JS function instead.
  • workers: Number of workers to utilize for PoW (defaults to navigator.hardwareConcurrency || 8, max value 16).
  • workerurl: URL of the Worker script (defaults to ./worker.js, only works with external build).

Data Obfuscation options:

  • obfuscated: The obfuscated data provided as a base64-encoded string (requires altcha/obfuscation plugin). Use only without challengeurl/challengejson.

Development / Testing options:

  • debug: Print log messages in the console.
  • mockerror: Causes verification to always fail with a "mock" error.
  • test: Generates a "mock" challenge within the widget, bypassing the request to challengeurl.

Internationalization (i18n)

ALTCHA supports 48+ languages. You can import individual language translations or a bundle that includes all of them.

Importing Translations

To import all translations:

import 'altcha/i18n/all';

To import specific languages only:

import 'altcha/i18n/de';
import 'altcha/i18n/fr-fr';

Alternatively, you can import the combined bundle, which includes both the widget and all translations:

import 'altcha/i18n';

Language Detection

The widget automatically detects the language from:

  • The <html lang="..."> attribute
  • The user's browser settings (navigator.languages)

To override the language manually, use the language attribute:

<altcha-widget language="de"></altcha-widget>

Customizing Translations

You can override default translations by updating the global altchaI18n registry (globalThis.altchaI18n or window.altchaI18n):

import 'altcha/i18n/de';

globalThis.altchaI18n.set('de', {
  ...globalThis.altchaI18n.get('de'),
  label: 'Ich bin ein Mensch', // Custom label
});

Code Challenges

For additional verification, ALTCHA supports image/audio code challenges (e.g., "Enter the code from the image"). This feature requires ALTCHA Sentinel or a custom server implementation.

Plugins

Extend functionality with plugins:

import 'altcha/obfuscation'; // Data obfuscation
import 'altcha/upload'; // File uploads
import 'altcha'; // Main package

Enable plugins per widget:

<altcha-widget plugins="upload,obfuscation"></altcha-widget>

Available Plugins

  • obfuscation: Secure sensitive data (emails, phone numbers).
  • upload: File uploads with ALTCHA Sentinel or a custom backend.

Programmatic Configuration

To configure the widget programmatically, use the configure() method:

document.querySelector('#altcha').configure({
  challenge: {
    algorithm: 'SHA-256',
    challenge: '...',
    salt: '...',
    signature: '...',
  },
  strings: {
    label: 'Verify',
  },
});

Available configuration options:

export interface Configure {
  auto?: 'off' | 'onfocus' | 'onload' | 'onsubmit';
  challenge?: {
    codeChallenge?: {
      audio?: string;
      image: string;
      length?: number;
    };
    algorithm: string;
    challenge: string;
    maxnumber?: number;
    salt: string;
    signature: string;
  };
  challengeurl?: string;
  credentials?: 'omit' | 'same-origin' | 'include' | boolean;
  customfetch?:
    | string
    | ((url: string, init?: RequestInit) => Promise<Response>);
  debug?: boolean;
  delay?: number;
  disableautofocus?: boolean;
  expire?: number;
  floating?: 'auto' | 'top' | 'bottom';
  floatinganchor?: string;
  floatingoffset?: number;
  floatingpersist?: boolean | 'focus';
  hidefooter?: boolean;
  hidelogo?: boolean;
  maxnumber?: number;
  mockerror?: boolean;
  name?: string;
  obfuscated?: string;
  refetchonexpire?: boolean;
  spamfilter?: boolean | 'ipAddress' | SpamFilter; // deprecated
  strings?: {
    ariaLinkLabel: strin;
    enterCode: string;
    enterCodeAria: string;
    error: string;
    expired: string;
    footer: string;
    getAudioChallenge: string;
    label: string;
    loading: string;
    reload: strin;
    verificationRequired: string;
    verified: string;
    verifying: string;
    waitAlert: string;
  };
  test?: boolean | number | 'delay';
  verifyurl?: string;
  workers?: number;
  workerurl?: string;
}

Events

  • code - Triggers when code-challenge verification is requested.
  • load - Triggers when the widget loads. The exported methods become available after this event.
  • sentinelverification - Triggers upon a verification with ALTCHA Sentinel.
  • serververification - (Deprecated) Triggers upon a server verification (only in conjunction with spamfilter).
  • statechange - Triggers whenever an internal state changes.
  • verified - Triggers when the challenge is verified.
enum State {
  CODE = 'code',
  ERROR = 'error',
  VERIFIED = 'verified',
  VERIFYING = 'verifying',
  UNVERIFIED = 'unverified',
  EXPIRED = 'expired',
}

Using events:

document.querySelector('#altcha').addEventListener('statechange', (ev) => {
  // See enum State above
  console.log('state:', ev.detail.state);
});

Important

Both programmatic configuration and event listeners have to called/attached after the ALTCHA script loads, such as within window.addEventListener('load', ...).

Contributing

See Contributing Guide and please follow our Code of Conduct.

Sponsorship

This project is sponsored by BAUSW.com - Digital Construction Site Diary, promoting transparency and trust in construction projects with real-time documentation.

License

MIT