# UFLPA Entity List Screener & Delta Tracker — DHS (`malonestar/uflpa-entity-list-monitor`) Actor

Screen suppliers against the official DHS UFLPA Entity List — the forced-labor import ban. Every barred entity by statutory sub-list with aliases, effective dates and source Federal Register notices, plus a delta mode that flags additions since your last run. Keyless and correctness-first.

- **URL**: https://apify.com/malonestar/uflpa-entity-list-monitor.md
- **Developed by:** [Kyle Maloney](https://apify.com/malonestar) (community)
- **Categories:** Business, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.60 / 1,000 uflpa screening results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## UFLPA Entity List Monitor & Delta Tracker

The authoritative **DHS UFLPA Entity List** — the U.S. government's list of companies whose goods are **barred from import** under the Uyghur Forced Labor Prevention Act's rebuttable presumption of forced labor — as clean, structured, screenable data, plus **delta tracking** of every addition over time.

If you import into the United States, screening counterparties against the UFLPA Entity List is not optional: U.S. Customs and Border Protection detains merchandise linked to a listed entity **at the port**, on issuance. This actor turns the list DHS publishes as three HTML tables into one row per entity — with **aliases, effective dates, the statutory sub-list, and the originating Federal Register notice** — so you can screen it, diff it, and wire it into a compliance pipeline.

Most trade-compliance tools on the market slap a derived "forced-labor risk" flag onto third-party shipping data. **This is the actual list**, reproduced faithfully from the primary source, and tracked for changes.

### Who it's for

- **Importers & customs brokers** — screen suppliers and their upstream vendors before a shipment is detained.
- **Trade-compliance & sanctions teams** — keep an internal screening list current; get alerted the day new entities are added.
- **Supply-chain / ESG / forced-labor due-diligence** — map exposure to Xinjiang-linked entities and the "poverty alleviation" / "pairing-assistance" labor programs.
- **Procurement & vendor onboarding** — check a new counterparty (and its aliases) against the ban list in one call.
- **Freight forwarders, 3PLs, sourcing agents** — verify goods will clear before they move.
- **AI agents** — a clean, chainable UFLPA-screening tool (see "Use as an MCP tool").

### What it does

- **Reads the primary source.** The current list comes straight from the DHS UFLPA Entity List page (`dhs.gov/uflpa-entity-list`), organized by the four statutory sub-lists under UFLPA Section 2(d)(2)(B).
- **Parses aliases faithfully.** A company hiding under an alias, a.k.a., or former name is still caught — search matches names **and** aliases (e.g. "Bingtuan" resolves to the Xinjiang Production and Construction Corps).
- **Attributes each entry to its Federal Register notice** by effective date, so you can cite the source of every addition.
- **Cross-checks currency.** Every run corroborates the DHS page against the newest UFLPA Entity List Federal Register notice, so you know the list you got reflects the latest official update.
- **Tracks changes.** `delta` mode reports only what is new since your last run — the additions that matter for an alerting pipeline.

### Modes

#### `list` — the full current list (default)

Returns every entity-by-sub-list row on the current UFLPA Entity List (about 200 rows today; it only grows).

```json
{ "mode": "list", "maxResults": 500 }
```

#### `search` — screen a counterparty

Filter by company name (matched against names **and** aliases) and/or a statutory sub-list.

```json
{ "mode": "search", "query": "Hoshine" }
```

```json
{ "mode": "search", "sublist": "v" }
```

#### `delta` — new since last run

Reports entries added since your previous run for the same scope, using a named cross-run baseline. **The first run for a scope stores a baseline and fails with an explanatory message** (rather than billing the whole list as "new") — schedule it and subsequent runs report genuine additions.

```json
{ "mode": "delta" }
```

#### Optional date window (any mode)

`addedSince` / `addedUntil` filter by the entry's effective (added) date. **Strictly `YYYY-MM-DD`** — slash dates and month names are rejected loudly rather than applied ambiguously.

```json
{ "mode": "list", "addedSince": "2025-01-01" }
```

### Output fields

One row per entity **× statutory sub-list** (an entity on two sub-lists yields two rows; `entity_appears_on_sublists` names them all).

| Field | Meaning |
|---|---|
| `entity_name` | Canonical company/facility name |
| `entity_name_full` | Full name exactly as DHS lists it (with the alias parenthetical) |
| `aliases` / `alias_count` | Published aliases / a.k.a. / former names (`\|`-joined) — **screen against these too** |
| `sublist` / `sublist_section` / `sublist_label` | Which UFLPA §2(d)(2)(B) sub-list and its statutory basis |
| `effective_date_iso` / `effective_date_raw` | When the entity was added on this sub-list |
| `entity_appears_on_sublists` / `entity_sublist_count` / `is_multi_sublist_entity` | Full sub-list membership for the entity |
| `entity_first_effective_date_iso` | When the entity was first added to the list |
| `source_fr_document_number` / `source_fr_url` | Originating Federal Register notice (matched by effective date) |
| `is_new_since_last_run` / `delta_baseline_status` | `delta` mode: additions since last run (`null` in other modes — "not checked", never a guessed `false`) |
| `latest_fr_notice_*` | The most recent UFLPA Entity List FR notice (document number, date, URL) |
| `dhs_current_with_latest_fr_notice` | Whether the DHS page reflects that latest notice |
| `drift_gate_status` | `verified` or `verified_degraded` (a corroborating check was unavailable — disclosed, not hidden) |
| `list_total_occurrences` / `list_total_unique_entities` | Size of the current list this run parsed |
| `matched_total` / `results_truncated` / `run_max_results_cap` / `rows_emitted_this_run` | So a capped answer is never mistaken for a complete one |
| `occurrence_key` | Stable identity (normalized name :: sub-list) — the delta identity |

### Scope and cost — read this first

- **Pricing: pay-per-result at $12 per 1,000 rows** (with graduated volume discounts on paid tiers).
- The **entire current list is only ~200 rows**, so a full `list` pull costs roughly **$2.40**. A `search` for one company costs a few cents. A `delta` run bills only the genuinely new entries — usually **$0** on a run where nothing was added.
- `maxResults` is a **hard cap on rows emitted and billed**. Every row carries `matched_total` and `results_truncated` so you always know whether you got the whole answer.
- **If the source cannot be reached and verified, the run fails and bills nothing.** A UFLPA screen must never report "clear" from an unreachable list — so you are never charged for a run that could not actually confirm the list.

### Correctness — why you can trust a "clear"

This actor is built so that an empty or "not found" answer is only ever produced when it is genuinely true:

- **Live drift gate before any billable row.** Every run verifies (1) the list is at least a floor size, (2) a pinned long-standing entity (the Xinjiang Production and Construction Corps) is present on its expected sub-list and effective date, (3) a nonsense query matches nothing, and (4) the DHS page reflects the latest Federal Register notice. If the load-bearing checks can't complete, the run **fails loudly** — it does not emit a clean empty list.
- **HTML-error-page guard.** A maintenance or rate-limit page served at HTTP 200 is rejected, never parsed into an empty "no entities" answer.
- **Aliases are first-class.** A counterparty on the list under an alias is matched — the failure mode of "screened clear because we only checked the primary name" is designed out.
- **Faithful, not derived.** Names, sub-lists, effective dates and aliases are reproduced from the primary source; nothing is inferred or scored.

### Use as an MCP tool

This actor is callable by AI agents (Claude, Cursor, etc.) via Apify's MCP server (`mcp.apify.com`). Its input and output fields are fully described, so an agent can screen a counterparty and chain the result into a decision.

Worked agent prompt:

> "Screen the supplier **Hesheng Silicon Industry** against the UFLPA Entity List. If it appears (including under any alias), tell me the statutory sub-list, the effective date, and the Federal Register notice."

Billing is unchanged when called as a tool: you pay per result row, and a run that cannot verify the list fails without billing.

### FAQ

**Is the UFLPA Entity List free to check somewhere?** DHS publishes it as HTML tables you must read by eye. This actor turns it into structured, searchable, diff-able rows with aliases and source citations — the work of screening and monitoring, not just reading.

**How current is it?** It reads the live DHS page every run and corroborates against the newest UFLPA Entity List Federal Register notice. `dhs_current_with_latest_fr_notice` tells you whether the page has caught up to the latest notice.

**What are the sub-lists (i)/(ii)/(iv)/(v)?** The statutory categories under UFLPA §2(d)(2)(B): (i) Xinjiang entities that mine/produce/manufacture with forced labor; (ii) entities working with the Xinjiang government to source forced labor; (iv) exporters into the US; (v) entities/facilities sourcing material from Xinjiang or from government forced-labor programs. (iii)/(iv) currently carry no separate DHS table — DHS states no additional exporters have been identified.

**Does it include addresses?** DHS does not publish addresses on the Entity List — only entity names, aliases, and effective dates — so this actor does not fabricate them. It provides the name, aliases, sub-list, effective date, and source notice.

**Does the row count match DHS's headline number exactly?** This actor reports its own measured totals (`list_total_occurrences`, `list_total_unique_entities`). DHS's headline count can differ slightly from the unique-name count because of how multi-sub-list and descriptor variants are counted; the list content is reproduced faithfully either way.

### Source & disclaimer

Data: U.S. Department of Homeland Security UFLPA Entity List (`dhs.gov/uflpa-entity-list`) and the Federal Register API (`federalregister.gov`), both public and keyless. This actor is an unofficial convenience tool and is not affiliated with DHS, CBP, or the Forced Labor Enforcement Task Force. Always confirm a screening decision against the official DHS list and the relevant Federal Register notice; this actor cites both on every row.

# Actor input Schema

## `mode` (type: `string`):

What to return. "list" = the full current DHS UFLPA Entity List, one row per entity-and-sub-list occurrence (name, aliases, statutory sub-list, effective date, originating Federal Register notice). "search" = filter the current list by a company-name query (matched against names AND aliases) and/or a statutory sub-list. "delta" = only entries new since your last run for the same scope, tracked in the named key-value store 'uflpa-entity-list-baseline'; the FIRST delta run stores a baseline and fails with an explanatory message rather than billing the whole list as new.

## `query` (type: `string`):

Company-name phrase to screen against the list, e.g. "Hoshine" or "Aksu". Case-insensitive substring, matched against each entity's name, its full listed name, AND every published alias / former name — so a counterparty hiding under an alias is still caught. Required for search mode (a sub-list alone also satisfies it).

## `sublist` (type: `string`):

Optional filter to one UFLPA Section 2(d)(2)(B) sub-list: i (Xinjiang entities that mine/produce/manufacture with forced labor), ii (entities working with the Xinjiang government to recruit/transport/harbor forced labor), iv (exporters into the US), v (facilities/entities sourcing material from Xinjiang or forced-labor programs). Leave blank for all sub-lists. Note (iii)/(iv) currently carry no separate DHS table.

## `addedSince` (type: `string`):

Only include entries whose effective (added) date is on or after this date. STRICTLY YYYY-MM-DD (e.g. 2025-01-01) — slash dates, month names and compact dates are rejected with a loud failure because they cannot be applied unambiguously. Leave blank for no lower bound (the list began 2022-06-21).

## `addedUntil` (type: `string`):

Only include entries whose effective (added) date is on or before this date. STRICTLY YYYY-MM-DD. Leave blank for no upper bound. An unusable value fails the run loudly; nothing is billed.

## `maxResults` (type: `integer`):

Hard cap on rows emitted AND billed this run. The whole current list is roughly 200 rows, so the default returns all of it; every row carries matched\_total and results\_truncated so a capped answer is never mistaken for a complete one.

## Actor input object example

```json
{
  "mode": "list",
  "maxResults": 500
}
```

# Actor output Schema

## `results` (type: `string`):

The default dataset.

# 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 = {
    "mode": "list",
    "maxResults": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/uflpa-entity-list-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 = {
    "mode": "list",
    "maxResults": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/uflpa-entity-list-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 '{
  "mode": "list",
  "maxResults": 500
}' |
apify call malonestar/uflpa-entity-list-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,malonestar/uflpa-entity-list-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/rMEdgAmScgRa0IGwp/builds/baoFbkhNQn3vhpMr9/openapi.json
