The knownprint demo
What knownprint sees about this browser, and under it a playground to wipe it, ban it and run it again.
Who is this browser?
Live on the pilot nodeknownprint runs on this browser when this page loads. It reads your browser's technical characteristics and your IP address, keeps one security event for 30 days (raw data for 7) and a record of this browser's characteristics as derived values until 400 days pass without a run, sets one cookie for up to 400 days plus copies in this site's storage, and remembers which knownprint pages this browser's visitor id has run on, under a keyed hash, for 400 days. Wipe or delete it any time; after a deletion this site keeps one setting in this browser so that it no longer runs here on load. Browsers that send Global Privacy Control or Do Not Track get a button instead. What this stores
Reading this browser 0 ms
- Visits recorded
- Private windows
- Networks
- Location
- coming
Your recent visits
The playground
Wipe this browser and run again, ban yourself, and read everything knownprint recorded.
Run 1 appears here once the panel above has its answer.
Reading this browser
Want this on your signup form? Get early access: one email when you can sign up, the price list first.
For developers
Wire it up
Safari caps cookies written by script at seven days, and cookies served from a third party's address too. knownprint runs from your own domain, so its cookie arrives in your own server's response and Safari does not cap it.
-
Step 1
One proxy rule
Your nginx or Caddy forwards /kp/ to knownprint, so the agent, its endpoints and the cookie are all on your own domain. Only the kp_t cookie leaves your server; your session cookies stay where they are.
nginx, from the knownprint recipe, shortened # Inside your site's TLS server block. The full recipe adds the bundle # location, the cache headers and /.well-known/knownprint.json. # Signup (coming) gives you $knownprint_upstream and the proxy secret. include /etc/knownprint/proxy-secret.conf; location = /kp/agent.js { proxy_pass $knownprint_upstream; proxy_set_header X-Knownprint-Proxy-Secret $knownprint_proxy_secret; proxy_set_header X-Knownprint-Client-Ip $remote_addr; proxy_set_header X-Knownprint-Forwarded-Host $host; proxy_set_header Cookie ""; proxy_hide_header Set-Cookie; } location ^~ /kp/ { proxy_pass $knownprint_upstream; proxy_set_header X-Knownprint-Proxy-Secret $knownprint_proxy_secret; proxy_set_header X-Knownprint-Client-Ip $remote_addr; proxy_set_header X-Knownprint-Forwarded-Host $host; proxy_set_header X-Knownprint-Net ""; # only kp_t leaves your server ($knownprint_cookie, knownprint-map.conf) proxy_set_header Cookie $knownprint_cookie; }Caddy, inside your site block import knownprint -
Step 2
One script tag, and the request id posted with the form
The agent reads the browser and hands the page a request id (
requestId) and its expiry, never the visitor id, the confidence or a verdict to tamper with. The page never learns which browser it is; your backend does. Your form posts the request id (kp_request_id) with the signup.Your page <script src="/kp/agent.js" defer></script> // PUBLIC_KEY is your environment's public key (pk_live_...). const agent = await window.knownprint.load({ pk: PUBLIC_KEY, profile: 'security' }); const { requestId } = await agent.identify(); form.elements.kp_request_id.value = requestId; // posted with the form -
Step 3
One call in your backend, in shadow mode first
Read the event with your secret key, then ask for a verdict. Shadow mode records what knownprint would have done and blocks nothing. Switch to enforce after a week of verdicts.
HTTP, live today GET /v1/events/evt_q3vx7k2mz4rb6nw5tc2ehj7ypd Authorization: Bearer <your secret key> POST /v1/check Authorization: Bearer <your secret key> Content-Type: application/json {"request_id": "evt_q3vx7k2mz4rb6nw5tc2ehj7ypd", "action": "signup", "shadow": true}Node SDK, coming with the SDK release app.post('/signup', kp.require('signup', options), signupHandler);
What comes back
A deny in shadow mode for a browser you banned: the verdict, its reasons, the identity behind it and the counters, for your code to log or act on. The ids are made up.
{
"action": "deny",
"score": 0, coming
"reasons": ["visitor_blocklisted", "shadow_mode"],
"list_hits": [
{
"list": "blocklist",
"subject_type": "visitor",
"subject": "v_m5tk2wq7xr3bz6ne4yc2hv7pja",
"via": "token"
}
],
"identity": {
"visitor_id": "v_m5tk2wq7xr3bz6ne4yc2hv7pja",
"match_type": "token",
"confidence": 1,
"anonymity_set_size": 1,
"device_cluster_id": null,
"cluster_confidence": null
},
"velocity": {
"accounts_visitor_5m": 0,
"accounts_visitor_1h": 0,
"accounts_visitor_24h": 0,
"ips_visitor_5m": 1,
"ips_visitor_1h": 1,
"ips_visitor_24h": 2,
"signups_ip_5m": 1,
"signups_ip_1h": 1,
"signups_ip_24h": 3,
"events_ip_5m": 2,
"events_ip_1h": 4,
"events_ip_24h": 9
},
"human_review_required": true,
"shadow": true,
"check_id": "chk_b7zq2m4kx6vn3rt5wy2ech7pdl",
"request_id": "evt_q3vx7k2mz4rb6nw5tc2ehj7ypd"
}
- What to do:
action(allow, challenge or deny). - Why, in codes that never change meaning:
reasons. - Which of your lists matched, and how:
list_hits. - Which browser, how it was recognised, how sure, and how many look alike:
identity. - Counts over 5 minutes, an hour and a day:
velocity. - Whether a person should look before you act:
human_review_required. - Whether this was a dry run that blocked nothing:
shadow.
score: 0 until the suspect score arrives coming
What you get
Every field
Someone on your team asks whether two accounts came from the same browser. The answer should come with its working. Everything below is live on the pilot today, and the panel above shows most of it on your own browser.
Identification
Recognise a returning browser, with or without its cookie.
visitor_idmatch_typeDecide how far to trust a match: meant as a probability, capped where the data is thin.
confidenceSee how many browsers look like this one, so a common setup never reads as sure.
anonymity_set_sizeRead why it matched, or why it refused to.
evidenceWhen knownprint will not link, get the likely candidate, if there is one, for review.
high_recall_idSpot a second browser on the same hardware and network.
device_cluster_idcluster_confidencePull every visit of a browser, an account, a device cluster or an address.
GET /v1/eventsGET /v1/visitors/{id}
Signals
Stop scripted signups, and know which tool ran them.
signals.botdetail.bot_typeKnow when a browser blurs or hides its fingerprint.
signals.privacy_settingsprotection_flagsKnow when a visit comes from a private window.
signals.incognitoRead the browser, engine and OS as knownprint classified them.
browserKeep the address and network block for your own lists, and know which network signals were measured.
network.ipnetwork.ip_prefixnetwork.availabilityCatch replayed and forged requests.
integrityCheck what the agent costs your page, source by source.
timings
Proof
How we measure
You have been quoted an accuracy figure before. Ask for the corpus behind it and the call goes quiet. Here is the honest version: what every event tells you, how we test it, and what we have not measured yet.
Read the confidence, not a claim
- See how many browsers look like this one before you act (
anonymity_set_size). - Know which signals could not be measured, instead of getting a guess: every event says how much of the network knownprint saw (
network.availability), absent values stay null, and below full the bot confidence is capped at 0.7. - Confidence is meant as the probability that the match is right, and it is capped where the data is thin: an exact match at 0.95, or at 1 divided by the number of browsers that share its fingerprint when that is lower, and a linked match at 0.8 until the pilot has confirmed 400 matches for its browser family.
- When knownprint refuses to link, it still names a likely candidate for your review when it has one (
high_recall_id), and a ban on that candidate answers challenge, never deny.
How we test it
G0, every commit: synthetic browsers in CI, in gate mode. A change that breaks stability, uniqueness or cost fails the build.
GatingG1, nightly: the lab's corpus of real browsers. It reports until it holds 3,000 hard negative and 400 positive real pairs, then it gates. On it held 0.
ReportingG2, weekly: labelled pairs from the pilot, and never blocking. It has not run yet.
Not run
Targets, and where they stand
Target: pairwise precision (of the visits knownprint links, the share that really are one browser) at least 0.995. Status: not yet measured on real pairs (G1 holds 0 real pairs; G2 has not run), as of .
Target: recall (of the visits that really are one browser, the share knownprint links) at least 0.90 on desktop after 7 days. Status: not yet measured on real pairs (G1 holds 0 real pairs; G2 has not run), as of .
Target: evader recall (the same, for banned users who come back) at least 0.80 on desktop after 7 days. Status: measured only by G2 on pilot pairs, which has not run, as of .
Target: calibration error (how far the stated confidence strays from the share of matches that are right) below 0.02. Status: not yet measured on real pairs (G1 holds 0 real pairs; G2 has not run), as of .
No accuracy percentage appears on this page until the lab publishes one with its gate.
What we have measured
Identify, p95 Identify: 95 of every 100 identifications answered within 33.96 ms (p95), match included, at 200 identifications a second against a gate of 40 ms, measured in CI on synthetic data on the self-hosted gate runner on (G0); on that runner the same code also read 41.71, 55.52 and 130.83 ms in its other gate runs that day, and older unchanged code reads from 33.76 to 45.65 ms from run to run, so read it as a range until the runner question is settled (A-161, open).
Check, p95 Check: p95 3.86 ms at about 200 checks a second, against a gate of 50 ms, measured in CI on synthetic data on the self-hosted gate runner on (G0).
The pilot
Live traffic, not a gate Since knownprint has run as a shadow pilot on a live community site: it records verdicts and blocks nothing. A count of live traffic, not a gate result: in the 24 hours before its upgrade at 21:34 UTC on , the pilot node answered 5,802 identify requests in total, by its own request log. That upgrade moved it to identification v2.2 and wiped its collected data first, so its history starts again from that day.
Per-site switches
comingThree behaviours stay off unless your site turns them on. Each switch says in plain words what it does and records that you turned it on.
- Token respawning: refill a cleared cookie or copy from the one that survived. Turning it on records your acknowledgement, and your disclosure file and notice say that your site does it.
- Cluster deny: deny, instead of challenge, when a blocklisted device cluster comes back. A cluster is hardware plus a shared network and can include someone else's browser; the switch records your acknowledgement of that.
- Network links: challenge or deny a browser on the same home connection as a banned one. VPNs, proxies, Tor, datacentres and, by default, any connection with more than 10 visitors a day are left out, and deny needs your acknowledgement.