Integration guide
Get stopbot protecting a form in a few minutes: add the widget, then verify the proof on your server.
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.
<!-- 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.
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>
);
}
<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>
{{-- 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>
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.
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.
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.');
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:
{
"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