Skip to content
Documentation

Integration guide

Get stopbot protecting a form in a few minutes: add the widget, then verify the proof on your server.

Replace YOUR_SITE_KEY and YOUR_SECRET_KEY with the keys from your stopbot dashboard. The exact SDK shape below is illustrative and will track the published API.

Quick start

Add the script to your page’s <head>, then drop the widget inside the form you want to protect.

html
<!-- 1. Load the stopbot script (async, non-blocking) -->
<script src="https://js.stopbot.io/v1.js" async defer></script>

<!-- 2. Drop the widget into your form -->
<form method="POST" action="/signup">
  <input type="email" name="email" required>

  <div class="stopbot" data-site-key="YOUR_SITE_KEY"></div>

  <button type="submit">Create account</button>
</form>

On submit, the widget adds a hidden stopbot_token field to the form. Verify it on your server (below) and you’re done.

Frontend integration

First-class helpers for the most common stacks. Each gives you a verified token to send with your request.

tsx
import { StopBot } from '@stopbot/react';

export function SignupForm() {
  const [token, setToken] = useState<string | null>(null);

  return (
    <form onSubmit={(e) => submit(e, token)}>
      <input type="email" name="email" required />

      <StopBot siteKey="YOUR_SITE_KEY" onVerified={setToken} />

      <button type="submit" disabled={!token}>Sign up</button>
    </form>
  );
}
vue
<script setup>
import { ref } from 'vue';
import { StopBot } from '@stopbot/vue';

const token = ref(null);
</script>

<template>
  <form @submit.prevent="submit(token)">
    <input type="email" v-model="email" required />

    <StopBot site-key="YOUR_SITE_KEY" @verified="token = $event" />

    <button type="submit" :disabled="!token">Sign up</button>
  </form>
</template>
blade
{{-- resources/views/signup.blade.php --}}
<form method="POST" action="{{ route('signup') }}">
    @csrf
    <input type="email" name="email" required>

    <x-stopbot::widget site-key="{{ config('stopbot.site_key') }}" />

    <button type="submit">Create account</button>
</form>
javascript
import { stopbot } from '@stopbot/browser';

const token = await stopbot.solve({ siteKey: 'YOUR_SITE_KEY' });

await fetch('/signup', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, stopbot_token: token }),
});

Server-side verification

Always verify the token on your server before trusting the submission. It’s a single API call.

php
use Illuminate\Support\Facades\Http;

$response = Http::asJson()->post('https://api.stopbot.io/v1/verify', [
    'secret' => config('stopbot.secret_key'),
    'token'  => $request->input('stopbot_token'),
]);

if (! $response->json('success')) {
    abort(422, 'Bot verification failed.');
}

// Proof is valid - continue handling the request.
javascript
const res = await fetch('https://api.stopbot.io/v1/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    secret: process.env.STOPBOT_SECRET_KEY,
    token: req.body.stopbot_token,
  }),
});

const { success } = await res.json();
if (!success) return res.status(422).send('Bot verification failed.');
bash
curl -X POST https://api.stopbot.io/v1/verify \
  -H "Content-Type: application/json" \
  -d '{
    "secret": "YOUR_SECRET_KEY",
    "token": "STOPBOT_TOKEN_FROM_FORM"
  }'

Token reference

A successful verification returns:

json
{
  "success": true,
  "difficulty": 18,
  "solved_at": "2026-06-11T10:24:00Z",
  "hostname": "yourdomain.com"
}

Next steps

We're in private beta. Request an invite to grab your keys and start sending verifications.

Request beta access