# SiteVerdict — UK Modern Slavery Statement Registry Search (`siteverdict/siteverdict-uk-modern-slavery-statements`) Actor

Search the official UK Home Office Modern Slavery Statement Registry (open data, OGL) by company, sector or turnover, score statement completeness, check supplier lists for missing or outdated statements and monitor changes with alerts.

- **URL**: https://apify.com/siteverdict/siteverdict-uk-modern-slavery-statements.md
- **Developed by:** [Aman Thakran](https://apify.com/siteverdict) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SiteVerdict — UK Modern Slavery Statement Registry Search

**Find out in one run which of your suppliers have a current modern slavery statement on the UK Home Office registry, which are missing or out of date, and what each statement actually covers. Then keep watching them on a schedule.**

> **Not legal advice.** The registry is self-reported and, for most private companies, submission is voluntary. A supplier that is not on the registry may still have published a compliant statement on its own website. Always check the statement itself before drawing conclusions.

### What it does

The Actor reads the official **Modern slavery statement registry** open data published by the Home Office (one CSV per statement year, updated daily, Open Government Licence v3.0). It never scrapes search pages.

It runs in three modes:

| Mode | You give | You get |
|---|---|---|
| **search** | Filters: organisation name, company number, sector, turnover band, public/private, group submissions, "missing areas", completeness score, updated since | One row per statement with the six-area coverage, risks reported, policies, training, audits, grievance mechanisms, links to the registry summary, the statement and the PDF |
| **supplier-check** | Your supplier list (name and/or Companies House number) | One row per supplier: `FOUND_CURRENT`, `FOUND_OUTDATED`, `POSSIBLE_MATCH`, `NOT_FOUND` or `INVALID_INPUT`, how it was matched (company number, exact name, group parent, fuzzy), years on the registry, completeness score and flags |
| **monitor** | The same supplier list, run on a schedule | Only what changed since the last run (new statement, updated statement, now found, no longer found, became outdated, score change), with a Slack / webhook alert |

Every statement also gets a transparent **completeness score (0–100)** and plain-English **flags**. The score covers what the organisation reported to the registry; it is not a legal assessment.

- **Six areas (72 points).** The six areas in s.54(5) Modern Slavery Act 2015 are organisation structure, policies, risk assessment, due diligence, training, and goals/KPIs. Each area covered earns 12 points.
- **Approval date recorded (8 points).**
- **Link to the full statement (8 points).**
- **Roughly 12-month reporting period (4 points).**
- **Specific risks reported (4 points).**
- **Progress or ILO indicators (4 points).**

The flags are:

| Flag | Meaning |
|---|---|
| `MISSING_AREAS` | One or more of the six areas is not covered. |
| `NO_STATEMENT_URL` | No link to the full statement on the organisation's website. |
| `NO_APPROVAL_DATE` | No board or approval date recorded. |
| `LATE_PUBLICATION` | Approved more than 6 months after the period end. |
| `PERIOD_NOT_12_MONTHS` | The reporting period is not roughly 12 months. |
| `STALE_PERIOD` | The reporting period ended more than 24 months ago. |
| `NO_RISKS_REPORTED` | No specific modern slavery risks were reported. |
| `VOLUNTARY_UNDER_THRESHOLD` | Turnover is under £36m, so the statement is likely voluntary. |

### Who it is for

1. **Procurement and supplier-onboarding teams.** Run your supplier master list once a quarter and see who needs chasing.
2. **ESG, sustainability and compliance analysts.** Benchmark a sector: for example, retail statements that miss due diligence or training, or companies over £500m with low scores.
3. **Consultancies, auditors and journalists.** Pull clean, analysis-ready data with registry links in seconds, instead of downloading and cleaning 18 MB CSVs by hand.

AI agents can use it too, through the SiteVerdict MCP server (see `MCP-TOOL.md`).

### Example: supplier check

Input:

```json
{
  "mode": "supplier-check",
  "suppliers": [
    { "ref": "sup-001", "name": "Acme Widgets Ltd" },
    { "ref": "sup-002", "name": "Beta Foods plc", "companyNumber": "SC123456" },
    { "ref": "sup-003", "name": "Gamma Holdings PLC" },
    { "ref": "sup-004", "name": "Unknown Supplier Ltd" }
  ]
}
```

**Before:** a spreadsheet of supplier names and a browser tab on the registry search page.

**After:** one row per supplier (shortened):

| ref | supplier | status | matched by | years | areas | score | flags |
|---|---|---|---|---|---|---|---|
| sup-001 | Acme Widgets Ltd | FOUND_CURRENT | exact-name | 2024, 2025 | 6/6 | 100 | – |
| sup-002 | Beta Foods plc | FOUND_OUTDATED | company-number | 2023 | 4/6 | 68 | MISSING_AREAS, STALE_PERIOD, NO_RISKS_REPORTED |
| sup-003 | Gamma Holdings PLC | FOUND_CURRENT | parent-name (group statement) | 2025 | 6/6 | 96 | – |
| sup-004 | Unknown Supplier Ltd | NOT_FOUND | – | – | – | – | "does NOT prove non-compliance: check their website" |

A live check on 11 Oct 2026 matched "Marks and Spencer Group plc" to the registry entry *MARKS AND SPENCER P.L.C.* (5 of 6 areas, score 84). It also found Tesco PLC (score 96) and J Sainsbury plc (score 100). 2025 and 2026 together came to 24,788 registry rows, loaded in about 12 s.

Try it free with `"sampleMode": true`. Sample mode uses a bundled synthetic file with the registry's real column layout, makes no network calls and charges nothing.

### Example: search

```json
{ "mode": "search", "sectors": ["Retail"], "turnoverBands": ["Over £500 million"], "onlyMissingAreas": true, "years": ["2025"] }
```

### Output

- **Dataset.** Views: **Statements**, **Supplier check**, **Changes since last run**. Export as CSV, Excel or JSON.
- **Key-value store:**
  - `REPORT`: an HTML report you can share;
  - `STATEMENTS.csv` or `SUPPLIERS.csv`;
  - `SUMMARY`: agent-ready JSON with the years loaded, totals, alert delivery results and the data source and licence.

### Monitoring and alerts

1. Schedule the Actor (for example weekly) in **monitor** mode with your supplier list.
2. The first run records a baseline in a named key-value store (`stateStoreName`).
3. Later runs report only changes and post them to your **Slack incoming webhook** and/or an **HTTPS webhook** (both stored as secrets, never logged).

### Pricing (pay per event)

| Event | When | Proposed price |
|---|---|---|
| `statement-record` | each statement returned by a search | $0.002 |
| `supplier-checked` | each valid supplier checked (any status, including NOT_FOUND) | $0.01 |
| `change-alert` | each supplier with a real change in monitor mode (never the baseline) | $0.02 |

Examples:

- 100 suppliers checked ≈ **$1.00**.
- A search returning 500 statements ≈ **$1.00**.
- Monitoring 200 suppliers weekly with about 5 changes a month ≈ **$8.10/month**.

Invalid inputs, failed downloads and sample-mode runs are never charged, and the run stops at your maximum total charge.

### FAQ

**Is a supplier missing from the registry breaking the law?**
Not necessarily. Section 54 requires commercial organisations with £36m+ turnover that do business in the UK to *publish* a statement on their website. Registry submission is voluntary for most companies. Treat `NOT_FOUND` as "ask the supplier", not as a finding.

**How accurate is matching?**
Company number is exact. Name matching ignores case, punctuation and legal suffixes, then checks group parents. Anything fuzzy is labelled `POSSIBLE_MATCH` with a similarity score so a human can confirm it. Give company numbers where you can.

**Which years are loaded?**
By default:

- **search:** the latest year (if the latest year is still nearly empty, fewer than 1,000 statements, the previous year is loaded too);
- **supplier-check and monitor:** the latest 3 years, so older statements show as `FOUND_OUTDATED`.

Set `years` to choose your own.

**Do you output personal data?**
The registry publishes the name and role of the person who approved each statement. We drop it by default (`includePersonalData: false`). Organisation addresses are business addresses.

**How fresh is the data?**
The Home Office regenerates the files daily. Each run downloads the current files, about 8–19 MB per year.

### Limits

- Data is only as good as what organisations submitted. Answers are self-reported and not verified by the Home Office or by us.
- Fuzzy matching only compares names that share their first significant word. Unusual trading names may need the company number.
- Each yearly file is downloaded per run, about 1–3 minutes for several years. Use `years` to limit it.
- The completeness score is our heuristic, explained above. It is not the Home Office's view and not legal advice.

### Sources & compliance

- **Source:** Home Office, *Modern slavery statement registry* open data, from https://modern-slavery-statement-registry.service.gov.uk/download. The files are `https://downloads.modern-slavery-statement-registry.service.gov.uk/publicdownloads/StatementSummaries<YEAR>.csv`. Checked 11 Oct 2026: the data is updated daily.
- **Licence:** Open Government Licence v3.0 (https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/). Every row carries the attribution: *Contains public sector information licensed under the Open Government Licence v3.0 (Home Office, Modern slavery statement registry).* Commercial re-use is permitted under OGL v3.0 with attribution.
- **Access:** we download only the published open-data files, with an honest User-Agent (`SiteVerdict/uk-modern-slavery-statements (+aman.thakran@bharatfare.com)`). robots.txt is respected, retries are polite and nothing is scraped behind a login.
- **UK GDPR:** the approver's name is personal data published by the registry. It is off by default (data minimisation). If you enable it, you are the controller for your use and need a lawful basis, typically legitimate interests for supply-chain due diligence. PECR does not apply: we send no marketing communications.
- **Legal context:** see Modern Slavery Act 2015 s.54 and the Home Office statutory guidance *Transparency in supply chains: a practical guide*.

Made by SiteVerdict, Aman Thakran / BharatFare Travel and Technologies Ltd (UK). Contact: aman.thakran@bharatfare.com.

# Changelog

This Actor's version history is a separate document: https://apify.com/siteverdict/siteverdict-uk-modern-slavery-statements/changelog.md

# Actor input Schema

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

<b>search</b>: filter registry statements by organisation, sector, turnover, completeness. <b>supplier-check</b>: one row per supplier with FOUND_CURRENT / FOUND_OUTDATED / POSSIBLE_MATCH / NOT_FOUND. <b>monitor</b>: like supplier-check, but compares with the previous run and alerts on new or updated statements.

## `suppliers` (type: `array`):

Array of objects <code>{"ref": "your id", "name": "Company name", "companyNumber": "01234567"}</code>. Company number gives the most reliable match; name is matched ignoring case, punctuation and legal suffixes (Ltd, plc …), then by group parent, then fuzzily (flagged POSSIBLE_MATCH). Max 5,000.

## `supplierLines` (type: `array`):

Alternative to the JSON above, one per line: <code>Company name | company number | your ref</code> (number and ref optional).

## `organisationNames` (type: `array`):

Case-insensitive; also matches the group parent name. Leave empty for all organisations.

## `companyNumbers` (type: `array`):

Companies House numbers (zero padding is added automatically).

## `sectors` (type: `array`):

Matches the registry's sector answers, e.g. <i>Retail</i>, <i>Construction</i>, <i>Textiles</i>, <i>Technology</i>, <i>Transport and logistics</i>.

## `turnoverBands` (type: `array`):

Registry turnover bands to include (empty = all).

## `sectorType` (type: `string`):

Private companies or public bodies.

## `groupSubmission` (type: `string`):

Group statements cover several organisations (one row per organisation).

## `onlyMissingAreas` (type: `boolean`):

Keep only statements that say they do not cover at least one of the six recommended areas (structure, policies, risk assessment, due diligence, training, goals/KPIs).

## `minCompletenessScore` (type: `integer`):

Our transparent 0–100 score of what was reported to the registry (see README).

## `maxCompletenessScore` (type: `integer`):

Use e.g. 60 to find weak statements.

## `updatedSince` (type: `string`):

Only statements whose registry entry was updated on or after this date.

## `latestPerOrganisation` (type: `boolean`):

When several years are loaded, keep one row per organisation.

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

Each returned statement is one billable event.

## `years` (type: `array`):

Statement years, e.g. <code>2024</code>, <code>2025</code>. Empty = the most recent N years offered by the registry (see next field).

## `yearsToLoad` (type: `integer`):

Default: 1 for search, 3 for supplier-check / monitor (so older statements are found and flagged as outdated).

## `fuzzyMatchThreshold` (type: `string`):

Similarity needed for a POSSIBLE_MATCH when no exact name / number / parent match exists.

## `currentStatementYear` (type: `integer`):

Statements for this year or later are FOUND_CURRENT; older ones FOUND_OUTDATED. Default: last full year.

## `includeDetail` (type: `boolean`):

Turn off for smaller rows.

## `includePersonalData` (type: `boolean`):

The registry publishes the name and role of the person who approved each statement. Off by default (data minimisation, UK GDPR). Turn on only if you have a purpose for it.

## `stateStoreName` (type: `string`):

Named key-value store that keeps the previous run (monitor mode). Use different names for different supplier lists.

## `alertOnFirstRun` (type: `boolean`):

By default the first monitor run only records a baseline.

## `webhookUrl` (type: `string`):

HTTPS endpoint that receives a JSON summary of changes. Stored encrypted; never logged.

## `slackWebhookUrl` (type: `string`):

Slack message with the changed suppliers. Stored encrypted; never logged.

## `generateReport` (type: `boolean`):

Saves REPORT (HTML), STATEMENTS.csv / SUPPLIERS.csv and SUMMARY to the run's key-value store.

## `sampleMode` (type: `boolean`):

Runs on a small synthetic fixture with the registry's real column layout. No network, no charges. Good for testing integrations.

## Actor input object example

```json
{
  "mode": "search",
  "suppliers": [
    {
      "ref": "sup-001",
      "name": "Tesco PLC"
    },
    {
      "ref": "sup-002",
      "name": "Example Supplier Ltd",
      "companyNumber": "01234567"
    }
  ],
  "organisationNames": [
    "tesco"
  ],
  "sectorType": "any",
  "groupSubmission": "any",
  "onlyMissingAreas": false,
  "latestPerOrganisation": false,
  "maxResults": 1000,
  "fuzzyMatchThreshold": "0.88",
  "includeDetail": true,
  "includePersonalData": false,
  "stateStoreName": "siteverdict-modern-slavery-monitor",
  "alertOnFirstRun": false,
  "generateReport": true,
  "sampleMode": false
}
```

# Actor output Schema

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

No description

## `report` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `files` (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 = {
    "suppliers": [
        {
            "ref": "sup-001",
            "name": "Tesco PLC"
        },
        {
            "ref": "sup-002",
            "name": "Example Supplier Ltd",
            "companyNumber": "01234567"
        }
    ],
    "organisationNames": [
        "tesco"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("siteverdict/siteverdict-uk-modern-slavery-statements").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 = {
    "suppliers": [
        {
            "ref": "sup-001",
            "name": "Tesco PLC",
        },
        {
            "ref": "sup-002",
            "name": "Example Supplier Ltd",
            "companyNumber": "01234567",
        },
    ],
    "organisationNames": ["tesco"],
}

# Run the Actor and wait for it to finish
run = client.actor("siteverdict/siteverdict-uk-modern-slavery-statements").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 '{
  "suppliers": [
    {
      "ref": "sup-001",
      "name": "Tesco PLC"
    },
    {
      "ref": "sup-002",
      "name": "Example Supplier Ltd",
      "companyNumber": "01234567"
    }
  ],
  "organisationNames": [
    "tesco"
  ]
}' |
apify call siteverdict/siteverdict-uk-modern-slavery-statements --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,siteverdict/siteverdict-uk-modern-slavery-statements"
        }
    }
}
```

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/gMhc8j5YZdTSAOalD/builds/1aK4txWNmoKR4eapN/openapi.json
