Code for your stack
Code for your stack
Each page has the steps for one stack and every file its code needs.
Pick your stack
- Any server with fetch (TypeScript): A function for Node 18 and later, Deno, Bun, Cloudflare Workers and any runtime with fetch. The other TypeScript examples import it.
- Next.js (App Router): Use a route handler for a signup API route, or a server action with its form. The form shows the error with useActionState. Both use lib/signupbouncer-fetch.ts.
- Express: A signup route for Express. The route imports signupbouncer-fetch.ts, saved next to your server file.
- Hono: A signup route for Hono. The route imports signupbouncer-fetch.ts, saved next to your server file.
- Python (requests): A function for Django, Flask, FastAPI or any Python backend. The file needs the requests package.
- Firebase Auth: A 2nd-gen blocking function that Firebase runs before it creates a user who signs up with email and password, an email link, a phone number or an OAuth provider. Blocking functions need Firebase Authentication with Identity Platform.
- Better Auth: The @signupbouncer/better-auth plugin, from npm or JSR. It checks each email and password signup (the /sign-up/email endpoint) before Better Auth creates the user.
Supabase, Ory and Keycloak need no code. See Supabase, Ory and Keycloak. AI coding assistants can fetch the same code through the MCP server's integration_guide tool.
The integrations page lists every platform and stack SignupBouncer plugs into, with a link to each install.
What the code does when a check fails
In every snippet, the call has a 1.5-second limit, and the code lets the signup through on any failure: a timeout, a network error, a non-2xx answer or an unreadable or incomplete body. It refuses a signup only after a complete answer with "action" and "verdict" both "block", "mode" set to "enforce", and no quota or error flag. The exception is an address that can't be real, which the code refuses without a call: one over 320 characters, or, in the Better Auth plugin, one that isn't an address at all. New apps start in shadow mode, where "action" is always "allow". So the code refuses no other signup until you switch the app to enforce in your dashboard. Each snippet checks only the signups that pass through it. So if your app also creates users somewhere else, such as an OAuth callback or an admin tool, call the check there too.