DOCUMENTATION

Integration Guide

Everything you need to embed GameCaptcha in your signup forms and verify tokens on your server.

Quick Start

The simplest possible integration — two lines of HTML, one verification call.

index.htmlhtml
<!-- Step 1: Add GameCaptcha script to your page (before </body>) -->
<script src="https://didyu.app/captchagames/widget.js"></script>

<!-- Step 2: Add the widget inside your form -->
<form id="signup-form">
  <input type="email" name="email" placeholder="Email" />

  <div
    data-gamecaptcha
    data-site-key="gc_connect4_your_key_here"
    data-game="connect4"
    data-theme="dark"
  ></div>
  <!-- data-theme: "dark" (default) or "light" — match your site's background -->

  <button type="submit">Sign up</button>
</form>

<!-- Step 3: Read the token on submit -->
<script>
  document.getElementById('signup-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const token = e.target.querySelector('[data-gamecaptcha]').dataset.token;
    if (!token) return alert('Please complete the game first.');

    const res = await fetch('/api/signup', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email: e.target.email.value, gamecaptchaToken: token }),
    });
  });
</script>

IMPORTANT

Always verify the token on your server before processing form submissions. Client-side checks alone are insufficient — a bot could submit directly to your API.

How Verification Works

The token flow in 4 steps.

1

Widget loads

The script tag renders the game inside the div. The player's site key is read from the data-site-key attribute.

2

Player passes the game

When the human wins, the widget calls our server with the site key. The server confirms the key is valid and issues a signed JWT.

3

Token written to the element

The signed token is stored in data-token on the widget div. Your form submit handler reads it.

4

You verify server-side

Your server calls POST /captchagames/api/verify with the token and site key. We return { success: true }. Only then do you process the form.

Token format (JWT, expires in 10 minutes)

{ siteKey: "gc_connect4_xxx", gameId: "connect4", iat: ..., exp: ... }

Server Verification

Call this endpoint from your server — never from the browser.

POST/captchagames/api/verify

Request headers

Authorization: Bearer YOUR_API_KEYContent-Type: application/json

Request body

{ "token": "...", "siteKey": "gc_..." }

✅ Success response

{ "success": true, "gameId": "connect4" }

❌ Failure response

{ "success": false, "error": "Invalid or expired token" }
// Express example
app.post('/api/signup', async (req, res) => {
  const { email, gamecaptchaToken } = req.body;

  // Verify the token server-side
  const verifyRes = await fetch('https://didyu.app/captchagames/api/verify', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_API_KEY',  // from your dashboard
    },
    body: JSON.stringify({
      token: gamecaptchaToken,
      siteKey: 'gc_connect4_your_key_here',
    }),
  });

  const { success, gameId } = await verifyRes.json();

  if (!success) {
    return res.status(400).json({ error: 'Bot detected. Please try again.' });
  }

  // ✅ Token is valid — proceed with signup
  await createUser(email);
  res.json({ ok: true });
});

Framework Guides

Complete examples for the most common stacks.

'use client'; // Next.js App Router

import { useRef, useState } from 'react';

export default function SignupForm() {
  const widgetRef = useRef<HTMLDivElement>(null);
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const token = widgetRef.current?.dataset.token;

    if (!token) {
      alert('Please complete the game first!');
      return;
    }

    setLoading(true);
    const res = await fetch('/api/signup', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        email: (e.target as HTMLFormElement).email.value,
        gamecaptchaToken: token,
      }),
    });

    setLoading(false);
    if (res.ok) window.location.href = '/welcome';
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" name="email" required />

      {/* The widget script must be loaded in a script tag,
          e.g. in <head> or via next/script with strategy="beforeInteractive" */}
      <div
        ref={widgetRef}
        data-gamecaptcha
        data-site-key="gc_connect4_your_key_here"
        data-game="connect4"
      />

      <button type="submit" disabled={loading}>
        {loading ? 'Signing up...' : 'Sign up'}
      </button>
    </form>
  );
}

Game Comparison

Choose the game that fits your form and audience.

GAMEAVG. TIMEDIFFICULTYBEST FORMOBILE
🔴Connect 415sEasyGeneral signups
👾Pac-Man Lite8sEasyGaming sites
🔨Whack-a-Bot12sMediumLogin forms
🎨Color Match10sMediumSignup flows
🌀Maze Runner20sHardHigh-security forms
🍎Fruit Sorter15sMediumE-commerce checkouts
🧱Stack It10sEasyComment forms

API Reference

All endpoints at a glance.

POST/captchagames/api/verify🔑 Auth required

Verify a game completion token. Requires Authorization: Bearer header.

POST/captchagames/api/game-complete

Called by the embed widget internally. Returns a signed JWT on game pass.

GET/captchagames/api/auth/me🔑 Auth required

Get the current authenticated user, their API key, and owned games.