WhiskerJS runs in your web page and gives you one JSON object describing the browser and device. These guides show how to get that object at the right moment (when someone signs in, signs up or pays), send it to your server with the request you already make, and check on the server that it is fresh and was not changed on the way. What you then decide with it is up to your own rules.
How the pieces fit
Every guide uses the same small contract between the page and your server, so you can mix any browser guide with any server guide.
browser your server
------- -----------
GET /api/whisker-nonce -> make a nonce (128 random bits) and note the time,
<- store both for this session: { nonce, timestamp }
user presses "Sign in"
collect({ timeoutMs: 3000, binding }) (in the browser, 46 signals, no network)
POST /api/login { email, password, device }
-> verify the binding: nonce known, unused, recent,
versions and component names as shipped, digest matches
<- then your own decision (password, rules, history)
| Endpoint | Method | Body | Answer |
|---|---|---|---|
/api/whisker-nonce |
GET | none | { "nonce": "<32 hex>", "timestamp": <ms> } |
/api/login (your existing form post) |
POST | your fields plus device: the WhiskerJS result |
your usual answer; a refused binding gives an error code such as unknown_or_used_nonce or digest_mismatch |
The names are examples: use your own routes. The only rule is that the nonce endpoint and the form post belong to the same session, so that a nonce issued to one visitor cannot be used by another.
Browser side
Server side
Rules every guide follows
- Collect at the moment you need it. On submit of a login, sign-up or checkout form, not on every page view.
collect()takes up totimeoutMs(the guides use 3000 ms) and briefly works on the main thread. - Only in the browser. WhiskerJS reads the browser it runs in. In frameworks that render on the server (Next.js, Nuxt, SvelteKit, Astro), call it only from an event handler or an effect that runs in the browser, never while rendering.
- A secure context. Hashing uses Web Crypto, which browsers offer only on https pages (and on
http://localhostwhile you develop). Without itvisitorIdandstructuredIdarenulland large components reportunavailablewith ruleIdno_digest. collect()never throws and never rejects. You do not need a try block around it. You do need one around your ownfetchcalls, which can fail like any request.- Send the result unchanged. The binding digest covers every field, so do not trim or reorder it before it reaches the server check. It is about 4 KB of JSON.
- The server decides. WhiskerJS gives signals and integrity flags, not verdicts. A valid binding proves the result is fresh and unchanged since it was made, not that the browser told the truth. See what never to trust from the client.
Install (all guides)
WhiskerJS is not on npm yet; the npm package is coming. Build it from source and install the tarball, or copy the built files:
cd whiskerjs # the WhiskerJS source folder
pnpm install && pnpm build # writes dist/
pnpm pack # writes whiskerjs-0.1.0.tgz
cd ../my-app
npm install ../whiskerjs/whiskerjs-0.1.0.tgz
Getting started covers the build in more detail.
How these guides were tested
Each code sample on these pages was run on 2026-10-26 with WhiskerJS 0.1.0 (signalsVersion 5, idVersion 2), built from source:
- every browser sample was built with its framework, served next to the server sample from the matching guide, and driven by headless Chromium 140 (Playwright 1.55.0): it filled in the form, submitted it, and checked that the server accepted the binding and refused the same result when it was sent a second time;
- every server sample was also run against three real results made by headless Chromium, Firefox and WebKit, and refused a result with one changed component value, a reused nonce and a result older than 60 seconds.
Each page names the runtime versions it was tested with.
Questions and answers
Which guide do I need?
Usually two: one for the browser side (the framework your login or checkout page uses) and one for the server side (the language your API is written in). The two talk through two endpoints that every guide uses the same way.
Can I use WhiskerJS without the anti-replay binding?
Yes. Leave out the binding option and the result has binding: null. You then lose the protection against a recorded result being sent again later, so the server guides recommend using it for logins, sign-ups and payments.
Is WhiskerJS on npm?
Not yet; the npm package is coming. Until then you build it from source, run pnpm pack and install the tarball it writes, or serve the files in dist/ as ES modules.