AbuseGraph + Cloudflare Workers
Browser SDK on Pages — Worker proxies toCheckBody to abusegraph.com with sk_ secrets.
Quick path
- Init the browser SDK with
pk_test_…on your site. - Store
ABUSEGRAPH_SECRET_KEYandABUSEGRAPH_SITEas Worker secrets. - Worker receives
toCheckBodyfrom the client and POSTs tohttps://abusegraph.com/api/v1/check.
Keys
| Key | Env | Use |
|---|---|---|
| Secret | ABUSEGRAPH_SECRET_KEY (sk_test_… / sk_live_…) | Server /api/v1/check |
| Publishable | NEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY (pk_test_…) | Browser SDK |
| Site | ABUSEGRAPH_SITE | DNS-verified domain |
Free includes 1,000 live API checks / month after DNS verify. Test keys never bill.
Env
Worker secrets (set via your Workers secrets UI or CLI):
ABUSEGRAPH_SITE=yourdomain.com
ABUSEGRAPH_CHECK_URL=https://abusegraph.com/api/v1/check
ABUSEGRAPH_SECRET_KEY=sk_test_…
NEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY=pk_test_…Use sk_live_… / pk_live_… in production after DNS verify.
Server check
Workers use fetch — POST to https://abusegraph.com/api/v1/check. Events: signup | login | password_reset | email_change. Optional sessionId.
Browser signals (recommended)
Load the browser SDK from the AbuseGraph CDN before your signup/login code. The publishable key is safe to expose; send the resulting body to your own backend, which makes the authoritative check with its server-held secret key.
<script src="https://abusegraph.com/sdk/abusegraph.min.js"></script>
<script>
const sdk = AbuseGraph.init({ publicKey: "pk_test_…" });
async function collectForAuth(email, event = "signup") {
const collected = await sdk.collect();
const evaluated = await sdk.evaluate(collected, { email });
return sdk.toCheckBody(collected, {
email,
event,
verdictToken: evaluated.verdictToken?.token,
});
}
</script>POST the returned JSON to your own endpoint. Never treat the browser result as the authoritative decision or put an sk_ key in browser code.
Cloudflare Worker proxy
Route the signup and login actions separately so the Worker chooses the event from the route, not from untrusted browser JSON. Invoke this check in the server-side signup/login handler before creating the account or session; a browser-only call is not an enforcement boundary.
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method !== "POST") {
return new Response("Method not allowed", { status: 405 })
}
const path = new URL(request.url).pathname
const event = path === "/api/signup-risk-check"
? "signup"
: path === "/api/login-risk-check"
? "login"
: null
if (!event) return new Response("Not found", { status: 404 })
const { email, ...browserFields } = await request.json()
const res = await fetch(
env.ABUSEGRAPH_CHECK_URL ?? "https://abusegraph.com/api/v1/check",
{
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": env.ABUSEGRAPH_SECRET_KEY, // sk_test_…
"x-abusegraph-site": env.ABUSEGRAPH_SITE,
},
body: JSON.stringify({
...browserFields,
email,
site: env.ABUSEGRAPH_SITE,
event,
}),
},
)
if (res.status === 402) {
return new Response("credits_exhausted", { status: 402 })
}
if (!res.ok) {
return new Response("Risk check unavailable", { status: 502 })
}
const result = await res.json()
if (result.verdict === "block") {
return Response.json(result, { status: 403 })
}
if (result.verdict === "challenge") {
return Response.json(result, { status: 428 })
}
return Response.json(result)
},
}Client:
const browserFields = await collectForAuth(email, "signup")
const response = await fetch("/api/signup-risk-check", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ ...browserFields, email }),
})
if (!response.ok) throw new Error("Signup requires review")
// Your server-side signup handler must also gate account/session creation.Lifecycle events
- login — POST with
event: "login"before session create. - password_reset — proxy with
event: "password_reset". - email_change — check before applying the email update with
event: "email_change".
Platform
Lists, rules, and linked accounts apply on every check — configure in the console. Optional session: POST /api/v1/session. Native apps: iOS, Android, React Native.
Verify
Deploy with sk_test_…, submit signup, confirm the Worker returns a verdict and Activity shows the check.