Node.js · Email breach checks
Check email breaches in Node.js with fetch
In Node.js the email breach check is a natural fit for an Express signup route or a background job that walks your users table. The endpoint responds with breached and an array of breach objects whose keys are PascalCase, such as Title, BreachDate and DataClasses. Because the response is plain JSON, you can map it straight into the shape your frontend or notification template expects.
The script below runs on its own with node check-email.mjs and an optional address argument. It uses node:timers/promises for a clean await on Retry-After, so a rate-limited request pauses without blocking the event loop. Validation failures and bad keys throw immediately, while quota_exceeded is surfaced as an error so a batch job stops spending effort when credits run out.
Steps
- 1
Confirm you are on Node.js 18 or newer by running node --version.
- 2
Export FINOWL_API_KEY with a key from the Finowl dashboard.
- 3
Save the example as check-email.mjs and run node check-email.mjs alex@example.com.
- 4
Map each breach's Title, BreachDate and DataClasses into your UI or email template.
- 5
Call checkEmail from your signup route or job runner once the output looks right.
// check-email.mjs (Node.js 18+, no dependencies)
import { setTimeout as sleep } from "node:timers/promises";
const API_URL = "https://api.finowl.co/v1/breaches/email";
async function checkEmail(email, attempts = 3) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(API_URL, {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.FINOWL_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
signal: AbortSignal.timeout(10_000),
});
if (res.ok) return res.json();
const payload = await res.json().catch(() => ({}));
const code = payload?.error?.code ?? "unknown_error";
if (res.status === 400) throw new Error("Invalid email address (" + code + ")");
if (res.status === 401) throw new Error("Unauthorized: check FINOWL_API_KEY");
if (res.status === 429 && code === "rate_limited") {
const seconds = Number(res.headers.get("retry-after")) || 1;
await sleep(seconds * 1000);
continue;
}
throw new Error("Finowl error " + res.status + ": " + code);
}
throw new Error("Still rate limited after " + attempts + " attempts");
}
const result = await checkEmail(process.argv[2] ?? "alex@example.com");
if (!result.breached) {
console.log(result.email + " does not appear in any known breach");
}
for (const breach of result.breaches) {
const flag = breach.IsVerified ? "" : " [unverified]";
console.log(breach.Title + " (" + breach.BreachDate + ")" + flag);
console.log(" exposed: " + breach.DataClasses.join(", "));
}IN PRODUCTION
Production tips
Run the check after you create the account and respond to the client, for example from a queue job, so a slow lookup never adds latency to the signup request itself.
If you process many users, use a small concurrency limit such as p-limit set to a few workers, and keep total throughput below 60 requests per minute for your account.
Show breach titles and dates to users but keep the longer Description text for internal views, and treat it as untrusted content that you escape or sanitize before rendering.
Each lookup costs 1 credit, with 100 free credits every month. See pricing and error codes.
A FEW GOOD QUESTIONS
Common questions
Related guides
- Screen breached passwords in Node.js
- Predict gender from a name in Node.js
- Check email breaches in Python with requests
- Check email breaches in TypeScript with typed results
- Check email breaches in Go with net/http
- Check email breaches in Java with HttpClient
- Email breach checks for fintech signups and logins
- Email breach checks for online stores and shopper logins
- Email breach checks for SaaS logins and admins
Check email breaches in Node.js with fetch
Grab an API key, paste the example and run it. 100 free credits every month.