Skip to content
Trustaige Docs

HumanProof without a form

Protect downloads, votes and costly actions with HumanProof. Listen for the proved event, send the token to your server, and use the API in single-page apps.

View as Markdown

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
CallDoes
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