DeSpoof
Liveness check for websites

Check a real person is there before you let them through.

A script tag on your page, and one call from your server to confirm what happened. The camera opens on our domain, the numbers are judged on our servers, and your site gets back a plain yes or no.

100 checks a month, free. No card, no server SDK, no photos kept.

Live reading Person present
Head angle
Eye openness
turn left 21° blink 0.71 jitter 0.031 score 0.94

No photo, ever

The camera view is measured on the device and thrown away. Nothing is uploaded, nothing is written to disk, and there is no thumbnail in anyone's dashboard.

No face data at all

What reaches us is a handful of numbers about movement and timing. There is no face map, no template, and nothing that could be matched against a person anywhere else.

Nothing to leak

A breach of DeSpoof cannot expose the people who used your site, because we never held anything that identifies them.

What it stops

Put a person in front of the actions that cost you the most.

You choose where the check appears. Everything else on your site stays exactly as it is.

Sign-ups that are not people

A script can fill your form a thousand times an hour. It cannot turn its head when asked to.

Reviews written in bulk

Ask for a check before a review posts and the cost of a fake review stops being close to zero.

Marketplace listings

One listing needs one person. A seller running a hundred throwaway accounts has to show up for each of them.

Password resets

Add a person to the most impersonated step you have, without adding another code to type.

First messages

Let people browse freely, then ask for a check the first time they contact someone.

Anything you name

Tag the button, give it a reference, and read that reference back when you confirm the result.

Who it is for

If you can edit your own pages, you can have this running today.

MarketplacesSellers, listings and first contact
Review sitesOne person, one opinion
Community forumsRegistration and first post
SaaS sign-upsFree trials that stop being farmed
Ticketing and dropsQueues that hold real buyers
Client portalsConfirm a person before a sensitive change
How it works

Three seconds for them. Two moving parts for you.

The camera opens in a frame on our domain, so your site never asks for camera permission and never receives the video.

They press your button

Your own button, your own wording, wherever the sensitive action lives.

They follow two prompts

Turn, blink, move closer. Spoken out loud if you want, and shown on screen if not.

They carry on

The camera shuts off, the frame closes, and they are back where they were.

Paste the tag

One script, one attribute on the button. Nothing else on your page changes.

Confirm it on your server

The widget hands your backend a short-lived code. One HTTP call turns it into a result you can trust.

Decide what happens

Allow the action, hold it for review, or ask for another attempt. That part stays yours.

Your controls

Tighten it, loosen it, or throttle it, without touching your site.

Every setting lives in the dashboard, so nobody can edit your page to ask for less.

How strict the check is

Three levels, applied to every measurement on our side. Move it up when abuse spikes and down when real people start failing.

Relaxedfewest retries
Normaldefault
Stricthardest to fake

Which prompts run

Turn on the checks you want and set how many are asked each time. The order is picked fresh for every attempt, so a recording of one attempt is no use for the next.

Blinkon
Turn left, turn righton
Move closer, nod, smile, open mouthoptional

How often one visitor can try

Set a cooldown between attempts and a ceiling per hour and per day, counted per connection. It protects your monthly allowance from anyone trying to burn through it.

Cooldown20 seconds
Per hour10 attempts
Per day30 attempts
Developers

One tag on the page. One call on the server. That is the whole integration.

There is no SDK to install and no API surface to learn. The widget runs the camera, the states and the retries. Your server makes a single request to find out what happened.

<!-- anywhere before </body> -->
<script src="https://widget.despoof.com/widget_v1.js"
        data-app="dsp_live_8x2kq4m"></script>

<!-- your own button, styled however you like -->
<button data-despoof="verify"
        data-despoof-ref="signup"
        data-despoof-then="submit">
  Continue
</button>

The button keeps its own styling. data-despoof-then="submit" posts the form it sits in once the check passes, with the code added as despoof_code.

// Fires in the browser. Use it for your interface only.
DeSpoof.on('verified', function (e) {
  // e.code is short lived. Send it to your server.
  fetch('/despoof/confirm', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code: e.code, reference: e.reference })
  });
});

DeSpoof.on('failed', function (e) {
  // e.reason: camera_denied | action_not_seen | low_confidence
  //           face_not_held | timeout | quota_exceeded
  showMessage(e.reason);
});

Set a callback URL in the dashboard and the widget posts the code there for you, so this step is optional.

// On your server. This is the only result worth trusting.
const r = await fetch('https://widget.despoof.com/verify.html', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + DESPOOF_SECRET,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ code })
});

const check = await r.json();
if (!check.success) return deny(check.error);

allowSignup();

A code works once and expires in two minutes, so there is nothing worth intercepting or replaying.

{
  "success": true,
  "app": "dsp_live_8x2kq4m",
  "reference": "signup",
  "score": 0.94,
  "strictness": "normal",
  "checks": ["turn_left", "blink"],
  "verified_at": "2026-08-07T04:19:52Z",
  "duration_ms": 5140,
  "origin": "https://your-site.com",
  "ip": "203.0.113.24",
  "browser": "Chrome 141",
  "os": "macOS 15.3",
  "device": "desktop"
}

Keep this next to your own record of the action. It is the evidence that a person was present, and it contains nothing about who they were.

Dashboard

See what happened, without seeing who it was.

Every attempt is listed with the time, the connection it came from, the browser, the prompts that were asked and the reason it passed or failed. There is no image to look at, because there never was one.

Change strictness, prompts, throttling, approved websites and your callback URL whenever you like. Your page never has to be touched again.

Create an account
despoof.com/dashboard
passed signup turn_right, blink Chrome 141 · 09:41
passed review blink, move_closer Safari 18 · 09:38
failed signup no_natural_movement Chrome 141 · 09:36
failed signup ip_hourly_limit Chrome 141 · 09:36
passed listing turn_left, nod Android 15 · 09:29
Pricing

You pay for checks that passed. Nothing else counts.

Failed attempts, blocked attempts and anything stopped by your own throttle are free.

Free

$0
per month
  • 1 website
  • 100 checks a month
  • Every control included
Start free
Most sites land here

Basic

$19
per month
  • 2 websites
  • 1,000 checks a month
  • Every control included
Choose Basic

Growth

$39
per month
  • 5 websites
  • 10,000 checks a month
  • Email support
Choose Growth

Mega

$159
per month
  • Unlimited websites
  • 60,000 checks a month
  • Email support
Choose Mega

Go past your allowance and we email you. Nothing switches off in the middle of the month.

Questions

The things people ask before they paste the tag.

Do you keep a photo of anyone?

No. There is no image, no video, no face map and no thumbnail, at any point. The camera view is measured on the device and the measurements are numbers about movement, timing and eye openness.

That is a deliberate limit on what the product does. DeSpoof tells you a live person followed instructions. It does not tell you who they were, and it cannot be turned into a way of finding out.

Could someone just fake the result on their own page?

No, and this is the reason for the one server call. The browser never receives a pass or a fail it could forge. It receives a code, which only means something once your server exchanges it with us.

The check itself runs in a frame on our domain, the measurements are judged on our servers, and the code is single use, tied to the website that asked for it, and dead after two minutes.

What stops someone burning through my monthly allowance?

Three things. Your widget only runs on the websites you list, so the tag cannot be lifted and used elsewhere. Attempts are throttled per connection, with a cooldown and hourly and daily ceilings that you set. And only successful checks count towards your plan.

What about people who cannot use a camera?

Some will not have one, some will refuse permission, and some will be in a dark room. Decide the way through before you go live: hold the action for review, fall back to email confirmation, or let it pass and flag it.

The widget reports the reason it did not finish, so your code can tell a refused camera apart from a failed check.

How well does this actually stop bots?

It makes automated abuse expensive rather than impossible, and we would rather say that plainly. A script cannot pass it. A recorded video does not survive a prompt order it has not seen. A person paid to sit in front of a camera can pass it, once, for each account they are paid to make.

That is the honest shape of it: liveness proves a person is present, not which person, and not who they are acting for.

Do I need to tell my users anything?

Yes. Camera use needs to be explained and agreed to, and your privacy policy should say what happens. The widget shows a short consent line before the camera opens, and the wording is yours to edit in the dashboard.

Which browsers and devices work?

Any current browser with a camera, on desktop and mobile. If your pages send a restrictive permissions policy header, add camera=(self "https://widget.despoof.com") to it, otherwise the browser will block the camera inside the frame.

A bot can fill in your form. It cannot turn its head.

Paste one tag, add one server call, and put a person in front of the actions that matter. 100 checks a month, free.

Start free