Profiles REST API

Fingerprints

Generated from real-device distributions, and checked for coherence before they are ever used.

Generate a fingerprint

POST/api/v1/fingerprints/generate

Draws a complete identity — a machine, a browser build, a locale — from a catalogue of devices people can actually buy. The hardware half comes out of one catalogue row rather than three independent tables: the GPU and its ANGLE renderer string, the hardwareConcurrency values that model ships with, and the displays it actually has. Drawing them separately is how an Apple M3 Max used to arrive beside a 13-inch MacBook Air panel — each value the most popular in its own column, the combination a machine nobody sells. The result is validated before it is returned and redrawn if it fails, so you never receive a Direct3D renderer on macOS. Pass a seed to reproduce an identity exactly, or deviceId to pin the machine and let everything else vary.

Body

FieldTypeWhat it is
deviceIdstringDraw this exact machine from the catalogue — see GET /fingerprints/devices. A phone id implies os: "android", so it is enough on its own. An unknown id falls through to a normal draw rather than failing, so a stale id in a saved template cannot stop a profile being created.
os"windows" | "macos" | "linux" | "android"Force a platform. Any desktop platform or android can be made on any computer, and the profile is drawn coherently for the platform it claims — a Windows profile gets a Windows GPU, screen and thread count. The host’s own desktop platform still matches best: the fonts installed, their metrics and how they rasterise come from the real machine, and no switch reaches them. Measured on a macOS host: claiming macOS scored 100/100 on IPHey, claiming Windows 80/100, and claiming Linux showed 1 font against 159. A foreign desktop is accepted with that caution in the editor, never refused. android draws a whole captured phone — screen, DPR, thread count, touch points and the entire WebGL record from one real device, never mixed with a table.
brand"Chrome"Browser brand, and there is one. Edge is a 400: its User-Agent suffix and the client-hint version lists are built from the same switch, so the engine can produce a correct Edge User-Agent or a correct Sec-CH-UA-Bitness, never both.
countryCodestringISO country, used to pick a coherent locale and timezone.
timezonestringIANA zone, overriding the country’s default.
languagesstring[]BCP-47 tags; also sets Accept-Language.
seedstringReproduce a specific identity. Omit for a new one.

Returns

A complete Fingerprint.

Errors

  • 400 — the options are mutually unsatisfiable and no coherent identity exists.

Regenerate a profile’s identity

POST/api/v1/profiles/:id/fingerprint/regenerate

Replaces the profile’s fingerprint with a new one, preserving any fields the profile has locked. Refused while the profile is running.

Path parameters

FieldTypeWhat it is
idrequiredstringThe record’s id.

Body

GenerateOptions. Same options as the generator.

Returns

The updated Profile.

Check a profile’s identity for contradictions

POST/api/v1/profiles/:id/fingerprint/validate

Answers two separate questions about the stored fingerprint. problems lists what is impossible on any machine — a GPU backend that does not exist on the chosen OS, a screen with no taskbar inset, a browser version that disagrees with its own User-Agent. warnings lists what is possible somewhere but not on this machine: a claimed platform the engine cannot back below JavaScript, a GPU vendor that contradicts navigator.gpu, a chip beside a core count it never shipped with. The generator never produces either; both come from hand-editing, and neither blocks a save.

Path parameters

FieldTypeWhat it is
idrequiredstringThe record’s id.

Returns

{ problems: string[], warnings: [{ field: "os"|"gpu"|"screen"|"hardwareConcurrency"|"browserMajor", title, detail }] }

List the real devices a profile can claim

GET/api/v1/fingerprints/devices

The device catalogue, as choices. Each entry is one machine somebody can buy — its GPU as the driver names it, the hardwareConcurrency values that model ships with, the memory configurations it comes in, and the displays it actually has. Pass an id back as deviceId to POST /fingerprints/generate to draw that exact machine.

The Android rows are captured phones rather than entries assembled from tables: one row is one device, and its screen, DPR, thread count, touch points and whole WebGL record were read off the same handset. A phone id such as sm-s918u implies os: "android" on its own, so naming one is enough to draw a phone.

backed says whether this computer can stand behind the claim, and it turns on two things a page reads directly: the OS, because fonts and their metrics come from the real machine and no switch reaches them, and the GPU vendor, because navigator.gpu is not injected and reports the real adapter from a worker realm. The thread count is deliberately not one of them — Emulation.setHardwareConcurrencyOverride is applied by Chromium itself, so it holds in every realm. For a phone it is one question rather than three: whether this engine moves the whole mobile record below JavaScript. Machines that fail backed are still listed, because a profile may be destined for a different computer; they are marked rather than hidden, and choosing one raises a warning from the audit rather than an error.

Query parameters

FieldTypeWhat it is
os"windows" | "macos" | "linux" | "android"Only this platform’s machines.
backed"true"Only machines this computer can stand behind.

Returns

{ total, devices: [{ id, label, chip, os, cores: number[], memory: number[], screens: string[], backed: boolean, gpu: GpuSpec }] }

Errors

  • 400 — os is not one of the four platforms.

Check a fingerprint that has not been saved

POST/api/v1/fingerprints/audit

The same two checks as /profiles/:id/fingerprint/validate, against a fingerprint in the request body rather than a stored profile. This is what the editor calls while someone is still choosing: it lets a draft identity be checked before it belongs to anything. Send a whole fingerprint, as returned by POST /fingerprints/generate — a partial object is refused rather than half-checked, because a missing field would silently read as a coherent one.

Body

Fingerprint. A whole fingerprint object.

Returns

The same shape as /profiles/:id/fingerprint/validate.

Errors

  • 400 if the body is not a whole fingerprint.

Run a detection audit

POST/api/v1/profiles/:id/audit

Drives the live browser through the probes a CreepJS-class detector uses: worker and iframe realm agreement, Function.prototype.toString integrity, property-descriptor shape, timezone against getTimezoneOffset, screen geometry, and automation traces such as navigator.webdriver, cdc_ symbols and window.chrome. Starts the profile headlessly if it is not already running, and stops it again afterwards.

Path parameters

FieldTypeWhat it is
idrequiredstringThe record’s id.

Returns

{ passed, score, checks: [{ id, label, status: "pass"|"warn"|"fail", detail }], ranAt }

Get a fresh seed

GET/api/v1/seed

A random seed value suitable for the generator, when you want to record it before generating.

Returns

{ seed: string }

Next Try it on your own accounts

Run the API on your own profiles

The REST API and the MCP server are part of Pro: $49 a month, with the first 14 days free. Free has every browser feature and no API key.