# Sanctions Delta Monitor - OFAC, UN, UK & EU Change Feed (`datadeltas/sanctions-delta-monitor`) Actor

Change feed for the world's sanctions lists: additions, removals and amendments to OFAC SDN + Consolidated, the UN Security Council consolidated list, the UK OFSI consolidated list and the EU consolidated financial sanctions list.

- **URL**: https://apify.com/datadeltas/sanctions-delta-monitor.md
- **Developed by:** [Daniel Matthee](https://apify.com/datadeltas) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 sanctions change detecteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Sanctions List Delta Monitor — OFAC, UN, UK OFSI, EU Changes Feed

The **change feed** for the world's major sanctions lists. Every scheduled
run downloads the official lists, diffs them against the previous run and
emits one record per **addition, removal or amendment** — including exactly
which fields changed. Screening tools tell you whether a name is sanctioned
*now*; this actor tells you **what changed since you last checked**, which
is what re-screening triggers, case reviews and audit trails actually need.

**Lists covered**

| List | Source | Entities (Aug 2026) |
|---|---|---|
| `ofac` | US Treasury OFAC — SDN list **plus** the consolidated non-SDN list (official sanctionslistservice.ofac.treas.gov exports) | ~19,800 |
| `un` | UN Security Council consolidated list (scsanctions.un.org XML) | ~1,000 |
| `uk` | UK OFSI consolidated list of financial sanctions targets (official ConList.csv) | ~5,100 |
| `eu` | EU consolidated financial sanctions list (FSF) — *needs a free EU Login token, see below* | ~4,900 |

### First run seeds — it emits nothing

By design the **first run of each list stores a baseline and emits zero
records** (so you are never billed for 20,000+ "changes" that are just the
existing list). From the second run on, only genuine deltas are emitted.
Want the full list as records once? Set `emitInitialSnapshot: true` and the
first run emits every entity as `added` (the `maxItems` cap applies).

Recommended schedule: **daily** (OFAC publishes most business days; UN/UK/EU
update several times a month).

### Example output record

```json
{
  "list": "ofac",
  "entityId": "sdn-52161",
  "changeType": "amended",
  "name": "BANK MARKAZI JOMHOURI ISLAMI IRAN",
  "aliases": ["CENTRAL BANK OF IRAN", "BANK MARKAZI IRAN"],
  "entityType": "entity",
  "programs": ["IRAN", "SDGT", "IRGC", "IFSR"],
  "changedFields": ["aliases", "remarks"],
  "listedDate": null,
  "sourceUrl": "https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.CSV",
  "detectedAt": "2026-08-31T04:52:11Z"
}
```

`changeType` is `added`, `removed` or `amended`. For amendments,
`changedFields` names the normalised fields that moved (e.g. `aliases`,
`programs`, `dob`, `passportNumbers`, `remarks`) — alias reordering,
whitespace and duplicate noise never trigger a change. `entityId` is the
list's own stable identifier (OFAC uid, UN DATAID, OFSI Group ID, EU
logical id), prefixed `sdn-`/`cons-` for the two OFAC files.

### Input options

| Field | Default | What it does |
|---|---|---|
| `lists` | `["ofac", "un", "uk"]` | Which lists to monitor. Add `"eu"` once your EU token URL is configured. |
| `euTokenUrl` | — | Your personal EU full-list download URL (secret). Get one in ~5 minutes: register a free EU Login at webgate.ec.europa.eu/fsd/fsf, then copy the token download URL for the XML full list. Without it the EU list is skipped with a log note. |
| `programs` | all | Only emit changes for entities under these programmes (e.g. `RUSSIA-EO14024`, `SDGT`, `Global Human Rights`). Case-insensitive. |
| `entityTypes` | all | Filter to `individual`, `entity`, `vessel` and/or `aircraft`. |
| `maxItems` | `1000` | Cap on change records per run. Split fairly across the lists that have changes, and **nothing is lost**: a change the cap holds back stays pending and is emitted by the next run. |
| `emitInitialSnapshot` | `false` | Emit the whole list as `added` records on each list's first run. |

### Reliability

- **Partial-failure safe**: if one list's endpoint is down (5xx), that list
  is skipped with a warning and its stored baseline is untouched — the other
  lists still diff normally. A list that suddenly returns zero entities is
  treated as a broken download, never as 20,000 removals.
- **No list starves, no change is lost**: `maxItems` is split fairly across
  the lists that actually have changes (a quiet list holds no share), and any
  change held back by the cap stays *pending* — its stored baseline entry is
  left as-is, so the very next run re-detects and emits it. A busy sanctions
  day can never silently swallow the UK, UN or EU changes behind OFAC's.
- **Amendment-grade diffing**: entities are compared as normalised field
  sets, so a DOB correction, new passport number or added alias surfaces as
  a named `changedFields` entry, while cosmetic re-ordering does not.
- Only official government sources are read. No scraping of third-party
  aggregators.

### Use cases

- **KYC / AML re-screening triggers** — "alert my compliance queue when
  anyone is added to OFAC SDN or the UK list under RUSSIA programmes" and
  re-screen your customer base only when something actually changed.
- **Audit trail of list changes** — keep a dated dataset of every addition,
  removal and amendment across OFAC, UN, UK and EU for regulator-ready
  evidence of your monitoring cadence.
- **Screening-vendor data pipelines** — feed deltas instead of re-ingesting
  full lists: cheaper, faster, and you know exactly which records to touch.
- **Crypto compliance** — OFAC amendments include digital-currency address
  updates in the `remarks` field of the affected entity.

### Pricing

Pay per event: a small per-run fee plus a fee per change detected. Calm
weeks cost you almost nothing; busy sanctions days deliver exactly the
records you need to act on.

### Maintenance

Source formats are checked against the official publications; schema drift
is logged clearly and never crashes a run. If a list moves its download
URL, the actor is updated — the state format keeps your baselines.

### Changelog

- **0.1** — initial release: OFAC (SDN + consolidated non-SDN), UN, UK OFSI
  live; EU consolidated list supported via personal EU Login token URL.
- **0.1 maintenance (1 Sep 2026)** — internals moved onto the shared monitor
  library. Your stored baselines are bit-for-bit unchanged (no reseed, no
  re-emitted changes), and a download error that can never recover — a moved
  or forbidden URL — now fails fast instead of spending the run on retries.
- **0.1 maintenance (1 Sep 2026)** — `maxItems` is now shared FAIRLY across the
  enabled lists and no longer destroys anything: previously a busy OFAC day
  could consume the whole cap in list order and the UN/UK/EU changes behind it
  were lost for good. Changes the cap holds back now stay pending and are
  emitted by the next run. (One exception, logged loudly: `emitInitialSnapshot`
  is a one-off dump, so a capped first run still seeds its baseline in full.)

# Actor input Schema

## `lists` (type: `array`):

Which sanctions lists to monitor. The EU list additionally requires the 'EU token URL' input (free EU Login registration).

## `euTokenUrl` (type: `string`):

Personal full-list download URL for the EU consolidated financial sanctions list, generated after a free EU Login registration at webgate.ec.europa.eu/fsd/fsf. Leave empty to skip the EU list.

## `programs` (type: `array`):

Optional case-insensitive sanctions-programme filter (e.g. RUSSIA-EO14024, SDGT, DRC, Global Human Rights). A change is emitted only when the entity is designated under at least one of these. Leave empty for all programmes.

## `entityTypes` (type: `array`):

Optional filter on the type of designated party. Leave empty for all types.

## `maxItems` (type: `integer`):

Safety cap on change records emitted in one run (keeps test runs cheap). Shared fairly across the lists that have changes, and nothing is lost: a change held back by the cap stays pending and is emitted by the next run. Exception: with Emit initial snapshot, a capped first run still seeds its baseline in full, so the over-cap snapshot rows are not re-emitted.

## `emitInitialSnapshot` (type: `boolean`):

By default the FIRST run of each list only seeds the baseline and emits nothing. Enable to emit every entity as an 'added' record on that first run instead (subject to filters and the max-changes cap).

## Actor input object example

```json
{
  "lists": [
    "ofac",
    "un",
    "uk"
  ],
  "programs": [],
  "entityTypes": [],
  "maxItems": 1000,
  "emitInitialSnapshot": false
}
```

# Actor output Schema

## `records` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "lists": [
        "ofac",
        "un",
        "uk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datadeltas/sanctions-delta-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "lists": [
        "ofac",
        "un",
        "uk",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("datadeltas/sanctions-delta-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "lists": [
    "ofac",
    "un",
    "uk"
  ]
}' |
apify call datadeltas/sanctions-delta-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datadeltas/sanctions-delta-monitor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dgOS0Fs3J5ZP7enux/builds/AG8okVdF9v8eqAsiU/openapi.json
