# EU Transparency Register Monitor - Lobbying Change Feed (`datadeltas/eu-transparency-register`) Actor

Scheduled change feed for the EU Transparency Register: new lobbying registrations, deregistrations and amended declarations since your last run - with the exact fields that changed.

- **URL**: https://apify.com/datadeltas/eu-transparency-register.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 $10.50 / 1,000 register 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.
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

## EU Transparency Register Monitor — lobbying registration change feed

**What moved in the EU lobbying register since you last looked.** Every run
downloads the European Commission / European Parliament **official
open-data export** of the EU Transparency Register (17,700+ registered
organisations, re-exported daily at 20:00 UTC), diffs it against your
previous run, and pushes one record per change:

| Change type | What it means |
|---|---|
| `new-registration` | An organisation joined the register |
| `deregistered` | An organisation left the register |
| `amended` | A registrant edited its declaration — **with the exact list of fields that changed** |

No API key, no login, no scraping of the search UI: this reads the register's
own published dataset. Other tools tell you who is on the register *now*.
This one tells you **what changed**.

### Example output

One real record (a professional consultancy, trimmed for readability):

```json
{
  "source": "eu-transparency-register",
  "registrationNumber": "32689998126-75",
  "changeType": "amended",
  "name": "Bernstein Public Policy",
  "category": "Professional consultancies",
  "country": "GERMANY",
  "fieldsOfInterest": [
    "Banking and financial services",
    "Digital economy and society",
    "Energy",
    "Public health",
    "Taxation"
  ],
  "changedFields": ["clients", "declaredBudgetMax", "epAccreditedNumber"],
  "registrationDate": "2012-02-21",
  "acronym": null,
  "website": "bernstein-group.com",
  "levelsOfInterest": ["european", "national", "sub-national"],
  "interestRepresented": "Advances interests of their clients",
  "lobbyistsFte": 2.2,
  "epAccreditedNumber": 2,
  "lobbyingCostsMin": null,
  "lobbyingCostsMax": null,
  "declaredBudgetMin": 60000,
  "declaredBudgetMax": 199999,
  "declaredBudgetBasis": "annual-revenue",
  "lastUpdateDate": "2026-03-12T15:19:55.610+00:00",
  "url": "https://transparency-register.europa.eu/search-details_en?id=32689998126-75",
  "detectedAt": "2026-08-31T10:52:04Z"
}
```

#### Field notes

- `registrationNumber` is the register's own identification number — stable
  and permanent, so it joins cleanly to your CRM or existing datasets.
- `changedFields` (on `amended` rows only) names any of: `name`, `nameLatin`,
  `acronym`, `entityForm`, `website`, `category`, `country`, `city`,
  `euOfficeCountry`, `levelsOfInterest`, `fieldsOfInterest`,
  `interestRepresented`, `epAccreditedNumber`, `lobbyists`, `lobbyistsFte`,
  `lobbyingCostsMin`, `lobbyingCostsMax`, `declaredBudgetMin`,
  `declaredBudgetMax`, `declaredBudgetBasis`, `financialYearEnd`, `clients`,
  `intermediaries`, `goals`, `euLegislativeProposals`,
  `communicationActivities`.
- **Money fields follow the register's own declaration model.** Registrants
  declaring a *lobbying cost band* fill `lobbyingCostsMin`/`Max` (EUR, band
  edges; `Min` is `null` for the lowest band). Consultancies and law firms
  instead declare annual revenue from EU representation, and
  NGOs / think tanks a total budget — those land in
  `declaredBudgetMin`/`Max` with `declaredBudgetBasis` telling you which
  (`annual-revenue` or `total-budget`). They are different quantities and are
  never mixed.
- `lobbyistsFte` is declared full-time-equivalent lobbyists;
  `epAccreditedNumber` is the count of European Parliament access badges.
- On `deregistered` rows the current-declaration fields (`website`,
  `lobbyistsFte`, cost/budget figures, `lastUpdateDate`, …) are `null`: the
  organisation is no longer in the export, so only `name`, `category`,
  `country`, `fieldsOfInterest` and `registrationDate` can be reported.
- No contact details. The export publishes phone numbers and street
  addresses; this actor deliberately does not carry them.

### Input options

| Input | Type | Default | What it does |
|---|---|---|---|
| `changeTypes` | array | all three | Emit only `new-registration`, `deregistered` and/or `amended` |
| `categories` | array | all | Filter by register section (the register's own 13 categories, e.g. `Professional consultancies`, `Companies & groups`, `Law firms`) |
| `countries` | array | all | Head-office country as published, e.g. `BELGIUM`, `GERMANY`, `UNITED STATES` (case-insensitive) |
| `keywords` | array | none | Case-insensitive substring match on organisation name and acronym |
| `emitInitialSnapshot` | boolean | `false` | See below |
| `maxItems` | integer | `1000` | Safety cap on records emitted per run |

Filters apply when records are emitted; the stored baseline always covers the
**whole** register, so narrowing or widening a filter later never fabricates a
registration or resurrects a deregistration.

### The first run seeds a baseline

The first run stores the whole register and **emits nothing** — you are never
billed for 17,700 "changes" that are just the existing register. From the
second run on, an empty dataset means nothing moved: that is a successful,
quiet run.

Want an initial full load? Set `emitInitialSnapshot: true` and every current
registrant is emitted once as a `new-registration` (your filters and
`maxItems` still apply).

**Recommended schedule: daily.** The register re-exports at 20:00 UTC, so a
run any time after that picks up the new edition. Give the run a **timeout of
at least 900 seconds and 1024 MB memory** — the export is a ~115 MB download.

### Use cases

1. **"Tell me the moment a new lobbyist registers on my client's file."**
   Set `keywords` to your client's issue-owning companies and `categories` to
   `Professional consultancies` + `Law firms`, schedule daily, and get an
   alert when a new consultancy registers or adds a client — the `clients`
   field lands in `changedFields`.
2. **"Which organisations quietly increased their declared EU lobbying
   spend?"** Filter `changeTypes` to `amended` and watch for
   `lobbyingCostsMax`, `declaredBudgetMax` and `lobbyistsFte` in
   `changedFields` — a ready-made story or benchmark, with the before/after
   visible across consecutive runs.
3. **"Who is newly lobbying on my file?"** Filter nothing but
   `changeTypes: ["new-registration"]` and screen the `fieldsOfInterest`
   array for your policy area (e.g. `Digital economy and society`,
   `Public health`) — the weekly intake list of new entrants to your dossier.
4. **Counterparty and grant-eligibility screening.** Join
   `registrationNumber` to your vendor list and get notified when a
   counterparty registers, deregisters, changes register category, or loses
   its EP accreditations.

### Reliability

- **Keyless and first-party**: the register's own open-data export, not the
  search UI. No proxies, no browser, no rate limits to trip over.
- **A broken download can never look like a quiet day, or a mass
  deregistration.** Every run cross-checks the export's own declared
  registrant count against what was parsed, refuses a suspiciously shrunken
  export, and fails loudly while keeping the stored baseline untouched.
- **Robust against the export's quirks.** The register publishes XML 1.1
  containing control characters that off-the-shelf XML parsers reject
  outright — this actor neutralises them in-stream, so one registrant's
  stray paste never costs you a day's feed.
- **Cosmetic noise never bills you.** Whitespace, list ordering, and the
  register's own `lastUpdateDate` stamp are normalised out — only substantive
  edits emit an `amended` record.
- Each change emits **exactly once**.

### Pricing (pay per event)

| Event | Price (USD) |
|---|---|
| Actor start | $0.005 per run |
| Register change detected | $0.015 per emitted record |

### Maintenance

Export URL, element names and the register's category / fields-of-interest
vocabularies are checked against the live export monthly; a schema change is
logged as a clear warning rather than crashing a run.

### Changelog

- **0.1.1** — Reliability: a permanent HTTP error from the register's export
  endpoint (for example a moved path) now fails the run immediately instead of
  retrying a status that cannot succeed, so the failure is reported sooner.
  No change to records, filters, state or pricing.
- **0.1** — First release. Daily delta over the official full-register XML
  export: new registrations, deregistrations and amended declarations with
  per-field change lists, declared lobbying costs / budgets / FTEs, EP
  accreditation counts, and category / country / keyword filters.

# Actor input Schema

## `changeTypes` (type: `array`):

Which kinds of register change to push to the dataset. Default: all three. 'Amended' carries the list of fields that moved, so declaration updates (lobbying costs, FTEs, clients, fields of interest) are never silently dropped.

## `categories` (type: `array`):

Optional filter on the registrant's register section, using the register's own wording. Leave empty for every section.

## `countries` (type: `array`):

Optional case-insensitive match on the registrant's head-office country as published by the register, e.g. "BELGIUM", "GERMANY", "UNITED STATES". Non-EU countries appear too. Leave empty for all countries.

## `keywords` (type: `array`):

Optional case-insensitive substring match on the organisation's registered name and acronym, e.g. "Bayer", "Greenpeace", "Kreab". A change is emitted when any keyword matches. Leave empty to monitor the whole register.

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

OFF by default: the first run stores a baseline of the register and emits NOTHING, so you are never billed for thousands of 'changes' that are just the existing register. Turn ON only if you want an initial full load - every current registrant is then emitted as a new-registration record (subject to your filters and maxItems).

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

Hard cap on change records emitted in one run (keeps test runs cheap). The baseline still updates in full, so capped changes are not re-emitted later.

## Actor input object example

```json
{
  "changeTypes": [
    "new-registration",
    "deregistered",
    "amended"
  ],
  "categories": [],
  "countries": [],
  "keywords": [],
  "emitInitialSnapshot": false,
  "maxItems": 1000
}
```

# 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 = {
    "categories": [],
    "countries": [],
    "keywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("datadeltas/eu-transparency-register").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 = {
    "categories": [],
    "countries": [],
    "keywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("datadeltas/eu-transparency-register").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 '{
  "categories": [],
  "countries": [],
  "keywords": []
}' |
apify call datadeltas/eu-transparency-register --silent --output-dataset

```

## MCP server setup

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

```

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/AmMHJ8wtjjqed05Og/builds/A5ZeCkxgs8F7txcQY/openapi.json
