How to Add Sanctions Screening to Your Node.js App in 10 Minutes
If your application handles money, you are legally required to screen customers and counterparties against sanctions lists like the OFAC SDN list. Skipping this step can result in fines starting at $330,000 per violation, and OFAC enforces on a strict liability basis. That means it does not matter whether you knew about the sanctioned person or not. If you processed a transaction involving them, you are liable.
The good news is that adding sanctions screening to a Node.js application is straightforward. This tutorial walks you through the entire process, from installing the SDK to building production-ready middleware, in about 10 minutes.
Why your app needs sanctions screening
Every fintech, payment processor, crypto exchange, neobank, and lending platform that touches U.S. dollars or serves U.S. customers must comply with OFAC regulations. This is not optional. The Office of Foreign Assets Control has been increasingly aggressive with enforcement actions, especially against technology companies that process payments without adequate screening.
In practical terms, compliance means checking every customer name against sanctions lists at three points: when they sign up, before you process a payment on their behalf, and periodically to catch people who get added to lists after they became your customer.
The cost of not screening is severe. OFAC fines start at $330,000 per negligent violation and can reach $20 million for willful violations. Beyond fines, a sanctions violation can destroy banking relationships, trigger license revocations, and generate the kind of press coverage no startup wants. The best sanctions screening APIs make this easy to implement, and the Verifex SDK is designed specifically for developers who want to get compliant fast.
Step 1: Install the Verifex SDK
Start by adding the Verifex package to your Node.js project. The SDK is a lightweight wrapper around the Verifex REST API with TypeScript support built in.
npm install verifexNext, grab your API key from the Verifex dashboard. The free tier gives you 100 screens per month, which is plenty for development and testing. Store the key as an environment variable in your .env file:
# .env
VERIFEX_API_KEY=vfx_sk_live_your_key_hereNever hardcode API keys in your source code. If you are using dotenv, make sure .env is in your .gitignore file.
Step 2: Basic screening — your first API call
Here is the simplest possible screening. Create a Verifex client instance and call the screen method with a name. The SDK handles authentication, request formatting, and response parsing automatically.
import Verifex from "verifex";
const verifex = new Verifex({
apiKey: process.env.VERIFEX_API_KEY,
});
// Screen a person
const result = await verifex.screen({
name: "Vladimir Putin",
type: "person",
});
console.log(result.risk_level); // "critical"
console.log(result.matches); // Array of matched sanctions entries
console.log(result.lists_checked); // ["OFAC SDN", "UN", "EU", "UK"]That is it. One function call screens against OFAC SDN, UN Security Council, EU Consolidated List, and UK HM Treasury sanctions lists simultaneously. The response comes back in under 50 milliseconds.
Step 3: Handling results — risk levels and confidence scores
The screening response includes a risk level and an array of matches, each with a confidence score. Understanding these is critical for building the right compliance logic.
Risk levels map to confidence score ranges:
- Critical (90-100%). Exact or near-exact match against a sanctions entry. This almost certainly refers to the same person or entity. You should block the transaction and escalate to your compliance team immediately.
- High (75-89%). Strong fuzzy or phonetic match. Likely the same person, but minor variations exist. Flag for manual review before approving.
- Medium (60-74%). Moderate similarity. Could be the same person or a common name collision. Worth investigating, especially if other data points like date of birth or nationality also match.
- Low (below 60%). Weak match. Probably a different person. Most businesses auto-approve at this level unless other risk indicators are present.
Here is how to implement risk-based decision logic in your application:
async function handleScreeningResult(result, userId) {
switch (result.risk_level) {
case "critical":
// Block immediately and alert compliance
await db.user.update({
where: { id: userId },
data: { status: "blocked", screeningResult: JSON.stringify(result) },
});
await notifyComplianceTeam(userId, result);
return { approved: false, reason: "sanctions_match" };
case "high":
// Flag for manual review
await db.user.update({
where: { id: userId },
data: { status: "pending_review", screeningResult: JSON.stringify(result) },
});
return { approved: false, reason: "pending_review" };
case "medium":
// Auto-approve but log for audit trail
await db.screeningLog.create({
data: { userId, result: JSON.stringify(result), action: "auto_approved" },
});
return { approved: true };
default:
// Low risk or clear — approve
return { approved: true };
}
}Step 4: Batch screening — screen multiple names at once
When you need to re-screen your entire customer base or process a list of counterparties, use the batch endpoint. The Verifex API accepts up to 100 entities per batch request, which is significantly faster than making individual calls.
// Fetch all active customers
const customers = await db.user.findMany({
where: { status: "active" },
select: { id: true, name: true },
});
// Process in batches of 100
for (let i = 0; i < customers.length; i += 100) {
const batch = customers.slice(i, i + 100);
const results = await verifex.screenBatch({
entities: batch.map((c) => ({ name: c.name, type: "person" })),
});
for (let j = 0; j < results.length; j++) {
if (results[j].risk_level === "critical" || results[j].risk_level === "high") {
await flagForReview(batch[j].id, results[j]);
}
}
}
console.log(`Screened ${customers.length} customers`);Schedule this as a weekly or monthly cron job. Most compliance frameworks require at least monthly re-screening. If you are in a higher-risk sector like crypto, weekly re-screening is recommended.
Step 5: Express.js middleware for automatic screening
If your backend runs on Express.js, you can create middleware that automatically screens users during signup and before transactions. This ensures that screening happens consistently, without relying on individual route handlers to remember to call the API.
import Verifex from "verifex";
const verifex = new Verifex({
apiKey: process.env.VERIFEX_API_KEY,
});
// Middleware: screen a name before proceeding
function sanctionsScreen(nameField = "name") {
return async (req, res, next) => {
const name = req.body[nameField];
if (!name) return next();
try {
const result = await verifex.screen({ name, type: "person" });
// Attach result to request for downstream handlers
req.screeningResult = result;
if (result.risk_level === "critical") {
return res.status(403).json({
error: "This request has been blocked for compliance review.",
reference: result.request_id,
});
}
next();
} catch (err) {
// Log the error but do not block the user — queue for async screening
console.error("Screening failed:", err.message);
req.screeningResult = { error: true, queued: true };
next();
}
};
}
// Usage in routes
app.post("/api/signup", sanctionsScreen("name"), async (req, res) => {
const { name, email, password } = req.body;
const status = req.screeningResult?.risk_level === "high"
? "pending_review"
: "active";
const user = await db.user.create({ data: { name, email, password, status } });
res.json({ user, status });
});
app.post("/api/transfer", sanctionsScreen("recipientName"), async (req, res) => {
if (req.screeningResult?.risk_level === "high") {
return res.json({ status: "pending_review" });
}
const transfer = await processTransfer(req.body);
res.json({ transfer });
});This pattern centralizes your screening logic in one place. Every route that needs screening simply adds the middleware, and the screening result is available to the downstream handler on req.screeningResult.
Step 6: Going to production — error handling and retry logic
In production, you need to handle edge cases that do not come up during development. The three most important are network failures, rate limiting, and timeout handling.
Here is a production-ready wrapper with exponential backoff retry logic:
async function screenWithRetry(name, type = "person", maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await verifex.screen({ name, type });
return result;
} catch (err) {
const isRetryable =
err.status === 429 || // Rate limited
err.status === 502 || // Bad gateway
err.status === 503 || // Service unavailable
err.code === "ECONNRESET";
if (!isRetryable || attempt === maxRetries) {
throw err;
}
// Exponential backoff: 1s, 2s, 4s
const delay = Math.pow(2, attempt - 1) * 1000;
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}Beyond retry logic, here are additional production best practices:
- Log every screening request. Store the request ID, name screened, risk level, and action taken. This creates the audit trail regulators require. Check the API documentation for details on the response format.
- Set a timeout. Configure a 5-second timeout on screening requests. If the API does not respond within that window, queue the request for async processing rather than blocking the user indefinitely.
- Monitor your screening volume. Set up alerts when you approach your plan limit so you can upgrade before screening stops working.
- Never skip screening on error. If the API is unreachable, place the user in a pending state rather than auto-approving. You can process the queue once the service is back.
Testing your integration
Before going live, verify your integration handles each risk level correctly. You can use the free OFAC search tool to find known sanctioned names for testing. A few reliable test cases:
- Critical match: Screen "Vladimir Putin" and verify your app blocks the user and notifies your compliance team.
- Fuzzy match: Screen "Vladmir Putin" (note the missing "i") and verify it still returns a high-confidence match.
- Clear result: Screen a common name like "John Smith" and verify your app auto-approves with a low risk level.
- Error handling: Temporarily set an invalid API key and verify your app gracefully handles the 401 error without crashing.
Complete example: screening at signup
Here is a complete, copy-paste-ready example that puts everything together. This handles signup screening with proper error handling, audit logging, and risk-based decisions:
import Verifex from "verifex";
import express from "express";
const app = express();
app.use(express.json());
const verifex = new Verifex({
apiKey: process.env.VERIFEX_API_KEY,
});
app.post("/api/signup", async (req, res) => {
const { name, email, password } = req.body;
try {
// Screen the customer
const screening = await verifex.screen({ name, type: "person" });
// Log the screening for audit trail
await db.screeningLog.create({
data: {
name,
requestId: screening.request_id,
riskLevel: screening.risk_level,
matchCount: screening.matches.length,
listsChecked: screening.lists_checked,
timestamp: new Date(),
},
});
// Decide based on risk level
if (screening.risk_level === "critical") {
return res.status(403).json({
message: "We are unable to process your registration at this time.",
reference: screening.request_id,
});
}
const status = screening.risk_level === "high" ? "pending_review" : "active";
const user = await db.user.create({ data: { name, email, password, status } });
res.json({ message: "Account created", status: user.status });
} catch (err) {
// Screening failed — do not auto-approve, queue for later
const user = await db.user.create({
data: { name, email, password, status: "pending_screening" },
});
res.json({ message: "Account created, verification in progress", status: user.status });
}
});
app.listen(3000);What to do next
You now have a working sanctions screening integration in your Node.js app. Here are the logical next steps to build out your compliance program:
- Add transaction screening before outbound payments and transfers
- Set up batch re-screening as a weekly or monthly cron job
- Build a compliance dashboard to review flagged users
- Read the full API documentation for advanced features like entity type filtering and webhook notifications
- Check the benchmark results to see how Verifex performs against other screening providers
Sanctions screening is one of those compliance requirements that seems daunting until you actually implement it. With the Verifex SDK, the entire integration takes about 10 minutes and fewer than 50 lines of code. The hard part is not the technology. It is remembering to screen at every touchpoint and keeping your audit trail clean.
Frequently asked questions
Do I need sanctions screening if my app only serves U.S. customers?
Yes. OFAC regulations apply to all U.S. persons and any business operating within the United States. Even if your customers are exclusively domestic, you are still required to screen against the SDN list before processing transactions or onboarding users. Fines for non-compliance start at $330,000 per violation.
How often should I re-screen existing customers in my Node.js app?
Most compliance frameworks recommend re-screening your entire customer base at least monthly. The OFAC SDN list is updated multiple times per week, so someone who was clear at signup could be added to the list later. Use the Verifex batch endpoint with a cron job to automate this.
Can I use the Verifex Node.js SDK in a serverless environment like AWS Lambda?
Yes. The Verifex SDK is a lightweight HTTP client with no native dependencies. It works in any Node.js runtime including AWS Lambda, Vercel Functions, Cloudflare Workers, and Google Cloud Functions. Average response time is under 50ms, well within serverless timeout limits.
What happens if the Verifex API is down when my app tries to screen a user?
You should implement retry logic with exponential backoff, which this tutorial covers. For critical flows like onboarding, consider a fallback strategy: queue the screening request and place the user in a pending state until the screen completes. Never skip screening entirely due to a transient API error.
Get started with Verifex
Screen against OFAC, UN, EU & UK sanctions lists in one API call. Free tier available.
Get Free API Key