Browser setup
Updated
A quick guide to set up your frontend. One script tag protects every form on the page.
The script's one request fetches a challenge. Try it with your public key:
curl "https://bot403.com/api/v1/challenge?pk=pk_live_YOUR_PUBLIC_KEY"
The script adds a hidden field with the solved challenge to every form. Full guide
<!-- 1. Load the script once, with your public key -->
<script src="https://bot403.com/v1/bot403.js" data-bot403-key="pk_live_YOUR_PUBLIC_KEY" async></script>
<!-- 2. Keep your form as it is. Every form on the page is protected -->
<form action="/contact" method="POST">
<input type="email" name="email" required>
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>
<!-- 3. On your server, post the _bot403 field to /api/v1/verify. See the server tabs. -->Loads with the page and solves a fresh challenge for every submit. Full guide
// npm install @bot403/browser, or load the script tag and call Bot403.solve()
import { solve, FIELD } from "@bot403/browser";
// 1. Get a token. The proof of work runs in a Web Worker
const token = await solve("pk_live_YOUR_PUBLIC_KEY");
// 2. Send the token with your data. Your server posts it to /api/v1/verify
await fetch("/contact", {
method: "POST",
body: new URLSearchParams({ email: "[email protected]", message: "Hello", [FIELD]: token }),
});Loads with the page and solves a fresh challenge for every submit. Full guide
// npm install @bot403/react
import { useBot403, FIELD } from "@bot403/react";
export function ContactForm() {
// 1. Loads the script on mount; getToken() returns a fresh single-use token
const getToken = useBot403("pk_live_YOUR_PUBLIC_KEY");
async function onSubmit(e) {
e.preventDefault();
const body = new URLSearchParams(new FormData(e.currentTarget));
// 2. Add the token before you post the form to your server
body.set(FIELD, await getToken());
await fetch("/contact", { method: "POST", body });
}
return (
<form onSubmit={onSubmit}>
<input name="email" type="email" required />
<textarea name="message" required />
<button>Send</button>
</form>
);
}HTML forms
Keep the form as it is. The script solves the puzzle when a visitor focuses a field and adds the _bot403 field before the submit. If the visitor submits before the answer is ready, the script holds the submit for up to 10 seconds, then lets the form go.
JavaScript (fetch)
window.Bot403.solve(), or solve() from the @bot403/browser package, returns a promise with a fresh token. Each token works one time. Ask for a new one for each request. The call takes about 0.2 seconds on a laptop and up to 2 seconds on an old phone.
React
The @bot403/react package has a hook that loads the script and returns a fresh token on each submit; the React tab above shows it. Forms that React renders later are found by a MutationObserver, so a plain <form> that posts to your server also works with no hook.
Choose which forms to protect
Load the script without a key and put data-bot403-key="pk_live_YOUR_PUBLIC_KEY" on the forms you want protected. A form attribute also overrides the script key, so one page can use two sites.
Next: verify the token on your server. All attributes and the JavaScript API are on the script options page.