Solve a DataDome captcha ( dd.t = fe /check ) Give it the captcha URL, get the datadome cookie back.
It runs the site's own challenge bundle inside a node:vm against a synthetic browser. Nothing
drives the challenge UI — there is no automated clicking or dragging
It fetches c.js, the challenge document and its assets the way a browser would, then submits
/captcha/check. It never touches the protected site; verifying the cookie against it is your job
npm install github:buggerlogger/datadome-captcha-solverimport { solveCaptcha } from 'datadome-captcha-solver';
const result = await solveCaptcha(
'https://geo.captcha-delivery.com/captcha/?initialCid=...&hash=...&cid=...&t=fe&s=...&e=...&dm=cd'
);
result.cookie; // "ABC~xyz..." -> send as Cookie: datadome=<cookie>
result.setCookie; // the full Set-Cookie string, attributes included
result.payload; // the encoded ddCaptchaEncodedPayload
result.plv3; // the plv3 blob
result.queryString; // the full /captcha/check query
result.ok; // a cookie came backThe URL comes from the 403 the protected site served you — its body carries
var dd = {cid, hsh, t, s, e, ...} and the iframe URL is built from those. tools/fetch.mjs does
that for you:
node tools/fetch.mjs https://site.example/logintransport uTLS chrome_win10 via fetch.exe proxy=direct
status 403 x-dd-b=1
challenge t=fe (slider captcha)
captcha url (pass this to solveCaptcha):
https://geo.captcha-delivery.com/captcha/?initialCid=...&t=fe&...
Add --json for a machine-readable object; challengeFor(pageUrl) is exported for the same thing.
It exits non-zero and tells you when the page is not a captcha this solver handles:
status 403 x-dd-b=2
challenge t=bv (behaviour interstitial)
solveCaptcha makes the same check on the URL you hand it and refuses anything that is not t=fe.
The cid, e and initialCid in that URL are one-shot, but they are spent by /captcha/check,
not by fetching the document — you can look at the challenge without burning it.
await solveCaptcha(captchaUrl, {
canvasFrames, // seven "data:image/png;base64,..." frames (see below)
device: generateDevice(), // a random coherent device; omit for the base profile
referer: 'https://site.example/login',
});import { buildPayload } from 'datadome-captcha-solver';
const { queryString, payload, plv3, checkUrl } = await buildPayload(html, captchaUrl);For authorised security testing and research.