# 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.

Source: https://docs.trustaige.com/humanproof/without-a-form

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

```html title="report.html" {1,3}
<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>
```

```js title="report.js"
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](/humanproof#quickstart), and only then returns the
download link.

## In a single-page app

Call `HumanProof.render` when your view appears.

```js title="app.js"
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. |

> **Note:** Whatever HumanProof unlocks must stay locked when it can't load, the same as
> behind any CAPTCHA that fails. Tell the person why, rather than letting the
> action through.
