/ Captcha

Captcha

Add animated captcha to protect your website forms from bots. Unique direction-based challenges that are easy for humans, hard for bots.

How It Works

1
Show Widget
User sees an animated object (arrow, ball, rocket, fish) moving in a direction
2
User Answers
User clicks the correct direction button (←, →, ↑, ↓ or ↻, ↺)
3
Server Verifies
Your backend sends the answer to our API to verify it's correct

Quick Start

Step 1: Go to Console → Captcha and create a new key.

Step 2: Add the widget to your HTML form:

HTML
<form action="/submit" method="POST">
  <input type="text" name="email" placeholder="Email" />
  <input type="password" name="password" placeholder="Password" />

  <!-- ToolPix Captcha -->
  <div data-tpx-captcha="YOUR_SITE_KEY"></div>

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

<!-- Load widget script (place before </body>) -->
<script src="https://toolpix.dev/api/v1/captcha/widget" defer></script>

Step 3: Verify the captcha on your backend (see examples below).

Widget Options

AttributeTypeDescription
data-tpx-captchastringYour site key (required)
data-tpx-darkflagEnable dark mode theme

You can also initialize programmatically:

JavaScript
const captcha = new ToolPixCaptcha('#my-captcha', 'YOUR_SITE_KEY', {
  dark: true,
  onSuccess: (data) => {
    console.log('Captcha solved!', data);
    // data contains: { challengeId, answer, token, expiresAt }
  }
});

// Check if solved
captcha.isSolved(); // true/false

// Get answer data for backend verification
captcha.getData(); // { challengeId, answer, token, expiresAt }

// Reset captcha
captcha.reset();

API Reference

POST /api/v1/captcha/challenge

Request a new captcha challenge. Called automatically by the widget.

POST /api/v1/captcha/verify

Verify a captcha answer. Call this from your backend only — never expose your secret key to the client.

ParameterTypeDescription
secretKeystringYour secret key from Console (required)
challengeIdstringChallenge ID from captcha data
answerstringUser's answer (direction)
tokenstringServer verification hash
expiresAtnumberChallenge expiry timestamp

Response:

JSON
// Success
{ "success": true, "verificationToken": "abc123...", "timestamp": 1711800000000 }

// Failure
{ "success": false, "error": "Incorrect answer" }

Backend Verification Examples

When the user submits your form, the captcha data is in a hidden input called tpx-captcha-data. Send it to our verify endpoint with your secret key.

Node.js / Express

JavaScript
app.post('/submit', async (req, res) => {
  const captchaData = JSON.parse(req.body['tpx-captcha-data']);

  const verify = await fetch('https://toolpix.dev/api/v1/captcha/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      secretKey: 'YOUR_SECRET_KEY',
      ...captchaData
    })
  });

  const result = await verify.json();

  if (!result.success) {
    return res.status(400).json({ error: 'Captcha verification failed' });
  }

  // Captcha passed — process the form
  // ...
});

PHP

PHP
<?php
$captchaData = json_decode($_POST['tpx-captcha-data'], true);

$response = file_get_contents('https://toolpix.dev/api/v1/captcha/verify', false,
  stream_context_create([
    'http' => [
      'method' => 'POST',
      'header' => 'Content-Type: application/json',
      'content' => json_encode([
        'secretKey' => 'YOUR_SECRET_KEY',
        'challengeId' => $captchaData['challengeId'],
        'answer' => $captchaData['answer'],
        'token' => $captchaData['token'],
        'expiresAt' => $captchaData['expiresAt'],
      ])
    ]
  ])
);

$result = json_decode($response, true);

if (!$result['success']) {
  die('Captcha verification failed');
}

// Captcha passed — process the form
// ...
?>

Python / Flask

Python
import requests, json
from flask import Flask, request

app = Flask(__name__)

@app.route('/submit', methods=['POST'])
def submit():
    captcha_data = json.loads(request.form.get('tpx-captcha-data', '{}'))

    result = requests.post('https://toolpix.dev/api/v1/captcha/verify', json={
        'secretKey': 'YOUR_SECRET_KEY',
        **captcha_data
    }).json()

    if not result.get('success'):
        return 'Captcha failed', 400

    # Captcha passed — process the form
    return 'Success!'

Go

Go
func submitHandler(w http.ResponseWriter, r *http.Request) {
    captchaData := r.FormValue("tpx-captcha-data")

    var data map[string]interface{}
    json.Unmarshal([]byte(captchaData), &data)
    data["secretKey"] = "YOUR_SECRET_KEY"

    body, _ := json.Marshal(data)
    resp, _ := http.Post(
        "https://toolpix.dev/api/v1/captcha/verify",
        "application/json",
        bytes.NewBuffer(body),
    )
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)

    if result["success"] != true {
        http.Error(w, "Captcha failed", 400)
        return
    }

    // Captcha passed — process the form
    fmt.Fprint(w, "Success!")
}

Ruby / Rails

Ruby
require 'net/http'
require 'json'

def verify_captcha(captcha_data_json)
  data = JSON.parse(captcha_data_json)
  data['secretKey'] = 'YOUR_SECRET_KEY'

  uri = URI('https://toolpix.dev/api/v1/captcha/verify')
  res = Net::HTTP.post(uri, data.to_json,
    'Content-Type' => 'application/json')

  result = JSON.parse(res.body)
  result['success'] == true
end

# In your controller:
unless verify_captcha(params['tpx-captcha-data'])
  render plain: 'Captcha failed', status: 400
  return
end

C# / .NET

C#
using System.Text.Json;

[HttpPost("submit")]
public async Task<IActionResult> Submit([FromForm] string tpxCaptchaData)
{
    var captchaData = JsonSerializer.Deserialize<Dictionary<string, object>>(tpxCaptchaData);
    captchaData["secretKey"] = "YOUR_SECRET_KEY";

    var client = new HttpClient();
    var response = await client.PostAsJsonAsync(
        "https://toolpix.dev/api/v1/captcha/verify", captchaData);
    var result = await response.Content.ReadFromJsonAsync<Dictionary<string, object>>();

    if (result?["success"]?.ToString() != "True")
        return BadRequest("Captcha failed");

    // Captcha passed — process the form
    return Ok("Success!");
}

Java / Spring

Java
@PostMapping("/submit")
public ResponseEntity<String> submit(@RequestParam("tpx-captcha-data") String captchaJson) {
    Map<String, Object> data = new ObjectMapper().readValue(captchaJson, Map.class);
    data.put("secretKey", "YOUR_SECRET_KEY");

    RestTemplate rest = new RestTemplate();
    Map result = rest.postForObject(
        "https://toolpix.dev/api/v1/captcha/verify", data, Map.class);

    if (!Boolean.TRUE.equals(result.get("success"))) {
        return ResponseEntity.badRequest().body("Captcha failed");
    }

    // Captcha passed
    return ResponseEntity.ok("Success!");
}

Dark Mode

Add data-tpx-dark attribute for dark theme:

HTML
<div data-tpx-captcha="YOUR_SITE_KEY" data-tpx-dark></div>

Domain Restrictions

In Console → Captcha, you can restrict which domains can use your captcha key. Only requests from listed domains will be accepted. Leave empty to allow all domains (useful for development).

Security Notes

  • Never expose your secret key — only use it on your backend server.
  • Challenges expire after 2 minutes. If expired, a new challenge is generated automatically.
  • Each challenge can only be verified once.
  • Wrong answers trigger a new challenge with a different animation.
  • Set allowed domains to prevent unauthorized use of your captcha key.

Ready to get started?

Create your captcha key and protect your forms in minutes.

Open Console → Captcha