ANIMA Documentation

The world's most advanced human verification API. Drop in one script, get cryptographic proof that your users are human.

ANIMA is live. Your free account includes 10,000 verifications/month. Create an account →

What is ANIMA?

ANIMA replaces CAPTCHA with a biometric verification system that reads 7 simultaneous biological signals — hand tremor, rhythm entropy, associative latency, mouse dynamics, device motion, scroll behavior, and a fusion score — to determine with 99.9% accuracy whether your user is a human or a bot.

Unlike CAPTCHA, which AI now defeats in under 2ms with 90%+ accuracy, ANIMA's signals cannot be replicated programmatically. The combination of passive background analysis and optional active challenges creates a mathematically infeasible barrier for automated systems.

Key Features

Architecture Overview

  1. Your page loads → ANIMA SDK starts passive signal collection silently
  2. User interacts with ANIMA widget → active signals collected (draw, tap, word)
  3. SDK sends signals to ANIMA API → API runs 7-signal fusion → returns signed JWT token
  4. Your form submits token to your server → your server calls ANIMA to verify
  5. ANIMA confirms: human ✅ or bot ❌ → you allow or block the action

Quick Start

Integrate ANIMA in under 5 minutes with 3 steps.

📋 You'll need your Site Key and Secret Key from your dashboard.

Step 1 — Add the widget to your page

<!-- Add before </body> -->
<script src="https://anima.id/sdk/v3/anima.min.js"
        data-site-key="anima_pub_YOUR_SITE_KEY"></script>

<!-- Place widget inside your form -->
<form id="myForm">
  <!-- your form fields -->
  <div class="anima-widget"></div>
  <input type="hidden" id="anima-token" name="anima-token">
  <button type="submit">Submit</button>
</form>

<script>
  // ANIMA calls this when human is verified
  ANIMA.onVerified(token => {
    document.getElementById('anima-token').value = token;
  });
</script>

Step 2 — Verify the token on your server

Node.js
Python
PHP
// In your form submission handler
const response = await fetch('https://anima.id/api/verify/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    token    : req.body['anima-token'],
    siteKey  : 'anima_pub_YOUR_SITE_KEY',
    secretKey: 'anima_sec_YOUR_SECRET_KEY'
  })
});

const result = await response.json();

if (!result.human) {
  return res.status(403).json({ error: 'Bot detected' });
}

// Human verified — process the form
console.log(`Human verified: ${result.confidence}% confidence`);

Step 3 — You're done! ✅

That's it. Your form is now protected. Every submission that passes contains a cryptographically signed proof that a human filled it out.

🎉 Test it: Visit GET /api/verify/test on your ANIMA instance to generate a test token and see the full response structure.

REST API Reference

All endpoints are available at your ANIMA instance base URL.

🔑 Widget calls use your Site Key (public). Server-side verification requires your Secret Key (keep private, never expose in frontend).

POST /api/verify/generate

Called by the ANIMA widget after collecting bio signals. Returns a signed JWT verification token.

POST/api/verify/generateWidget → Server

Request Body

FieldTypeRequiredDescription
siteKeystringYesYour public site key (anima_pub_...)
signals.drawnumberNoTremor signature score (0-100)
signals.tapnumberNoRhythm entropy score (0-100)
signals.wordnumberNoAssociative latency score (0-100)
signals.mousenumberNoMouse dynamics score (0-100)
signals.devicenumberNoDevice motion score (0-100)

Response

{
  "success"   : true,
  "token"     : "eyJ...",  // signed JWT — pass this to your server
  "status"    : "verified", // "verified" | "uncertain" | "failed"
  "confidence": 91         // 0-100 human confidence score
}

POST /api/verify/token

Called by your server to cryptographically validate a token received from a form submission. Always call this server-side — never from the browser.

POST/api/verify/tokenYour Server → ANIMA
FieldTypeRequiredDescription
tokenstringYesThe JWT token from the form submission
siteKeystringYesYour public site key
secretKeystringYesYour secret key (server-side only)

Response

{
  "success"   : true,
  "valid"     : true,
  "human"     : true,   // ← the main field to check
  "status"    : "verified",
  "confidence": 91,
  "signals"   : { // individual signal scores
    "draw": 90, "tap": 88, "word": 85, "mouse": 72, "device": 65
  },
  "issuedAt"  : "2026-04-02T15:30:00.000Z",
  "expiresAt" : "2026-04-02T15:35:00.000Z"
}

// If invalid / bot:
{
  "success": false,
  "valid"  : false,
  "reason" : "Token expired" // or "Bot detected", "Invalid signature", etc.
}

GET /api/verify/test

Generates a test token with sample signals. Use this to test your server-side verification without going through the widget.

Plans & Limits

All plans include full API access. Limits reset on the 1st of every month.

Feature Free Professional — $99/mo Enterprise
Verifications / month10,000500,000Unlimited
Bio signals37 (full fusion)7 + custom
API keys2UnlimitedUnlimited
Invisible analysis
Custom branding
Webhooks
On-premise / air-gap
SOC2 Type II
SLA guarantee99.9%99.99%
SupportCommunityPriority emailDedicated 24/7
⚠️ When you reach your monthly limit, verifications return status: "limit_reached" — your site keeps working but ANIMA falls back to allow-all mode. Upgrade to avoid gaps.

Security & Privacy

ANIMA is built privacy-first. We never store personal data, never track across sites, and generate ephemeral tokens that expire in 5 minutes.

What data does ANIMA collect?

Nothing personally identifiable. ANIMA collects and processes:

All analysis happens ephemerally. The resulting data is a single confidence score (0–100) and a signed JWT token. No raw behavioral data is ever persisted.

Token Security

Compliance

🔐 Best practice: Store your Secret Key in environment variables, never in frontend code. Rotate it immediately if compromised via your dashboard.

How It Works

Seven simultaneous biometric signals — measured in under 400ms — create a human fingerprint that no AI can replicate.

The 7 Signals

#SignalTypeHuman RangeBot Pattern
01Tremor SignatureActiveCV 0.25–2.5, 2–8px varianceCV <0.01, perfect strokes
02Rhythm EntropyActiveInter-tap CV 0.04–0.50CV <0.01, machine-precise
03Associative LatencyActive400–2,800ms response<50ms (scripted) or >5s (lookup)
04Mouse DynamicsPassiveCurved paths, micro-correctionsLinear/geometric movement
05Device MotionPassiveNatural physiological tremorZero movement (desktop bot)
06Scroll BehaviorPassiveMomentum, pauses, accelerationLinear or scripted scroll
07Fusion Score™Computed≥72 = verifiedMathematically infeasible to fake all 7
🧬 Why fusion matters: Any single signal can be spoofed with enough engineering effort. All seven simultaneously requires replicating human biology — computationally and practically impossible.

Widget Embed

The ANIMA widget is a self-contained component that handles the entire user-facing verification flow.

📦 Full widget embed guide: See the Quick Start section for the 3-step integration.

Configuration Options

OptionDefaultDescription
data-site-keyrequiredYour public site key
data-themelight"light" or "dark"
data-langenLanguage code (en, es, fr, de, zh...)
data-modeauto"auto" (invisible-first), "widget" (always show), "invisible" (never show)

Server-Side Verification

Always verify tokens server-side. Never trust the client to self-report verification status.

🚨 Critical: Never verify tokens from the browser. Always call /api/verify/token from your backend with your Secret Key. Your Secret Key must never be exposed in frontend code.

See the API Reference section for the full endpoint documentation and response schema.

Webhooks

Receive real-time notifications for verification events.

🔧 Webhooks are available on the Pro plan and above. Configure your webhook URL in the dashboard.

Events

EventDescription
verification.successHuman verified successfully
verification.failedBot detected
limit.approaching80% of monthly limit used
limit.reachedMonthly limit hit

Node.js Integration

Full Express.js integration example.

// npm install node-fetch (or use built-in fetch in Node 18+)
const express = require('express');
const app     = express();
app.use(express.urlencoded({ extended: true }));

// Middleware to verify ANIMA token
async function verifyAnima(req, res, next) {
  try {
    const r = await fetch('https://YOUR_ANIMA_URL/api/verify/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        token    : req.body['anima-token'],
        siteKey  : process.env.ANIMA_SITE_KEY,
        secretKey: process.env.ANIMA_SECRET_KEY
      })
    });
    const result = await r.json();
    if (!result.human) return res.status(403).json({ error: 'Bot detected' });
    req.animaResult = result;
    next();
  } catch(e) {
    res.status(500).json({ error: 'Verification error' });
  }
}

app.post('/contact', verifyAnima, (req, res) => {
  // Human confirmed — process the form
  res.json({ success: true });
});

Python Integration

# pip install requests
import requests, os

ANIMA_URL = os.environ['ANIMA_URL']
SITE_KEY  = os.environ['ANIMA_SITE_KEY']
SEC_KEY   = os.environ['ANIMA_SECRET_KEY']

def verify_human(token):
    if not token: return False
    r = requests.post(f'{ANIMA_URL}/api/verify/token', json={
        'token'    : token,
        'siteKey'  : SITE_KEY,
        'secretKey': SEC_KEY
    }, timeout=5)
    return r.json().get('human', False)

# Django view
from django.http import JsonResponse

def contact_view(request):
    if request.method == 'POST':
        if not verify_human(request.POST.get('anima-token')):
            return JsonResponse({'error':'Bot detected'}, status=403)
        # Process form...
        return JsonResponse({'success': True})

PHP Integration

// WordPress / PHP integration
function anima_verify($token) {
    $payload = json_encode([
        'token'     => $token,
        'siteKey'   => getenv('ANIMA_SITE_KEY'),
        'secretKey' => getenv('ANIMA_SECRET_KEY')
    ]);
    $ch = curl_init(getenv('ANIMA_URL') . '/api/verify/token');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_TIMEOUT        => 5
    ]);
    $result = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $result['human'] ?? false;
}

// WordPress form hook
add_action('init', function() {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (!anima_verify($_POST['anima-token'] ?? '')) {
            wp_die('Bot detected', 'Forbidden', ['response' => 403]);
        }
    }
});

React / Next.js Integration

// components/AnimaWidget.jsx
import { useEffect, useRef } from 'react';

export default function AnimaWidget({ onVerified }) {
  const loaded = useRef(false);

  useEffect(() => {
    if (loaded.current) return;
    loaded.current = true;
    const script = document.createElement('script');
    script.src = 'https://YOUR_ANIMA_URL/sdk/v3/anima.min.js';
    script.setAttribute('data-site-key', process.env.NEXT_PUBLIC_ANIMA_SITE_KEY);
    script.onload = () => {
      window.ANIMA?.onVerified(token => onVerified(token));
    };
    document.body.appendChild(script);
  }, []);

  return <div className="anima-widget" />;
}

// API route: pages/api/contact.js
export default async function handler(req, res) {
  const r = await fetch(`${process.env.ANIMA_URL}/api/verify/token`, {
    method: 'POST', headers: {'Content-Type':'application/json'},
    body: JSON.stringify({ token:req.body.animaToken, siteKey:process.env.ANIMA_SITE_KEY, secretKey:process.env.ANIMA_SECRET_KEY })
  });
  const { human } = await r.json();
  if (!human) return res.status(403).json({ error:'Bot detected' });
  res.json({ success: true });
}