# Regulation Radar (`conceivable_extension/regulation-radar`) Actor

Tracks UK regulatory change itself — new/amended statutory instruments and FCA policy — with a real section-level diff engine, not entity compliance status. Plain-English change summaries from real government sources, not raw document dumps.

- **URL**: https://apify.com/conceivable\_extension/regulation-radar.md
- **Developed by:** [joseph fadero](https://apify.com/conceivable_extension) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 document checked no changes

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

## Regulation Radar

**Watches the regulatory framework changing, not your compliance status against it.** This is distinct from two other actors in this account's regulatory family, and that distinction matters for which one a buyer actually needs:

| Actor | Watches |
|---|---|
| [UK Regulatory Compliance Status Watchdog](../../UK%20Regulatory%20Compliance%20Status%20Watchdog) (Actor 23) | *your* entity's compliance status against a fixed regulatory framework |
| [EUDR-CSRD Supply-Chain Data Feed](../../EUDR-CSRD%20Supply-Chain%20Data%20Feed) (Actor 29) | *your* supply chain's status against a specific EU framework |
| **Regulation Radar (this actor)** | **the framework itself changing** — new regulation, amended regulation, regulator guidance, consultations, enforcement actions — independent of any single watched company |

If a buyer needs "am I compliant," they need Actor 23 or 29. If they need "what changed in the law this week, and why does it matter," they need this actor.

### The real differentiator: a genuine section-level diff engine

Most "compliance monitoring" tools hand over a PDF or a diff of raw HTML and call it done. This actor stores a real structured snapshot of every document it tracks (via the same `deltaStore.ts` module reused across this program — see below), and on each subsequent run, diffs the new version against the stored one **section by section**, not just "changed: yes/no." `changeSummary` names which section changed and what moved, in plain language — not a raw HTML diff dump.

**Validated against 3 real, known, genuinely amended UK statutory instruments** (fetched live, two real point-in-time text versions of each):

- The Money Laundering Regulations 2017 (SI 2017/692) — 2018 vs 2022 text, 158→220 real sections
- The Building Regulations 2010 (SI 2010/2214) — 2013 vs 2022 text, 78→136 real sections
- The Data Protection, Privacy and Electronic Communications (Amendments etc) (EU Exit) Regulations 2019 (SI 2019/419) — 2019 vs 2021 text

In all three, the engine correctly identified which real sections changed and produced a readable, section-anchored summary rather than a wall of markup. UK legislative text itself contains real amendment-tracking markers (e.g. `[ F27 ... ]`, a genuine legislation.gov.uk convention for cross-referencing which later instrument changed a given passage) — these appear in `changeSummary` when present because they're part of the real source text, not stripped out as if they were noise; they're actually useful provenance, not garbage.

Heavily-amended documents can trigger dozens of real section-level deltas in one diff (the Money Laundering Regulations example above did). Rather than dump all of them, `changeSummary` reports the most significant ones and states plainly how many more weren't shown — a genuine plain-English summary, not a full raw diff.

### Real sources — what was checked, what was kept, what was dropped

**UK — 3 real, live, keyless sources, confirmed working:**

1. **`legislation.gov.uk`'s UKSI Atom feed** (`/uksi/data.feed`) — the UK government's own official feed for new Statutory Instruments. Real, rich metadata per entry (`ukm:Subject`, a genuine official plain-English `<summary>`, made/published dates) plus links to full text in multiple formats. This actor also fetches each instrument's `data.xht` for real section-headed full text — confirmed live to have genuine structure (5 real headings / 28 paragraphs on a fresh SI; 150+ real headings on a heavily-amended one).
2. **`fca.org.uk/publications/rss.xml`** — real, structured, and — critically — carries a genuine `<category>` field per item (`Consultation papers`, `Policy statements`, `Good and poor practice`, `External research`, `Data`, confirmed across a live sample) that maps directly and reliably to the PRD's `documentType` enum, no keyword guessing needed for this source.
3. **`fca.org.uk/news/rss.xml`** — real FCA press releases, including enforcement/tribunal coverage that doesn't appear in the publications feed at all (no dedicated FCA enforcement RSS feed exists — `news/final-notices/rss.xml` 404s). Classified by keyword since this feed's own `<category>` is a generic label ("Press Releases") shared by nearly every item.

**ICO — checked live, genuinely dropped from v1:** `ico.org.uk`'s "RSS feeds" page (`/global/rss-feeds/decision-notices/`, `/enforcement/`) return HTML landing pages, not RSS/XML — confirmed via direct fetch, content-negotiation headers, common URL-variant guesses (`/rss.xml`, `/feed`, etc., all 404), and checking for an RSS `<link rel="alternate">` autodiscovery tag in the page head (none present). No JSON/API alternative or sitemap hint was found either. This matches independent research findings that ICO's RSS infrastructure has been broken since a site redesign. Not silently ignored — ICO coverage is a real, documented gap in v1, not assumed working.

**EU — checked live, genuinely dropped from v1:** Three real paths checked for a keyless EU-wide new-legislation discovery source, all ruled out:

1. EUR-Lex RSS alerts require an account-bound saved search (`myRssId`) created interactively — there's no public, keyless, "give me all new legal acts" feed URL.
2. The "recent legal acts" search page (`/collection/eu-law/legal-acts/recent.html`) and the daily Official Journal L-series view (`/oj/daily-view/L-series/`) are both JS-rendered — confirmed live (near-empty raw HTML, results populated client-side) with no discoverable public API backing them.
3. Direct CELEX/OJ URI access (`/legal-content/EN/TXT/?uri=OJ:L_202600001`) does work for a **known** document ID (confirmed live — resolved a real 2026 delegated regulation), but that's read-access to an already-known document, not a discovery mechanism for new ones.

`jurisdiction: ["EU"]` is kept in the input schema (per the original spec) rather than removed, but selecting it produces an honest `fetchStatus: "failed"` record explaining exactly why, rather than silently returning nothing or fabricating EU coverage that doesn't exist. UK jurisdiction results are unaffected when both are selected.

### Document-type classification and severity scoring

- **UK Statutory Instruments:** `(Amendment)` in the title is a standard, official UK SI naming convention — reliably distinguishes an amending instrument from a new one. Falls back to `new_regulation` otherwise (SIs are, by definition, new legal instruments when first published).
- **FCA publications:** mapped directly from the source's own real `<category>` field (see above) — no guessing where the source already tells us.
- **FCA news / anything without a usable category:** keyword-classified, order-sensitive (enforcement/consultation-specific phrases checked before the generic guidance fallback — the same substring-ordering lesson from this program's earlier actors).
- **Severity (1-5):** base score by document type (enforcement action > new/amended regulation > consultation > guidance — enforcement carries immediate legal consequence for someone, a consultation doesn't yet), +1 if implementation is within 90 days, +1 if it maps to 3+ industries. Confirmed live: enforcement actions score at or above consultations across the real test set, as required.

### Industry/topic mapping and `affectedActivities` — an honest limitation

Neither source exposes an official field matching the PRD's `industries`/`topics` vocabulary (`legislation.gov.uk`'s `ukm:Subject` is real but differently-shaped UK government subject headings like "OFFENDER MANAGEMENT, ENGLAND AND WALES"; FCA's categories describe document type, not industry). `affectedIndustries`/`topics` filtering is keyword-based against each document's real text — best-effort, returns an empty array rather than guessing when nothing matches. `affectedActivities` reuses each source's own real category/subject field verbatim, since that's genuine source-provided context even though the PRD didn't specify its own vocabulary for it.

### Modes

| Mode | Behavior |
|---|---|
| `jurisdiction_snapshot` | Every real document currently available for the selected jurisdiction(s), optionally filtered by `industries`/`topics` |
| `topic_monitor` | Iterates `watchList` entries, each scoped to one jurisdiction + topic set — built for scheduled recurring runs (see n8n Workflow A below) |

Both modes always run the diff engine and store a snapshot for next time — the diff engine is this actor's core value, not an opt-in feature.

### Shared "Radar" architecture reused here

- **Diff:** `src/shared/deltaStore.ts` — the same module from Actor 26, reused unmodified across 7 actors now (26, 27, 34, 35, 37, and here), storing each document's full `DocumentSnapshot` so the diff engine has real previous content to work from, not just a changed/unchanged flag.
- **Classify:** keyword-based, order-sensitive, real-category-first where a source provides one.
- **Explain:** rule-based plain-English generation from real diff output — no external LLM call (consistent with every actor in this program).

### Output schema

```json
{
  "sourceRegulator": "string",
  "documentType": "new_regulation | amended_regulation | guidance | consultation | enforcement_action",
  "title": "string",
  "affectedIndustries": ["string"],
  "affectedActivities": ["string"],
  "changeSummary": "string",
  "previousVersionUrl": "string | null",
  "currentVersionUrl": "string",
  "implementationDate": "string | null",
  "severityScore": "number (1-5)",
  "changedSinceLastRun": "boolean",
  "sourceUrl": "string",
  "checkedAt": "ISO timestamp",
  "fetchStatus": "success | failed",
  "errorMessage": "string | null"
}
```

`previousVersionUrl` is `null` on first sighting of a document (no previous version exists yet), populated on every run after that.

### Setup note

No browser needed — every real source (legislation.gov.uk, FCA) works over plain HTTP/RSS/Atom. UKSI full-text fetches are capped at 25 per run (each is 500KB-1.8MB) to keep runtime and memory reasonable; entries beyond that cap fall back to the feed's own real summary text rather than being dropped.

### Pricing

| Event | Price |
|---|---|
| Run started | £0.05 |
| Reading success | £0.06 |
| Fetch failed | free |

This actor's structured, evidence-layer output is well-suited to AI agent consumption — e.g. an agent researching "what changed in UK financial regulation this month" is a direct, well-defined query this actor answers.

### n8n integration

- **Workflow A (trigger):** scheduled weekly run against a watched jurisdiction/industry/topic combination (`topic_monitor` mode), logging all detected regulatory activity.
- **Workflow B (processing):** alert on `changedSinceLastRun: true` where `severityScore >= 4`, routed as urgent; lower-severity changes logged for a periodic digest rather than immediate alert.

# Actor input Schema

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

jurisdiction\_snapshot: every real document currently available for the selected jurisdiction, optionally filtered by industries/topics. topic\_monitor: iterates watchList entries, each scoped to one jurisdiction + topic set — built for scheduled recurring runs. Both modes always run the diff engine and store a snapshot for next time.

## `jurisdiction` (type: `array`):

UK is fully covered by real, verified sources (legislation.gov.uk statutory instruments, FCA policy/consultation/news feeds). EU is accepted here per the original spec but returns an honest 'no real source available' record — no free, keyless, machine-readable EU-wide new-legislation discovery source was found live (see README: EUR-Lex RSS requires an account-bound saved search, and its search/daily-view pages are JS-rendered with no public API). Not silently ignored — explained in the output.

## `industries` (type: `array`):

Optional filter. Matched against each real document's own text via keyword mapping — best-effort, not an official taxonomy field on any source (see README).

## `topics` (type: `array`):

Optional filter. Matched against each real document's own text via keyword mapping — best-effort, not an official taxonomy field on any source (see README).

## `watchList` (type: `array`):

Required for topic\_monitor mode. A list of { jurisdiction, topics } pairs to check on each scheduled run — e.g. weekly, per the n8n companion workflow.

## Actor input object example

```json
{
  "mode": "jurisdiction_snapshot",
  "jurisdiction": [
    "UK"
  ]
}
```

# Actor output Schema

## `resultsDatasetUrl` (type: `string`):

New and amended regulation, regulator guidance, consultations, and enforcement actions tracked independent of any single watched company, produced by this run.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("conceivable_extension/regulation-radar").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("conceivable_extension/regulation-radar").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 '{}' |
apify call conceivable_extension/regulation-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,conceivable_extension/regulation-radar"
        }
    }
}
```

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/JB2RrTRwbwO6vWQUv/builds/BWF2migQeXybGmuVv/openapi.json
