# EU NANDO Notified Body & CE Scope Finder (`kilipilot/eu-ce-notified-body-finder`) Actor

Unofficial EU NANDO/SMCS search tool to find notified bodies by legislation, country, status, number, name, scope, procedure, article, or product. Export structured CE-marking data with official profile links, notification details, and published conformity-assessment scope.

- **URL**: https://apify.com/kilipilot/eu-ce-notified-body-finder.md
- **Developed by:** [Kilian Pérez de Gracia](https://apify.com/kilipilot) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 verified notified bodies

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

## EU NANDO Notified Body & CE Scope Finder

Search the European Commission's live NANDO / Single Market Compliance Space and turn its published notified-body records into structured data. Filter by legislation, country, status, body name or number, article, conformity-assessment procedure, or product keywords, then export the matching organizations and their exact published scope.

Use this Actor to:

- find active bodies across the legislation options currently exposed by NANDO, not only MDR and IVDR;
- retrieve official organization profiles, contacts, notification details and source links;
- inspect normalized product, procedure, article/annex, condition and limitation fields;
- preserve NANDO's original headings and values in `rawCells` when legislation-specific tables differ;
- run the same research from Apify Console, the API, scheduled tasks or an MCP-compatible agent.

It is useful for regulatory-affairs and quality teams, manufacturers, laboratories, consultants, market-access researchers and developers building CE-marking workflows.

> **Unofficial independent tool.** This Actor is not affiliated with, endorsed by or operated by the European Commission, NANDO/SMCS, a notifying authority or any notified body. It accelerates research; it does not determine product compliance or body suitability. Always verify results against the linked official source.

It is designed to resolve legislation options currently exposed by NANDO, but the legislation list and table structures can change. The release check uses personal protective equipment (PPE); use a small test run before scaling a different legislation.

### Quick start

The default input retrieves up to three active PPE bodies, processes at most two matching notification pages per body and returns scope details:

```json
{}
```

Filter to Spain:

```json
{
  "legislation": "2016/425",
  "country": "Spain",
  "detailLevel": "scope",
  "maxResults": 3,
  "maxNotificationsPerBody": 2
}
```

The Apify Console opens with a deliberately lighter example input: one active PPE body in `list` mode. This keeps Store previews and automated quality checks fast and predictable. Increase the result limit and choose `organization` or `scope` when you need broader or richer results.

Start with a small run. Increase `maxResults` only after checking the first results and the run duration for your legislation.

### Pricing

- **$0.02 per saved notified-body record** through the `result-item` pay-per-event event.
- The default `maxResults` of 3 therefore creates at most **$0.06 in body-result charges**.
- An empty search, a body that cannot be saved and a source failure do not create a `result-item` charge.
- Apify displays current pricing and lets you set a maximum charge before the run. The Store pricing panel is authoritative if pricing changes.

The small automatic `apify-actor-start` event may also appear in the pricing panel. It is separate from body results and helps cover startup compute. Post-run storage or downloads can incur normal Apify platform costs under the user's plan and retention settings.

| Saved records | Body-result charge |
|---:|---:|
| 3 | $0.06 |
| 25 | $0.50 |
| 100 | $2.00 |

### Common use cases

- **Shortlist bodies:** find active PPE, RED, EMC, machinery, construction-product or other NANDO bodies for a country or product keyword.
- **Check a known body:** retrieve the current official profile, notifications and published scope for a body number such as `1239`.
- **Review procedures:** search for scope rows mentioning EU type-examination, production-quality assurance or another conformity-assessment route.
- **Build a CE data workflow:** feed structured NANDO records and source links into an internal tool, spreadsheet pipeline, scheduled check or AI agent.
- **Preserve evidence trails:** retain retrieval time, official links, original NANDO cells and explicit completeness metadata with every result.

### API and agent use

Run synchronously and return dataset items with the Apify API:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/kilipilot~eu-ce-notified-body-finder/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"legislation":"2016/425","country":"Spain","maxResults":3}'
```

The Actor's **API** tab provides ready-made Python, JavaScript, CLI, OpenAPI, HTTP and MCP integration examples. Example requests for an MCP-compatible agent include:

- `Find up to three active PPE notified bodies in Spain and include their official scope.`
- `Retrieve the official NANDO profile and published notification scope for body 1239.`
- `Find active bodies whose published scope mentions EU type-examination under Regulation (EU) 2016/425.`

### What each result can contain

Depending on `detailLevel`, a saved body record can include:

- body type, body number, organization name and country;
- the official organization profile URL;
- published address, phone, fax, email and website;
- body version and organization approval date;
- all notification rows listed on the organization's profile, including legislation, dates and official links;
- processed scope sections with their original NANDO columns and rows;
- normalized product, procedure/module, article/annex, condition and limitation fields when those columns can be recognized;
- explicit notification-processing counts and truncation metadata;
- source attribution and retrieval time.

Different legislation can publish different scope columns. `rawCells` preserves those original headings and values even when a field does not fit the normalized convenience fields.

### Inputs

| Field | Meaning |
|---|---|
| `notificationStatus` | NANDO notification status. Defaults to `Active`. |
| `legislation` | Full or partial current NANDO label or identifier. Examples: `2016/425`, `PPE`, `2024/2847`, `Cyber Resilience Act`. Explicitly set `""` to search all legislation. |
| `bodyNumber` | Optional body number. |
| `bodyName` | Optional full or partial organization name. |
| `country` | Optional case- and accent-insensitive partial match against the Country column, for example `Spain` or `ital`. |
| `articleAnnex` | Optional article or annex wording used by NANDO. |
| `procedure` | Optional conformity-assessment procedure wording. |
| `products` | Optional product or competence keywords. |
| `detailLevel` | `list`, `organization` or `scope`. Defaults to `scope`. |
| `maxResults` | Maximum saved bodies, from 1 to 100. Defaults to 3. |
| `maxNotificationsPerBody` | Maximum matching notification pages processed per body in scope mode, from 1 to 50. Defaults to 2. |
| `maxRunSeconds` | Safety budget for source-page work, from 60 to 240 seconds. Defaults to 240. The Actor also honors Apify's `ACTOR_TIMEOUT_AT` deadline and reserves up to 60 seconds for browser cleanup and `RUN_SUMMARY`. |

Legislation text is resolved against the live NANDO selection list. If text matches more than one option, the run reports candidate labels instead of guessing.

### Detail levels

| Level | Behavior |
|---|---|
| `list` | Returns compact body rows from the official search results. Fastest. |
| `organization` | Opens each body profile and adds published contacts and notification links. |
| `scope` | Also processes matching notification detail pages, up to `maxNotificationsPerBody`, and extracts their published scope tables. |

`list` and `organization` deliberately do not retrieve notification scope. Their records are useful for discovery and contact workflows, not as full-scope exports.

### Completeness and truncation

Each body record includes:

- `detailLevel`: the requested depth: `list`, `organization` or `scope`;
- `notificationListComplete`: true only when the organization profile and its notification list were actually read;
- `totalNotificationsFound`: notification rows found on the organization profile (use only when `notificationListComplete` is true);
- `matchingNotificationsFound`: notification links matching the selected legislation;
- `notificationsProcessed`: matching notification detail pages actually opened in scope mode;
- `notificationsSkipped`: matching pages omitted because a safety limit was reached;
- `scopeStatus`: `not_requested`, `complete` or `truncated`;
- `scopeComplete`: true only when scope mode processed every matching notification;
- `truncationReason`: empty when complete or not applicable, otherwise `maxNotificationsPerBody` or `maxRunSeconds`.

`list` and `organization` records now report `scopeComplete: false` and `scopeStatus: "not_requested"`; they never imply that unrequested scope work was complete. A body-level error cannot be saved or charged as a result. Check `RUN_SUMMARY` for run-level failures, spending-limit stops and time-budget stops.

When `legislation` is blank, scope mode can encounter many notifications per body. Increase `maxNotificationsPerBody` only if you need them and review `notificationsSkipped` after the run.

### Output

The default dataset contains one record per saved body. Before a row can be saved or charged, its body number, name, country and official European Commission profile URL are validated. The default key-value store contains `RUN_SUMMARY`, with the resolved legislation, country filter, reported and discovered counts, saved and failed bodies, spending-limit status, time-budget status, errors and completion time.

Example body record (shortened):

```json
{
  "bodyType": "NB",
  "bodyNumber": "1239",
  "bodyName": "CERTINALIA, S.L.U.",
  "country": "Spain",
  "matchedLegislation": "Regulation (EU) 2016/425 Personal protective equipment",
  "profileUrl": "https://webgate.ec.europa.eu/...",
  "notifications": [
    {
      "legislation": "Regulation (EU) 2016/425 Personal protective equipment",
      "lastApprovalDate": "29/03/2023",
      "endDate": "14/03/2028",
      "detailUrl": "https://webgate.ec.europa.eu/...",
      "officialPdfUrl": "https://api.tech.ec.europa.eu/...",
      "notifiedItems": [
        {
          "product": "Equipment providing general body protection (clothing)",
          "procedures": ["EU type-examination"],
          "articlesAnnexes": ["Annex V"],
          "conditions": [],
          "limitations": [],
          "rawCells": {
            "Product": ["Equipment providing general body protection (clothing)"],
            "Procedures": ["EU type-examination"],
            "Articles/Annexes": ["Annex V"]
          }
        }
      ]
    }
  ],
  "totalNotificationsFound": 4,
  "matchingNotificationsFound": 2,
  "notificationsProcessed": 2,
  "notificationsSkipped": 0,
  "scopeItemCount": 8,
  "scopeComplete": true,
  "truncationReason": "",
  "source": "European Commission NANDO / Single Market Compliance Space",
  "fetchedAt": "2026-08-24T16:00:00.000Z"
}
```

#### Export format

**JSON is the richest and recommended output** because `notifications`, `scopeSections`, `notifiedItems` and legislation-specific `rawCells` are nested. CSV and Excel exports are useful for the top-level body overview but can serialize nested values into cells; they are not a lossless flat scope-item table.

### Limitations

- NANDO/SMCS is a client-rendered external source. Changes, outages or throttling can make a run fail or require an Actor update.
- The Actor returns what the public interface exposes at retrieval time. It does not replace the official record, attached PDF or direct confirmation from the body.
- Scope normalization is best effort. Legislation-specific columns remain available in `rawCells`.
- A zero `scopeItemCount` can be a valid published result; inspect the official notification link and completeness fields before interpreting it.
- `maxResults` limits saved bodies, and `maxNotificationsPerBody` can deliberately truncate matching scope pages.
- Larger scope runs take longer than list or organization runs. Runtime depends on source response time and the number of notification pages. The Actor stops new page work at the earlier of `maxRunSeconds` or Apify's runtime deadline (with a cleanup margin), then preserves already verified results plus a final summary.
- Numbers such as body identifiers remain strings to preserve leading zeroes.

If the official search reports results but the Actor cannot parse a consistent body set, or if no discovered body can be saved, the run fails rather than presenting a misleading successful empty result.

### Privacy and data handling

- The Actor visits only public European Commission NANDO/SMCS pages and their linked official files. It does not log in to NANDO or bypass access controls.
- Input should contain search filters only. Do not enter passwords, API tokens, personal case files, confidential product information or other secrets.
- Results can include public business contact details published by NANDO. Use them lawfully and respect applicable privacy, marketing and communications rules.
- Input, datasets, logs and `RUN_SUMMARY` are stored in the user's Apify account according to Apify's platform, plan and retention settings. Delete runs or storage records when they are no longer needed.
- The Actor does not intentionally persist browser cookies or create an external customer database controlled by the Actor author.

### Responsible use

A returned match does **not** establish that a body is suitable for a specific product, that notified-body involvement is required, that a conformity-assessment route is correct, or that a product complies with EU law. Scope wording can contain exclusions, conditions and limitations that require professional interpretation.

Open the supplied official links, review the current notification and PDF, confirm suitability directly with the body, and obtain qualified regulatory advice where appropriate. This Actor does not provide legal, certification, classification, conformity-assessment or market-access advice.

### FAQ

#### Is this an official European Commission tool?

No. It is an independent data-extraction tool that links every result back to the public European Commission source.

#### Why did I receive fewer bodies than NANDO's reported result count?

`maxResults` limits saved bodies. A country filter can also exclude search rows. Check `RUN_SUMMARY` for reported, discovered, saved and failed counts.

#### Why does a result contain more notifications than `notificationsProcessed`?

The `notifications` array preserves the notification list published on the organization's profile. Only notification pages matching the selected legislation and within the processing cap are enriched with full scope details.

#### Why is `scopeComplete` false?

Check `scopeStatus`. `not_requested` means you selected list or organization mode, so no scope pages were opened. `truncated` means `maxNotificationsPerBody` or `maxRunSeconds` stopped some scope work; narrow the search or adjust the relevant limit and rerun.

#### Why is the dataset empty?

The current official search may contain no match for the filters. Empty searches do not create body-result charges. If NANDO reported results but extraction could not safely read them, the run should fail and explain the issue in the log or `RUN_SUMMARY`.

#### Can I treat the result as proof of certification coverage?

No. Treat it as a research lead. The official current NANDO notification, its PDF, exclusions and confirmation from the body take precedence.

# Actor input Schema

## `notificationStatus` (type: `string`):

Status of the notified-body record.

## `legislation` (type: `string`):

A full or partial NANDO legislation label. Leave empty to search all legislation. Examples: 2024/2847, Cyber Resilience Act, 2023/1542, batteries, 2016/425, PPE, 2014/53/EU, radio equipment.

## `bodyNumber` (type: `string`):

Optional four-digit notified body number.

## `bodyName` (type: `string`):

Optional full or partial organization name.

## `country` (type: `string`):

Optional case- and accent-insensitive partial match against the Country column, for example Spain, Italy or Germany.

## `articleAnnex` (type: `string`):

Optional article or annex filter exactly as used in NANDO.

## `procedure` (type: `string`):

Optional procedure filter, for example EU type-examination.

## `products` (type: `string`):

Optional product/scope keywords.

## `detailLevel` (type: `string`):

List returns one compact row per body. Organization adds contact details and notification links. Scope also opens matching notification pages and exports notified products, procedures and annexes.

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

Maximum number of body records to save. At $0.02 per saved body, the default of 3 creates at most $0.06 in body-result charges. Check the Store pricing panel for the separate small start event and current terms.

## `maxNotificationsPerBody` (type: `integer`):

Safety limit for matching notification pages opened for each organization in full-scope mode. If the limit is reached, completeness fields and warnings mark the result as truncated.

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

Safety budget for source-page work. The Actor stops before Apify's five-minute default timeout and may return explicitly marked partial results instead of being terminated without a final summary.

## Actor input object example

```json
{
  "notificationStatus": "Active",
  "legislation": "Regulation (EU) 2016/425 Personal protective equipment",
  "detailLevel": "list",
  "maxResults": 1,
  "maxNotificationsPerBody": 1,
  "maxRunSeconds": 240
}
```

# Actor output Schema

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

One JSON record per saved notified body. JSON is the richest format because notifications and scope rows are nested.

## `runSummary` (type: `string`):

Run-level result counts, completeness information, spending-limit status, warnings and per-body failures.

# 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 = {
    "notificationStatus": "Active",
    "legislation": "Regulation (EU) 2016/425 Personal protective equipment",
    "detailLevel": "list",
    "maxResults": 1,
    "maxNotificationsPerBody": 1,
    "maxRunSeconds": 240
};

// Run the Actor and wait for it to finish
const run = await client.actor("kilipilot/eu-ce-notified-body-finder").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 = {
    "notificationStatus": "Active",
    "legislation": "Regulation (EU) 2016/425 Personal protective equipment",
    "detailLevel": "list",
    "maxResults": 1,
    "maxNotificationsPerBody": 1,
    "maxRunSeconds": 240,
}

# Run the Actor and wait for it to finish
run = client.actor("kilipilot/eu-ce-notified-body-finder").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 '{
  "notificationStatus": "Active",
  "legislation": "Regulation (EU) 2016/425 Personal protective equipment",
  "detailLevel": "list",
  "maxResults": 1,
  "maxNotificationsPerBody": 1,
  "maxRunSeconds": 240
}' |
apify call kilipilot/eu-ce-notified-body-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kilipilot/eu-ce-notified-body-finder"
        }
    }
}

```

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/i2SxrIUlkHidDOGUc/builds/jx5ycKxNI3zW5U3pg/openapi.json
