OFAC Sanctions Screening from $0.02/Name - Fuzzy, No API Key avatar

OFAC Sanctions Screening from $0.02/Name - Fuzzy, No API Key

Pricing

from $4.00 / 1,000 sanctions records

Go to Apify Store
OFAC Sanctions Screening from $0.02/Name - Fuzzy, No API Key

OFAC Sanctions Screening from $0.02/Name - Fuzzy, No API Key

Screen names against the official U.S. Treasury OFAC SDN and Consolidated sanctions lists for $0.02 per name. Fuzzy matching (typos, aliases), CSV batch input, downloadable audit trail. No API key, no monthly subscription.

Pricing

from $4.00 / 1,000 sanctions records

Rating

0.0

(0)

Developer

Moose & Raven

Moose & Raven

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

1

Monthly active users

5 hours ago

Last modified

Share

OFAC Sanctions Screening API - No API Key Required

Screen a name against the U.S. Treasury's official OFAC sanctions lists for $0.02 per name (a hit adds $0.004 per matched record) - no monthly subscription, no API key. Every name gets a clear / possible / hit verdict plus a downloadable audit-trail CSV, whether it's a new customer, vendor, or business counterparty you need to clear before onboarding them. Built for fintechs and banks running AML/KYB checks at account opening, and for compliance or procurement teams vetting a vendor before signing.

Worked example: A bank's onboarding team needs to clear a new commercial customer, "Example Trading Co", before opening an account. They run the actor with names: ["Example Trading Co"] - the default lists value already screens both SDN and CONSOLIDATED, and the default matchMode ("fuzzy") checks both the official SDN_Name field and OFAC's own a.k.a./f.k.a. aliases, with typo/reorder-tolerant scoring, so there's nothing extra to configure. Every match comes back as a dataset item with recordType: "sanctions-listing", listSource ("SDN" or "CONSOLIDATED"), sdnName, sdnType, program (the sanctions program code, e.g. "CUBA" or "IRAN"), remarks with any further detail OFAC published, plus matchScore, matchType ("exact" or "fuzzy"), matchedField ("primary-name" or "aka"), and matchedName. A second dataset item,

recordType: "screening-summary"
, gives the same screen a per-name verdict ("hit" / "possible" / "clear") with the top-3 candidate matches - the audit-trail record a compliance reviewer actually needs. No match on either list means a clean result - and because this actor aborts loudly rather than reporting "0 matches" when a list fails to load (see below), a clean result here means the lists were actually checked, not silently skipped.

No API key required. This actor screens names against the official U.S. Treasury OFAC Specially Designated Nationals (SDN) list and the Consolidated (non-SDN) sanctions list for AML/KYB compliance - via the official, keyless Sanctions List Service. No account, no registration, no scraping: just supply names and screen. Optional incremental monitoring flags newly-added listings on scheduled runs.

Live-validated 2026-09-24 against the real, current lists (19,391 real SDN entries + 20,205 alias/AKA rows + 4,367 remarks-embedded aliases, 481 CONSOLIDATED entries + 1,110 alias rows + 72 remarks-embedded aliases) - the CSV parsing, fuzzy/alias matching, CSV batch input, and monitor-mode diff logic have all been exercised against live data, not just fixtures. A live 200-query precision benchmark against both full lists (~19,872 records + aliases) ran in ~69s (~0.34s/query) - comfortably inside Apify's run timeout for a realistic compliance batch of dozens to low hundreds of names; a batch in the many hundreds should set a longer timeoutSecs if needed.

This is a screening aid, not legal advice. Even with fuzzy/alias matching, this is not a certified compliance-screening engine on par with enterprise AML platforms. Use it to narrow down candidates for review, not as a standalone legal clearance - see Limitations below.

What makes this different

Zero setup. Treasury's Sanctions List Service (sanctionslistservice.ofac.treas.gov) is a free, official REST service - no account, no API key, nothing to configure beyond your search input. Most comparable actors on the Store require registration or scrape a web UI; this hits the official bulk-data service directly.

Built for ongoing monitoring, not just one-off lookups. Incremental new-listing detection flags newly-added sanctions designations on scheduled runs - most comparable actors in this category only support one-off searches.

Natural pairing: combine with our SAM.gov Federal Contracting Suite actor for a combined "federal debarment + OFAC sanctions" screening pass.

A lightweight, no-subscription complement to enterprise AML platforms, not a replacement for one. ComplyAdvantage publishes pricing starting "from $99 per month for 100" monitored entities (complyadvantage.com/pricing), and LexisNexis Bridger Insight XG's published UK public-sector pricing (via the Digital Marketplace G-Cloud framework) starts at an annual license "for up to 10,000" screenings/year - both are enterprise-annual-contract products with global watchlist coverage, PEP and adverse-media coverage, and case management this actor does not do (see the Limitations warning below). As of 2026-09-24 this actor's default matchMode also does fuzzy/alias matching (see How it works), narrowing but not closing that gap - it's still not a certified compliance-screening engine or a full case-management platform. If all you need is a fast, no-subscription OFAC/SDN/Consolidated screen with typo/alias tolerance and an audit trail, this actor does that at $0.004/matched record with zero monthly commitment; if you need global watchlist coverage (beyond OFAC), PEP/adverse-media screening, or a compliance case-management workflow, a platform like those is the right tool, not this one.

How it works

  • No API key needed. Nothing to register, nothing to configure beyond your search input.
  • Supply names (an array) and/or namesCsv (paste raw CSV text, optionally with name and referenceId header columns - see Input below) to screen. Any real screen always checks both SDN and CONSOLIDATED by default - the primary sanctions list is never silently dropped just because you didn't specify lists yourself. namesCsv is standard CSV - if a name itself contains a comma (e.g. OFAC's own "Last, First" style, "Smith, John"), quote it ("Smith, John",CASE-1) or the comma will be parsed as a column separator, splitting the name and shifting your referenceId column - confirmed live while verifying this build.
  • Matching mode (matchMode, default "fuzzy"): checks the official SDN_Name field AND OFAC's own a.k.a./f.k.a. aliases, using exact substring matching plus a typo/reorder-tolerant rapidfuzz-style score (fuzzyThreshold, default 85/100). Set matchMode: "exact" to restore the original, literal substring-only matching against SDN_Name alone (no aliases, no fuzzy scoring)
    • useful if you need output identical to this actor's pre-2026-09-24 behavior. Fuzzy mode is strictly additive: every match exact mode would have found, it still finds, plus new alias and near-miss matches. On a fuzzy-mode match, matchType: "exact" means the submitted name literally equals the published name or alias (case/accent differences aside) - not merely that the score hit 100. A name that only aligns after transliteration folding (e.g. "Victor" folding to "Viktor" via the c/k rule) is correctly labeled "fuzzy" even at a perfect score, so the audit trail never overstates how closely a hit actually matches what OFAC published.
  • Choose which lists to check (SDN, CONSOLIDATED, or both) and optionally filter by sanctions program code (e.g. "CUBA", "IRAN"). Explicitly narrowing lists yourself is always respected exactly as given.
  • Leaving names empty with no explicit lists choice (nothing to screen at all) uses a cheaper, CONSOLIDATED-only default rather than pulling the full ~19,659-entry combined list - this keeps a zero-configuration run fast and inexpensive. This run always pushes an explicit lists-coverage record naming exactly what was and wasn't included, so it's never silent. Pass lists explicitly (with or without names) to include SDN in a no-screen run too.
  • This actor downloads and filters locally - Treasury's service is a bulk-file distribution endpoint, not a server-side search API, so there's no way to query it more surgically than "fetch the current list, then filter." The full SDN list is a manageable ~5-6MB/~19K entries, so this is fast and cheap in practice, not a real limitation in disguise.
  • Optional incremental monitor mode: remembers which ent_num values it has seen (Apify key-value store) and emits a separate new-listing record for anything newly added since the last run - designed for scheduled runs watching for new designations. Confirmed live: a second run against unchanged data produces zero false-positive new-listing flags.
  • Scheduled re-screen + change alerts for YOUR OWN list (watchlistName, combined with monitorMode and a real screen): set up an Apify Schedule with the same names/namesCsv and a watchlistName every time, and each run pushes a watchlist-alert record only for a match that is genuinely NEW since that exact watchlist's last run - not a repeat, and not every new designation on the full OFAC list. Different watchlistName values are tracked completely independently, even in the same Apify account - built for running several distinct customer lists through one actor. Reuses the existing monitor-run charge, no extra event. Confirmed live with a real 3-run cross-schedule test: bootstrap run alerts on the first-ever hit, an identical second run stays silent, a third run with one genuinely new hit alerts on only that one.
  • An optional maxRecordsPerRun per-list cap (default 0 = uncapped). Screening is exhaustive by default - every matching record on every requested list is returned, because a silently partial sanctions screen is the worst failure mode this actor could have (see below). If you set a cap and it truncates a list, the actor emits a loud screening-status record with status: "TRUNCATED" plus a warning log - it never lets a capped run look like a complete one.
  • The actor aborts the whole run (non-zero exit, clear error) if a list fails to fetch - it never reports "0 matches" when the authoritative list simply never loaded. A compliance user reading a clean result must be able to trust that the list was actually checked. The same discipline applies to the alias lists fetched for fuzzy mode: a failed or suspiciously-small alias fetch aborts the run rather than silently screening without alias coverage.
  • Audit trail: whenever you screen at least one name, the actor also emits one screening-summary record per input name (verdict + top 3 matches + scores, even for a "clear" result - so the audit trail proves a name was actually checked, not just that hits exist) and a screening-evidence record pointing at a downloadable CSV written to a NAMED key-value store (ofac-screening-evidence). The CSV's URL requires YOUR Apify account token to fetch (private storage, same as any other Apify key-value store record - an unauthenticated fetch 403s, that's expected, not a bug). Every input row is evaluated fully independently, including two rows that share the exact same name - each gets its own verdict, its own confirmedBy/conflictReasons (from its own supplied dateOfBirth/country), and its own screened-name/sanctions-record charges. This matters for batches where the same common name legitimately belongs to two different real people - supply each row's own DOB or referenceId and they're never conflated.
  • Secondary identifiers (dateOfBirth, country) - the real fix for common-name noise. "Jose Garcia" or "Ahmed Hassan" genuinely IS a real designee's actual name on the SDN list, so name-only screening correctly flags it - that's not a bug, per this actor's standing false-negatives-are-worse rule. But if YOU know the date of birth or nationality of the specific person you're screening, supply it and this actor resolves the ambiguity automatically: pass an object instead of a plain string in names (
    {"name": "Jose Garcia", "dateOfBirth": "1985", "country": "Mexico"}
    ), or add dateOfBirth/country columns to namesCsv. If the supplied year (or country) conflicts with what's actually listed for the matched record (+/-1 year tolerance when OFAC itself lists an approximate "circa" DOB), the verdict downgrades from "hit" to "possible" with a verdictReason - never silently suppressed, a human still reviews it. If it agrees, the match gets confirmedBy: ["dob"]/["country"]. Missing data on either side (you don't supply it, or OFAC's own listing doesn't have it) never counts as a conflict - only an actual mismatch does. Live-benchmarked: supplying a (deliberately mismatched, synthetic) random adult birth year cut the false-"hit" rate on 200 common names from 16.5% to 1.0%.

WARNING: Limitations - read this before relying on it for compliance decisions

  • Fuzzy/alias matching (default matchMode: "fuzzy") is a real improvement over pure substring matching, but it is still not a certified compliance-screening engine on par with enterprise AML platforms (see "What makes this different" above for how it compares). It combines exact matching, common-transliteration folding (c/k, v/w, y/i/j, ph/f, ou/u, kh/h, double letters - e.g. "Victor Bout" and "Viktor Bout" score identically), and a one-to-one per-token fuzzy alignment against SDN_Name, OFAC's own a.k.a./f.k.a. aliases, AND aliases embedded in the free-text remarks field (not all real aliases are in the structured alias export). It is still not phonetic matching in the general case, and a name spelled meaningfully differently than OFAC's listing, its aliases, AND any common transliteration pattern can still produce a false negative. This is not legal advice. For compliance-critical decisions, always cross-check against OFAC's own official search tool (sanctionssearch.ofac.treas.gov) - do not treat a clean result from this actor as a legal clearance.
  • Verdicts are coverage-aware, not just score-based. "hit" requires the match to cover at least 2/3 of the MATCHED candidate name's own tokens (not just the query's), or a fully-matched alias - a short query that only overlaps part of a much longer real name (e.g. "Jose Garcia" against the real "GIL GARCIA, Jose Alejandro" - matches 2 of that name's 4 tokens) is surfaced as "possible" instead, never suppressed, but not overstated as a confirmed match either.
  • Measured recall and false-positive rates, live-benchmarked against the real current SDN + CONSOLIDATED lists (2026-09-25; see scripts/recall-benchmark.js/scripts/precision-benchmark.js for full methodology and to re-run them yourself):
    • Recall (hit + possible combined): 97.6% across 1,097 generated variants (c/k and v/w transliteration swaps, a dropped middle/patronymic name, reordered name parts, a one-letter typo, an adjacent-character transposition, and hyphenation) of 220 real sampled SDN individuals, each tested against that individual's own real record at the default fuzzyThreshold (85) - "recall" here means the tool surfaced the real match at all (hit OR possible), since a "possible" verdict is never suppressed. Of that 97.6%, 95.3% landed as a confident "hit" and 2.4% as "possible" (a real match, correctly flagged as lower-confidence rather than missed). The residual ~2.4% of true misses cluster on typos/ swaps/transpositions landing on very short (2-3 letter) name tokens, deliberately held to exact-match-only to avoid a worse false-positive class (see below) - plus a smaller tail on 5-9 letter tokens, where the per-token fuzzy floor (MIN_TOKEN_FUZZY_RATIO = 90, not configurable) needs a token length of 10+ to tolerate a single-edit typo or transposition.
    • False "hit" rate: 16.5%, false "possible" rate: 20.5% across 200 common, unremarkable real-world names (50 each of Anglo, Hispanic, Arabic, and Chinese naming patterns - nobody on any sanctions list) screened against the full real SDN + CONSOLIDATED lists. These rates are markedly higher on Hispanic/Arabic/Chinese names specifically because the real SDN list is genuinely dense in exactly those surname families (cartel, Middle East, and PRC-trafficking sanctions programs) - many of the "false" hits are not algorithm defects at all: they are a real designee's actual full name genuinely containing both the generated first AND last NAME-PART (e.g. "Jose Lopez" against the real "LOPEZ, Jose Francisco"), which any honest name-based screen would reasonably surface. This is the direct, disclosed cost of favoring recall - see the next bullet - concentrated on exactly the name families where getting it wrong matters most.
    • These numbers describe the matching algorithm's own behavior on this specific data snapshot, not a certified accuracy claim - they will drift as the underlying SDN/Consolidated lists change, and are not independently audited.
  • Fuzzy matching still favors recall over precision by design, per this actor's standing "false negatives are the dangerous direction for a sanctions screen" rule - within a query, every token is matched one-to-one against the candidate's tokens (so extra candidate tokens like patronymics never hurt a match on their own, though they do count against the 2/3 coverage requirement above), but a completely coincidental strong overlap between two otherwise-unrelated names is still possible, especially on very common surnames. Precision guards exist specifically to bound this: (1) tokens shorter than 4 characters get NO fuzzy credit at all, only exact equality (found and fixed live: a short 2-word query like "Li Na" was coincidentally matching across two unrelated candidate words before this guard existed); (2) a multi-token query needs at least 2 tokens with real, one-to-one per-token support (>= 90% token similarity) before it counts as a match at all (found and fixed live: "Devon Hale" was coincidentally scoring as a "possible" match against an unrelated real entity before this guard existed); (3) the 2/3 candidate-coverage requirement above. Review "possible" verdicts and lower-scoring "hit" verdicts manually rather than treating every match as fully confirmed.
  • The Consolidated (non-SDN, e.g. NS-PLC) list is fetched and screened in full - as of 2026-09-24 it's ~481 real entries. This actor never treats a near-empty result as normal for either list (or their alias lists); an unexpectedly small or missing list is treated as a fetch problem, not a quiet "nothing to report."
  • The legacy CSV format is undocumented/positional (no header row, no official published schema for the exact column order) - the 12-column mapping used here (entNum, sdnName, sdnType, program, title, callSign, vesselType, tonnage, grt, vesselFlag, vesselOwner, remarks) is inferred from the well-known, long-standing OFAC SDN.CSV format and confirmed against real live data, but OFAC could change this format without notice since it isn't a versioned/documented API contract the way SAM.gov's or FMCSA's JSON APIs are. The alias export files (ALT.CSV/CONS_ALT.CSV) are the same undocumented legacy shape.
  • A full-list export with no names to screen can hit a real cost limit if left uncapped. Leaving names empty with the default lists gets a cheap, bounded default automatically (see above). But if you explicitly request a full list with nothing to screen (e.g. lists: ["SDN"] alone, no names) and leave maxRecordsPerRun at 0, fetching and delivering the entire ~19,000-row SDN list can exceed Apify's own per-run cost limit and abort partway through. This is a loud abort, not a silent miss - but set an explicit maxRecordsPerRun for a full-list export to avoid it.

Pricing

screened-name and bulk-export-1k were announced 2026-09-24 and take effect 2026-10-08 (Apify's Store Publishing Terms require a 14-day notice period before a price increase/new paid event takes effect). Until then, the previous per-record pricing applies: every delivered record - whether a screen hit or a bulk export row - charges sanctions-record at $0.004, and a clean screen costs $0, exactly as it always has. This actor enforces that date itself in code (not just by policy), so nothing below applies early regardless of platform behavior.

Pay per event, effective 2026-10-08:

  • sanctions-record - $0.004 / matched record delivered during a real name screen
  • screened-name - $0.02 / input name actually screened (array or CSV row), hit or clear alike - this is what makes a clean result cost something, not just a hit
  • bulk-export-1k - $4.00 / 1,000 records, for a full-list export with no names to screen (the same effective per-record rate as sanctions-record, just billed in coarser, clearer units)
  • monitor-run - $0.05 / scheduled monitor-mode run, in addition to per-record charges

Worked example: screening a 500-name CSV batch where 10 come back as hits costs 500 x $0.02 (screened-name) + 10 x $0.004 (sanctions-record, assuming one matched record per hit) = $10.04. A bare full-list export of ~19,600 SDN+CONSOLIDATED records costs 20 x $4.00 (bulk-export-1k, rounded up from 19.6 units of 1,000) = $80.00 - the same effective rate as before, just clearer units.

The screening-summary and screening-evidence audit-trail records (see below) are not separately charged - they ride along with whatever charges a run already generates. The Apify platform's own zero-input daily health-check run is charged nothing at all.

Input

Key fields (see the Input tab for the full form): names, namesCsv, matchMode, fuzzyThreshold, lists, programFilter, monitorMode, watchlistName, maxRecordsPerRun. No required fields - a run with all defaults screens against both full lists with fuzzy/alias matching.

Supply date of birth and country where you have them - they resolve most common-name alerts. A name-only "hit" on "Jose Garcia" or "Ahmed Hassan" is correct (a real designee really is named that), but if you know the person you're actually screening's DOB or nationality, adding it lets this actor tell your person apart from the coincidentally-same-named designee automatically. See "Secondary identifiers" above.

Output

Each dataset item has a recordType of "sanctions-listing", "new-listing" (monitor mode only), "screening-status" (only when a run is truncated), "lists-coverage" (only when a run covers fewer than both sanctions lists - see Limitations below), "screening-summary" (one per input name, only when you screened at least one name), "screening-evidence" (one per run, points at the downloadable audit CSV - only when you screened at least one name), or "watchlist-alert" (only when watchlistName + monitorMode + a real screen are combined, and only for a genuinely new match - see "Scheduled re-screen + change alerts" above). See the Output tab for the full field reference.

Sample output (real, live-verified sanctions-listing record for

names: ["GUZMAN LOERA, Joaquin"]
):

{
"recordType": "sanctions-listing",
"listSource": "SDN",
"entNum": "6861",
"sdnName": "GUZMAN LOERA, Joaquin",
"sdnType": "individual",
"program": "SDNTK",
"remarks": "DOB 25 Dec 1954; POB Mexico.",
"fetchedAt": "2026-09-24T15:35:14.449Z",
"sourceApi": "sanctionslistservice.ofac.treas.gov",
"matchScore": 100,
"matchType": "exact",
"matchedField": "primary-name",
"matchedName": "GUZMAN LOERA, Joaquin",
"queryName": "GUZMAN LOERA, Joaquin"
}

The shape is stable and predictable across calls: every sanctions-listing item has the same fields (null where OFAC published no value), keyed on recordType for programmatic branching - built for both human review and agent/pipeline consumption.

Integrations

Apify API - the fastest way to call this from anywhere. run-sync-get-dataset-items runs the actor and returns the dataset items directly in the response (no separate poll-for-completion step) - the right endpoint for a one-off screen from an external tool or script. Real, tested example (replace YOUR_TOKEN):

curl -X POST "https://api.apify.com/v2/acts/K3bU3g9UVc8WLIqx8/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"lists": ["SDN"], "names": ["GUZMAN LOERA, Joaquin"]}'

JavaScript (apify-client, the official SDK):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const { items } = await client.actor('K3bU3g9UVc8WLIqx8').call({
lists: ['SDN', 'CONSOLIDATED'],
names: ['GUZMAN LOERA, Joaquin'],
}).then((run) => client.dataset(run.defaultDatasetId).listItems());
const hits = items.filter((i) => i.recordType === 'sanctions-listing');

Python (apify-client):

from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("K3bU3g9UVc8WLIqx8").call(run_input={
"lists": ["SDN", "CONSOLIDATED"],
"names": ["GUZMAN LOERA, Joaquin"],
})
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
hits = [i for i in items if i["recordType"] == "sanctions-listing"]

Zapier: add the official "Apify" app, action Run Actor and Get Dataset. Pick this actor (mooseandraven/ofac-sanctions-screening-suite), map your trigger's name field to the names input array (or namesCsv for a batch), and feed the resulting dataset items into your next Zap step (e.g. filter on recordType = "sanctions-listing" and verdict/matchType from the screening-summary items to branch on hit/clear).

Make (Integromat): add the official "Apify" module, action Run an Actor, same actor ID as above. Use Make's built-in JSON parser on the returned dataset items, or add an Apify > Get Dataset Items module after the run to pull results into a downstream Google Sheets/Airtable/ Slack module.

n8n: no actor-specific node needed - use a plain HTTP Request node, POST to the run-sync-get-dataset-items URL above with your input as the JSON body (same shape as the curl example). This works in any n8n instance without installing a community node.

Google Sheets: the simplest no-code path is Apify's own Google Sheets integration (Console > this actor > Integrations tab > "Save to Google Sheets") - point it at a sheet and it appends each run's dataset items as new rows automatically, no script needed. For a spreadsheet-triggered batch screen instead (read names FROM a sheet, screen them, write results back), use Apps Script's UrlFetchApp.fetch() against the same run-sync-get-dataset-items endpoint, building namesCsv from a column range.

Local development

npm install
npm test # recorded-fixture unit tests, no network needed
npx apify-cli run # local end-to-end run - works immediately, no key/account needed

Support

Built and maintained by Moose & Raven. Questions or issues: support@mooseandraven.com.