# Company Data Scraper - Ownership & LEI (`datalayer/corporate-ownership-lei`) Actor

GLEIF is the only free official source for who owns whom: direct and ultimate parents across 2.5M+ entities in 100+ jurisdictions. It also shows whether an entity still renews its LEI — 1,190,660 sit at LAPSED. A different question from whether the company is active, and the two often disagree.

- **URL**: https://apify.com/datalayer/corporate-ownership-lei.md
- **Developed by:** [Datalayer](https://apify.com/datalayer) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 entities

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/platform/actors/running/actors-in-store#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

## Company Ownership Scraper — LEI Parents & Subsidiaries

Scrape **official legal entity data** from GLEIF: 2.5M+ companies across 100+
jurisdictions, with legal names, registered addresses, company numbers — and the
two fields a KYC or supplier-risk team cannot get free anywhere else.

### 1. Who owns whom

GLEIF is the only free, global, official source that publishes **direct and
ultimate parent relationships** between legal entities, with the accounting
periods they were reported for.

Deutsche Bank AG alone has **330 direct subsidiaries** on file (measured
2026-08-14). A live run against the first five returned entities in **Spain,
Hong Kong, Mauritius and the United States** — a group footprint you would
otherwise assemble by hand from five national registries.

You can also work top-down: pass a parent LEI to `ownedBy` and get its
subsidiaries directly.

### 2. Whether the entity still maintains its identity

An LEI must be **renewed annually** against an authoritative source.
**1,190,660 records currently sit at registration status LAPSED** (measured
2026-08-14) — meaning the entity stopped revalidating.

This is not the same question as whether the company is active, and the two
frequently disagree. A live search for *Deutsche Bank* returned, in the first 20
records, a Swiss pension foundation that is **`entityStatus: ACTIVE` but
`registrationStatus: LAPSED`**, plus **6 entities with an overdue renewal date**.
Read only `entity.status` and every one of those looks clean.

Both fields are returned, plus `isLapsed`, `isRenewalOverdue`,
`daysUntilRenewal` and `isActive` (the only combination that means fully
current: entity ACTIVE *and* registration ISSUED).

### What else you get

- **`corroborationLevel`** — how well evidenced the record is.
  `FULLY_CORROBORATED` means validated against a public registry;
  `ENTITY_SUPPLIED_ONLY` means the company simply said so. Materially different
  levels of trust, and it is right there in the data.
- **`registeredAs` + `registrationAuthority`** — the company number in its home
  registry and which registry that is. This is the join key from GLEIF to
  national company data.
- **`isCrossBorderHq`** — the headquarters sits in a different country to the
  registered address. Not wrongdoing, but exactly what a jurisdiction-risk check
  looks for.
- **Group summaries** — parent chain, subsidiary count, jurisdictions spanned,
  and how many group members have a lapsed LEI.
- **LEI is a stable key.** It survives name changes, which is why matching on it
  beats matching on a company name.

### Who uses this

- **KYC, AML and onboarding** — resolving a counterparty to an official
  identifier and checking whether it still maintains it.
- **Supplier and third-party risk** — mapping a supplier's ownership before
  signing, and spotting groups spanning unexpected jurisdictions.
- **B2B data enrichment** — attaching a global, stable identifier and a home
  registry number to a CRM record.
- **Financial research** — mapping fund and subsidiary structures.

### Input

Give at least one of `searchTerm`, `leis`, `country` or `ownedBy`. An unfiltered
walk across 2.5 million records is refused rather than started.

| Field | Type | Default | Notes |
|---|---|---|---|
| `searchTerm` | string | `Deutsche Bank` | Full-text across legal and other names |
| `leis` | array | `[]` | Exact 20-character LEIs, looked up directly |
| `country` | string | `""` | Two-letter country of the registered address |
| `ownedBy` | string | `""` | Parent LEI — map a group from the top down |
| `entityStatus` | string | `""` | Is the **company** active |
| `registrationStatus` | string | `""` | Is the **LEI** maintained — a different question |
| `lapsedOnly` | boolean | `false` | Keep only lapsed registrations |
| `includeRelationships` | boolean | `true` | Direct and ultimate parents |
| `includeChildren` | boolean | `false` | Off by default — large groups have hundreds |
| `maxChildrenPerEntity` | integer | `50` | |
| `maxEntities` | integer | `100` | 200 per page |

`lapsedOnly` narrows the **entity rows only**. Group summaries are built from
everything, or a group would look entirely lapsed by construction.

### Output

**`entity`** — `lei`, `legalName`, `otherNames`, `entityStatus`,
`registrationStatus`, `isLapsed`, `isRenewalOverdue`, `daysUntilRenewal`,
`corroborationLevel`, `jurisdiction`, `legalAddress`, `headquartersAddress`,
`isCrossBorderHq`, `registeredAs`, `registrationAuthority`, `bic`, `gleifUrl`.

**`relationship`** — `relationship` (direct\_parent, ultimate\_parent,
direct\_child), `relatedLei`, `relatedLegalName`, `relatedCountry`,
`relatedEntityStatus`, `relatedIsLapsed`.

**`group_summary`** — `directParentName`, `ultimateParentName`,
`hasReportedParent`, `isUltimateParentItself`, `directChildren`,
`childCountries`, `jurisdictionsInGroup`, `lapsedRelatedEntities`,
`lapsedSharePercent`.

### Limits

- **Most entities report no parent, and that is normal.** GLEIF answers those
  with a 404, which this actor records as `hasReportedParent: false` rather than
  treating as an error. Absence of a parent is not evidence of independence —
  it means none was reported.
- Coverage is strong for financial institutions and regulated entities, thinner
  for small private companies that have never needed an LEI.
- Ownership is **legal consolidation**, not beneficial ownership. It answers who
  consolidates the accounts, not who ultimately benefits.

### Pricing

Pay per event. $0.001 per entity, $0.002 per ownership relationship, $0.05 per
group summary.

# Actor input Schema

## `searchTerm` (type: `string`):

Full-text search across legal names and other names, e.g. Deutsche Bank. Give at least one of this, an LEI, a country or an owner LEI.

## `leis` (type: `array`):

Exact 20-character Legal Entity Identifiers, e.g. 7LTWFZYICNSX8D621K86. Looked up directly rather than searched.

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

Two-letter country of the registered legal address, e.g. DE, GB, AU.

## `ownedBy` (type: `string`):

Return the entities owned by this LEI. The fastest way to map a group from the top down.

## `entityStatus` (type: `string`):

Whether the company itself is active.

## `registrationStatus` (type: `string`):

A different question from entity status: is the LEI still being renewed? LAPSED means the entity stopped revalidating its identity.

## `lapsedOnly` (type: `boolean`):

Keep only entities whose LEI has lapsed. Group summaries are still built from everything.

## `includeEntities` (type: `boolean`):

Return one row per legal entity. Turn off to get only ownership and group summaries.

## `includeRelationships` (type: `boolean`):

Look up direct and ultimate parents for every entity. Most entities report none, which GLEIF returns as a 404 and this actor records as "no parent reported".

## `includeChildren` (type: `boolean`):

Also fetch direct children. Off by default because large groups have hundreds — Deutsche Bank AG alone has 330.

## `includeGroupSummary` (type: `boolean`):

Per entity: parent chain, subsidiary count, jurisdictions spanned and how many group members have lapsed.

## `maxEntities` (type: `integer`):

GLEIF serves 200 per page.

## `maxChildrenPerEntity` (type: `integer`):

Cap on subsidiaries fetched per entity. Deutsche Bank AG alone has 330 direct children.

## `proxyConfiguration` (type: `object`):

Optional. GLEIF is a public API and does not require a proxy.

## Actor input object example

```json
{
  "searchTerm": "Deutsche Bank",
  "leis": [],
  "country": "",
  "ownedBy": "",
  "entityStatus": "",
  "registrationStatus": "",
  "lapsedOnly": false,
  "includeEntities": true,
  "includeRelationships": true,
  "includeChildren": false,
  "includeGroupSummary": true,
  "maxEntities": 100,
  "maxChildrenPerEntity": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `entities` (type: `string`):

Legal entities with addresses, jurisdiction and LEI registration health.

## `relationships` (type: `string`):

Direct parents, ultimate parents and subsidiaries.

## `groups` (type: `string`):

Per entity: parent chain, subsidiary count, jurisdictions spanned and lapsed members.

## `csv` (type: `string`):

Everything as a CSV download.

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

Counts, lapsed registrations, and any LEI that could not be read.

# 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 = {
    "searchTerm": "Deutsche Bank",
    "maxEntities": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("datalayer/corporate-ownership-lei").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 = {
    "searchTerm": "Deutsche Bank",
    "maxEntities": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("datalayer/corporate-ownership-lei").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 '{
  "searchTerm": "Deutsche Bank",
  "maxEntities": 100
}' |
apify call datalayer/corporate-ownership-lei --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datalayer/corporate-ownership-lei"
        }
    }
}

```

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/tFwGSUobJtMTjwIbi/builds/7nb94XTDrO9BhS279/openapi.json
