Not everything worth protecting is a form. To gate a download, a vote, a text
message code or an expensive action, put data-humanproof on any element: the
widget is drawn inside it. When the person proves, the element fires
humanproof:proved with the token in event.detail.token. Send it to your
server before you unlock anything.
On a page
<script src="https://id.trustaige.com/humanproof.js" defer></script>
<div id="report" data-humanproof></div>
<a id="download" hidden>Download the report</a>
<script src="/report.js" defer></script>
const gate = document.getElementById('report');
gate.addEventListener('humanproof:proved', async (event) => {
const res = await fetch('/unlock', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: event.detail.token }),
});
const { url } = await res.json();
Object.assign(document.getElementById('download'), { href: url, hidden: false });
});
// HumanProof could not load here. The download stays locked, as behind any CAPTCHA that fails to load.
gate.addEventListener('humanproof:unavailable', () => explain('We couldn’t check that you’re human. Reload to try again.'));
Your /unlock route checks the token exactly as a form handler would, with
the verify endpoint, and only then returns the
download link.
<script src="https://id.trustaige.com/humanproof.js" defer></script>
<div id="report" data-humanproof></div>
<a id="download" hidden>Download the report</a>
<script src="/report.js" defer></script>const gate = document.getElementById('report');
gate.addEventListener('humanproof:proved', async (event) => {
const res = await fetch('/unlock', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: event.detail.token }),
});
const { url } = await res.json();
Object.assign(document.getElementById('download'), { href: url, hidden: false });
});
// HumanProof could not load here. The download stays locked, as behind any CAPTCHA that fails to load.
gate.addEventListener('humanproof:unavailable', () => explain('We couldn’t check that you’re human. Reload to try again.'));In a single-page app
Call HumanProof.render when your view appears.
HumanProof.render(element, {
onProof: (token) => unlock(token),
onUnavailable: () => explain('We couldn’t check that you’re human. Reload to try again.'),
});
HumanProof.reset(element); // after a proof is used, ask for a fresh one
HumanProof.remind(element); // they pressed on without proving: point them at it
| Call | Does |
|---|---|
HumanProof.render(element, options) | Draws the widget in element. onProof gets the token; onUnavailable runs when HumanProof can’t load or the browser can’t hold a passkey. |
HumanProof.reset(element) | A token works once: after using one, asks for a fresh one, without another tap if the person proved recently. |
HumanProof.remind(element) | Points the person at the check when they try to go on without proving. The widget explains the rest, including how to get a passkey. |
HumanProof.render(element, {
onProof: (token) => unlock(token),
onUnavailable: () => explain('We couldn’t check that you’re human. Reload to try again.'),
});
HumanProof.reset(element); // after a proof is used, ask for a fresh one
HumanProof.remind(element); // they pressed on without proving: point them at it