← Back to guides

AbuseGraph + Cloudflare Workers

Browser SDK on Pages — Worker proxies toCheckBody to abusegraph.com with sk_ secrets.

Install the browser SDK

npm install @palisade/sdk

Init early on app load. Call check({ email }) at signup or login — not on every page view.

Quick path

  1. Init the browser SDK with pk_test_… on your site.
  2. Store ABUSEGRAPH_SECRET_KEY and ABUSEGRAPH_SITE as Worker secrets.
  3. Worker receives toCheckBody from the client and POSTs to https://abusegraph.com/api/v1/check.

Keys

KeyEnvUse
SecretABUSEGRAPH_SECRET_KEY (sk_test_… / sk_live_…)Server /api/v1/check
PublishableNEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY (pk_test_…)Browser SDK
SiteABUSEGRAPH_SITEDNS-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):

bash

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)

init + collect + evaluate + toCheckBody — NEVER bare sdk.check() alone as the authoritative decision.

typescript

import { init } from "@palisade/sdk"

const sdk = init({
  publicKey: import.meta.env.VITE_ABUSEGRAPH_PUBLISHABLE_KEY!, // pk_test_…
})

export async function collectForAuth(
  email: string,
  event: "signup" | "login" | "password_reset" | "email_change",
) {
  const collected = await sdk.collect()
  const edge = await sdk.evaluate(collected, { email })
  return sdk.toCheckBody(collected, {
    email,
    event,
    verdictToken: edge.verdictToken.token,
  })
}

Cloudflare Worker proxy

typescript

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== "POST") {
      return new Response("Method not allowed", { status: 405 })
    }

    const body = 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({
          ...body,
          site: env.ABUSEGRAPH_SITE,
          event: body.event ?? "signup",
        }),
      },
    )

    if (res.status === 402) {
      return new Response("credits_exhausted", { status: 402 })
    }

    const result = await res.json()
    if (result.verdict === "block") {
      return Response.json(result, { status: 403 })
    }

    return Response.json(result)
  },
}

Client:

typescript

const browserFields = await collectForAuth(email, "signup")
await fetch("/api/abusegraph-check", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ email, event: "signup", ...browserFields }),
})

Lifecycle events

  • login — POST with event: "login" before session create.
  • password_reset — proxy with event: "password_reset".
  • email_change — proxy 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.