# UK Charity Commission Portfolio Status Monitor (`plym-actor-factory/uk-charity-commission-portfolio-status-monitor`) Actor

Watch a list of England & Wales charity registration numbers and emit typed Registered/Removed/name/interim-manager events from the official Charity Commission Register API (user-supplied key) and/or OGL full-register extract. Not an HTML scrape; not ComplyTrack/CharityIQ. Not OSCR/CCNI.

- **URL**: https://apify.com/plym-actor-factory/uk-charity-commission-portfolio-status-monitor.md
- **Developed by:** [Daniel Witney](https://apify.com/plym-actor-factory) (community)
- **Categories:** AI, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 charity status event delivereds

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

## UK Charity Commission Portfolio Status Monitor

Watch a **list of England & Wales charity registration numbers** and receive **typed Registered / Removed / name / interim-manager events** when the official **Charity Commission Register** flips — **Registered → Removed**, restorations, main-name changes, optional interim-manager flags. **Not** another Charity Commission directory scrape. **Not** ComplyTrack / CharityIQ seats. **Not** Companies House dissolution (different register). **Not** OSCR (Scotland) or CCNI (Northern Ireland) as primary.

### A1b (v8) — already PASS

Cited from `opportunity/reports/phase3-a1b-next3-v8.md` + `phase3-demand-first-v8.md` (do not invent competitors):

| Field | Evidence |
|-------|----------|
| **DIRECT SAME-JOB COMPETITORS** | **0** adopted charity#-portfolio status-change products. Directory dumps (different job): `ryanclinton/uk-charity-commission` (1 MAU / 9 tot); `scrapesage/uk-charity-commission-leads` (1); `parseforge/uk-charity-register-scraper` (1); `automation-lab/uk-charity-commission-register-scraper` (1 NEW); others @ 0–1. |
| **EXTERNAL DEMAND** | ComplyTrack / CharityIQ-class Charity Commission compliance monitoring seats; grant-makers re-check Registered status. |
| **OUR WEDGE** | Charity-number watchlist × scheduled Register API / OGL extract snapshot diff → typed events only for the book. |
| **Legal** | **GREEN** — OGL v3.0 / official API; user-supplied portal key for API path; trustee PII default **OFF**. |

### Honest coverage (read before buying)

| Included | **Not** included |
|----------|------------------|
| England & Wales charity# `reg_status` (R/RM ↔ Registered/Removed) | OSCR (Scotland) / CCNI (Northern Ireland) as primary |
| Main charity name changes | HTML scrape of register-of-charities UI |
| Optional interim manager (Register API `interim_manager_ind`) | ComplyTrack / CharityIQ keys |
| Official OGL full-register daily extract **or** Register API | Nationwide new-charity lead dumps |
| Lookup by **charity number** on your watchlist only | Trustee PII (default OFF) |
| Open Government Licence v3.0 attribution | SLA / uptime guarantees |

**Live paths:**

1. **OGL extract** (no key): stream-filter official `publicextract.charity.zip` for your watchlist.
2. **Register API** (user-supplied key): `GET …/charitydetails/{n}/{suffix}` / `charityRegNumber/{n}/{suffix}` with header `Ocp-Apim-Subscription-Key` (free [developer portal](https://api-portal.charitycommission.gov.uk/hub)).

First observation stores a **baseline** (no charge). Quiet days ≈ $0 product charges.

### Value proposition

- **Charity# watchlist × Register/OGL snapshot diff** → `UK_CHARITY_REMOVED`, `UK_CHARITY_REGISTERED_RESTORED`, `UK_CHARITY_NAME_CHANGED`, optional `UK_CHARITY_INTERIM_MANAGER`, `UK_CHARITY_GONE`.
- Official Commission HTTP / OGL only. **No ComplyTrack / CharityIQ key.**
- **Pay only for unique delivered change events.** Durable KVS checkpoint + `event_uid` dedupe.

### PRODUCTION USE (required for real monitoring)

> **Store default ≠ product.** Schema defaults use `sourceMode=fixture` so Apify Store daily auto-tests leave a non-empty health dataset **without** calling the Commission. That fixture path only writes a non-billable `RUN_STATUS` / `FIXTURE_HEALTH` row. It is **not** charity monitoring.

For **production monitoring** you **must**:

1. Set **`sourceMode` = `live`**
2. Choose **`liveBackend`**: `ogl` (free extract, no key) or `api` (requires `charityApiKey`)
3. Provide your `charityNumbers` watchlist
4. Schedule runs (daily is typical; Register/OGL are snapshot/poll-class, not a stream)

Official references:

- [Register of Charities](https://register-of-charities.charitycommission.gov.uk/en/) (England & Wales)
- [Full register download (OGL)](https://register-of-charities.charitycommission.gov.uk/en/register/full-register-download)
- [API developer portal](https://api-portal.charitycommission.gov.uk/hub)

### Apify Store daily auto-test / default input

| Field | Default |
|-------|---------|
| `charityNumbers` | `["202918","220949"]` |
| `signalGroups` | `status`, `identity`, `interim_manager` |
| `sourceMode` | `fixture` |
| `emitFixtureDemoEvents` | `false` |
| `includeTrustees` | `false` |
| `maxRunSeconds` | `55` |
| `requestPaceMs` | `250` |

On that path the Actor **SUCCEEDS** quickly, pushes exactly one `RUN_STATUS` / `FIXTURE_HEALTH` row (`billable: false`), and does **not** charge `charity-status-event-delivered`.

### Input (summary)

| Field | Notes |
|-------|--------|
| `charityNumbers` | Watchlist (required, England & Wales charity#) |
| `signalGroups` | `status`, `identity`, `interim_manager` |
| `sourceMode` | `fixture` (default) or `live` |
| `liveBackend` | `api` or `ogl` (auto: api if key else ogl) |
| `charityApiKey` | Required for live+api (`isSecret`) |
| `oglExtractUrl` | Optional OGL zip URL override |
| `emitFixtureDemoEvents` | Default **false** |
| `includeTrustees` | Default **false** (A5) |
| `maxRunSeconds` / `maxEvents` | Budgets |
| `resumeFromCheckpoint` | Default true |
| `requestPaceMs` | Default **250** (API path) |

#### Production example (OGL, no key)

```json
{
  "charityNumbers": ["202918", "220949", "205846"],
  "signalGroups": ["status", "identity"],
  "sourceMode": "live",
  "liveBackend": "ogl",
  "asOfHint": "2026-09-17",
  "maxRunSeconds": 300,
  "resumeFromCheckpoint": true
}
```

#### Production example (Register API)

```json
{
  "charityNumbers": ["202918", "220949"],
  "signalGroups": ["status", "identity", "interim_manager"],
  "sourceMode": "live",
  "liveBackend": "api",
  "charityApiKey": "<portal-subscription-key>",
  "maxRunSeconds": 300,
  "requestPaceMs": 250,
  "resumeFromCheckpoint": true
}
```

### Output

#### Change events (billable under PPE)

Typed rows include: `charity_number`, `charity_name`, `event_type`, `event_subtype`, `changed_fields`, `previous_value`, `new_value`, `as_of`, `evidence`, `summary`, `source_url`, `event_uid`, `reg_status`, `billable: true`.

#### RUN\_STATUS (never billed)

Every successful run pushes one health row (`FIXTURE_HEALTH` | `MONITOR_IDLE` | `CATCHUP_COMPLETE` | `HEALTH_OK`).

### Pricing

Pay-per-event: **`charity-status-event-delivered`** at **$0.02** per delivered unique change event ($20 / 1,000). Single tier (see `docs/monetization.md` and ADR 0010). Health / baseline / duplicate / fixture rows are never charged. `apify-actor-start` ~$0.00005.

### Local development

```bash
cd actors/uk-charity-commission-portfolio-status-monitor
npm install
npm test
npm run build
apify run -p
```

### Attribution

Data originates from the **Charity Commission for England and Wales** under the **Open Government Licence v3.0** (Register API / full-register extract). Not an official Charity Commission product. Not ComplyTrack / CharityIQ. Covers **England & Wales only**.

# Actor input Schema

## `charityNumbers` (type: `array`):

England & Wales charity registration numbers to monitor via official Register API and/or OGL extract. Digits (5–8); optional -suffix for linked charities (default main = 0). Scottish OSCR / NI CCNI numbers are out of scope. Invalid entries are skipped with no charge. Not a nationwide dump — only these charity#s are evaluated.

## `signalGroups` (type: `array`):

Which change groups to evaluate: status (Registered/Removed/gone), identity (main name), interim\_manager (API interim\_manager\_ind; OGL may not carry this flag). Default: all. Trustee PII is never included.

## `maxRunSeconds` (type: `integer`):

Wall-clock budget for the run. Large books may need longer budgets or chunked schedules. OGL extract download can take longer on first run.

## `maxEvents` (type: `integer`):

Stop after this many unique change events are delivered (does not include RUN\_STATUS).

## `resumeFromCheckpoint` (type: `boolean`):

If true, resume charity snapshots and seen event\_uids from the default Key-Value Store.

## `sourceMode` (type: `string`):

fixture = local/CI / Apify Store daily auto-test default (no network; emits RUN\_STATUS only unless emitFixtureDemoEvents=true). live = official Charity Commission Register API and/or OGL extract. Not HTML scrape; not ComplyTrack/CharityIQ.

## `emitFixtureDemoEvents` (type: `boolean`):

When sourceMode=fixture, if true push fabricated change events from local fixtures (unit/local demos only). Default false so Store daily auto-tests never emit fake charity events or charge charity-status-event-delivered. Production: leave false and use sourceMode=live.

## `liveBackend` (type: `string`):

api = per-id Register API (requires charityApiKey; supports interim\_manager). ogl = free OGL v3.0 daily full-register charity extract (no key; status/name). If unset: api when key present, else ogl.

## `charityApiKey` (type: `string`):

Subscription key from the free Charity Commission developer portal (api-portal.charitycommission.gov.uk). Required only when sourceMode=live and liveBackend=api. Marked secret; never logged. Not a ComplyTrack/CharityIQ key.

## `oglExtractUrl` (type: `string`):

Optional override for the official publicextract.charity.zip URL. Default is the Commission Azure blob daily extract under Open Government Licence v3.0.

## `asOfHint` (type: `string`):

Optional as\_of label for events / RUN\_STATUS. Does not force a bulk dump.

## `maxTotalChargeUsd` (type: `number`):

Optional soft budget hint for delivered change events. Platform ACTOR\_MAX\_TOTAL\_CHARGE\_USD also applies when set.

## `requestPaceMs` (type: `integer`):

Minimum delay between outbound Register API HTTP requests. Default 250 ms. Raise if you see 429s. Ignored for OGL single-download path.

## `includeTrustees` (type: `boolean`):

A5 legal default: OFF. This build does not emit trustee PII even if set true — product stays charity number + reg\_status + name + dates (+ optional interim\_manager).

## Actor input object example

```json
{
  "charityNumbers": [
    "202918",
    "220949"
  ],
  "signalGroups": [
    "status",
    "identity",
    "interim_manager"
  ],
  "maxRunSeconds": 55,
  "maxEvents": 500,
  "resumeFromCheckpoint": true,
  "sourceMode": "fixture",
  "emitFixtureDemoEvents": false,
  "requestPaceMs": 250,
  "includeTrustees": false
}
```

# Actor output Schema

## `OUTPUT` (type: `string`):

JSON summary: delivered, charged, runStatus, checkpoint, stats, England & Wales coverage limits

# 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("plym-actor-factory/uk-charity-commission-portfolio-status-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("plym-actor-factory/uk-charity-commission-portfolio-status-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 '{}' |
apify call plym-actor-factory/uk-charity-commission-portfolio-status-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,plym-actor-factory/uk-charity-commission-portfolio-status-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/JhoEJQDCuppWM6vuC/builds/guo4lwINBoO6cKl4f/openapi.json
