solvegate — Cloudflare Turnstile solver API client for Node

Official Node/TypeScript client for the SolveGate API — clears
Cloudflare Turnstile (managed, non-interactive, invisible) and Turnstile WAF
challenge pages and returns a token. Dependency-free (global fetch, Node ≥ 18); wraps
auth, the error envelope, 429 backoff and async polling.
Built for Playwright, Puppeteer and Selenium suites, CI pipelines and synthetic
monitoring against sites you own or are authorised to test.
Get 1,000 free solves — no card required →
npm install solvegate
import { SolveGate } from "solvegate";
const sg = new SolveGate(process.env.SOLVEGATE_KEY!);
const { token, solve_ms } = await sg.solve({
gate: "turnstile",
sitekey: "0x4AAAAAAAAA_target",
url: "https://app.example.com",
});
Async submit, then poll:
const pending = await sg.solve({ gate: "waf", sitekey: "0x4…", url: "…", async: true });
const done = await sg.wait(pending.id, { timeoutMs: 60_000 });
Does it solve reCAPTCHA or hCaptcha?
No. Turnstile and Turnstile WAF only — not reCAPTCHA, hCaptcha, GeeTest, FunCaptcha,
DataDome or AWS WAF. If your flow hits any of those, use a general-purpose service.
Testing your own app? You may not need this
Cloudflare publishes dummy sitekeys that always pass, work on localhost, and cost nothing:
1x00000000000000000000AA (sitekey) with 1x0000000000000000000000000000000AA (secret).
Point staging at those and the widget stops being a problem. See
Cloudflare's testing docs.
Solving is for what test keys cannot cover — a staging environment whose Turnstile config
you do not control, or monitoring that must exercise the real production path.
Playwright
const sitekey = await page.locator("[data-sitekey]").first().getAttribute("data-sitekey");
const { token } = await sg.solve({ gate: "turnstile", sitekey, url: page.url() });
await page.evaluate((t) => {
document.querySelector<HTMLInputElement>('[name="cf-turnstile-response"]')!.value = t;
}, token);
See playwright-turnstile for a fixture
that handles waits, explicit-render widgets and WAF detection properly.
Errors
import { SolveGateError } from "solvegate";
try {
await sg.solve({ gate: "turnstile", sitekey, url });
} catch (e) {
if (e instanceof SolveGateError) {
console.error(e.status, e.code, e.billed);
}
}
balance_empty · pass_expired · forbidden_target · unknown_sitekey · rate_limited ·
solve_timeout. Failed solves are never billed.
Pricing
Prepaid credits, one credit per successful solve: $0.40 per 1,000 on the smallest pack
down to $0.075 per 1,000 on the largest. First 1,000 solves free; credits do not expire.
Full ladder →
Intended use
Properties you own or are explicitly authorised to test — E2E/QA, CI, uptime and synthetic
monitoring, staging, anti-bot configuration testing. Third-party use in breach of a site's
terms is prohibited by the Acceptable Use Policy.
Links
Docs · API reference ·
OpenAPI · Status ·
Source
MIT