# Website Legal Entity Extractor: CIF, VAT & Audit (`rastriq/legal-entity-extractor`) Actor

Find the company behind any website: CIF/NIF, EU VAT ID and legal name, plus cookie-consent, security, SEO and social-profile audit in one run.

- **URL**: https://apify.com/rastriq/legal-entity-extractor.md
- **Developed by:** [Rastriq — Structured data from the world](https://apify.com/rastriq) (community)
- **Categories:** Lead generation, SEO 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 results

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?

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

## Website Legal Entity Extractor: CIF, VAT ID, Company Name & Compliance Audit

Find the **company behind any website**: tax ID (Spanish CIF/NIF/NIE or EU VAT number), registered company name and country, taken from the site's own footer, privacy policy and legal notice (*aviso legal*). In the same run it audits the page's **cookie consent behaviour, security headers, tech stack, SEO snapshot and social profiles**.

No registry API keys needed. Give it a URL, get one structured record per audited page.

### Why use this Actor

- **Legal entity + audit in one record.** Other Store Actors extract either contact details, a VAT validation, an SEO report or a security scan. This one returns the legal entity and the audit together, so you do not chain four Actors.
- **Looks where the data really is.** Checks the current page, then the linked privacy policy, then the legal notice, and tells you which one the ID came from (`source`, `sourceUrl`).
- **Real consent test.** Loads the page in separate browser contexts (no interaction, reject all, accept all) and compares which trackers fire before and after consent.
- **Pay per audited page.** Failed or blocked pages are not billed.

### Use cases

- **B2B lead enrichment**: attach CIF/VAT and legal name to a list of domains.
- **KYC / vendor onboarding**: pre-fill tax IDs from company websites before checking them in an official registry.
- **GDPR and cookie compliance audits**: find trackers that load before consent and banners where "reject" does not work.
- **Agencies and consultants**: audit client or prospect sites (security headers, SEO tags, tech stack) at scale.
- **Competitive intelligence**: map brands to the legal entities that operate them.

### How to use

1. Open the Actor and paste one or more website URLs.
2. Leave **Max pages per site** at `1` for a fast, cheap run (default).
3. Optional: choose which consent states to test, and set a proxy country close to your audience.
4. Click **Start**. Results appear in the dataset (Overview table: site, CIF/VAT, company name, score).
5. Export as JSON, CSV or Excel, or call the Actor through the API, Make, Zapier, n8n or MCP.

### Input example

```json
{
  "startUrls": [{ "url": "https://www.example.es" }],
  "maxPagesPerSite": 1,
  "consentStates": ["baseline", "reject", "accept"],
  "locales": ["es-ES"],
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyCountry": "US" }
}
```

Tip: `"consentStates": ["baseline"]` runs about 3x faster if you mostly want the legal entity.

### Output example

```json
{
  "hostname": "www.example.es",
  "requestUrl": "https://www.example.es",
  "auditedStates": 3,
  "legalEntity": {
    "cif": "B12345678",
    "companyName": "EXAMPLE RETAIL S.L.",
    "country": "ES",
    "source": "legal_notice",
    "sourceUrl": "https://www.example.es/aviso-legal"
  },
  "technologies": ["Google Tag Manager", "Google Analytics", "OneTrust"],
  "trackingIds": 4,
  "preConsentViolations": ["Google Analytics"],
  "complianceScore": { "score": 70, "grade": "B", "breakdown": { "preConsentViolations": -10, "securityHeaders": -20, "rejectFailed": 0 } },
  "darkPatternScore": { "score": 30, "flags": ["reject_button_smaller"] },
  "securityHeaders": { "score": 40, "maxScore": 100, "grade": "C", "findings": [] },
  "socialProfiles": [{ "platform": "instagram", "source": "own_media", "type": "profile_link", "profileId": "example" }]
}
```

Values above are illustrative. `legalEntity` fields are `null` when the site does not publish a tax ID.

### Output fields

| Field | Description |
|-------|-------------|
| `hostname`, `requestUrl`, `siteId` | Audited site and page |
| `legalEntity.cif` | CIF / NIF / NIE or EU VAT ID, normalized |
| `legalEntity.companyName` | Company name found near the tax ID |
| `legalEntity.country` | Country code derived from the ID format |
| `legalEntity.source` / `sourceUrl` | `current_page`, `privacy_policy` or `legal_notice`, and its URL |
| `auditedStates` | Number of consent states tested |
| `technologies`, `trackingIds` | Detected technologies and number of tracking IDs |
| `preConsentViolations` | Analytics/advertising/session-replay technologies active before consent |
| `complianceScore` | Score 0-100, grade A-F and penalty breakdown |
| `darkPatternScore` | Banner manipulation score and flags (null if no banner) |
| `securityHeaders` | Security header score, grade and findings |
| `performance` | Core Web Vitals, requests and transfer size (baseline state) |
| `socialProfiles` | Social profile links and ad pixel IDs found on the page |
| `deltaMatrix`, `states` | Per-technology and per-state comparison across consent states |

### Supported tax IDs

Spain (CIF, NIF, NIE) plus VAT formats for FR, DE, IT, PT, NL, PL, BE, AT, IE, SE, DK, FI, RO and GB. Matching is pattern-based: IDs next to labels such as "CIF", "NIF", "VAT" or "identificación fiscal" are preferred; bare matches are lower confidence. Format is checked, but the ID is **not** validated against VIES or a registry.

### Pricing

Pay per event: one result is billed for each audited page that returns data. Your Apify plan tier sets the price.

| Plan | Price per 1,000 pages |
|------|-----------------------|
| Free | $35 |
| Bronze | $30 |
| Silver | $25 |
| Gold | $20 |

Example: 200 sites at 1 page each on the Free plan costs about $7. Set a maximum cost per run in the run options; the Actor stops cleanly when it is reached. Platform usage (compute, proxy) is included in the per-result price.

### FAQ

**Is it legal?** The Actor reads publicly available pages, the same ones a visitor sees, and respects `robots.txt` by default. Company tax IDs are business data, but you are responsible for complying with the website's terms and with GDPR/local law when you process the results.

**Why is `legalEntity.cif` null?** Many sites, especially outside the EU, do not publish a tax ID, or publish it as an image or behind scripts the Actor does not read.

**How long does it take?** About 1-2 minutes for a page with 3 consent states, less with `baseline` only. Slow or blocked sites take longer.

**Extra datasets (opt-in).** By default the Actor writes only to the run's default dataset, so nothing piles up in your storage. Enable `saveDetailedDatasets` to also get 8 named raw datasets per run (`pcs-<runId>-pages`, `-detections`, `-network-requests`, `-storage-items`, `-tracking-ids`, `-consent-audit`, `-social-profiles`, `-sites`). They are not billed as results, but named datasets persist until you delete them.

**Consent banners differ by country.** Many banners only appear for EU visitors. Use a proxy country in your target market for a faithful consent audit.

**How often should I run it?** Legal entities rarely change: monthly or on demand. For compliance monitoring, schedule weekly runs.

**Integrations.** Use the Apify API, Make, Zapier, n8n, webhooks or the Apify MCP server to call it from workflows and AI agents.

### Support

Found a site where the tax ID is missed or wrong? Open an issue on the Actor's Issues tab with the URL and we will look at it.

# Actor input Schema

## `startUrls` (type: `array`):

Home pages (or any page) of the websites to analyze. Example: <code>https://www.example.es</code>. The actor looks for the tax ID on the page, then in the privacy policy and legal notice (aviso legal) linked from it.

## `maxPagesPerSite` (type: `integer`):

Maximum number of pages audited per website (one billed result per page). Use <b>1</b> to only analyze the URL you provide; higher values also follow internal links.

## `consentStates` (type: `array`):

<b>baseline</b>: no interaction with the banner. <b>reject</b>: rejects non-essential cookies. <b>accept</b>: accepts all. Selecting only <code>baseline</code> is about 3x faster. Example: <code>\["baseline"]</code>.

## `locales` (type: `array`):

Browser locale used for the audit. It affects the language of the consent banner and the page. The first value is used. Example: <code>es-ES</code>, <code>en-GB</code>, <code>de-DE</code>.

## `captureRawCookieValues` (type: `boolean`):

When off, cookie values and tracking identifiers are masked before saving. Turn on only if you need real values for forensic analysis.

## `captureRequestPayloadValues` (type: `boolean`):

When off, HTTP request bodies are redacted. Turn on to inspect what data trackers send.

## `includeUrlGlobs` (type: `array`):

Only internal links matching these globs are followed. Example: <code>https://example.com/legal/\*\*</code>

## `excludeUrlGlobs` (type: `array`):

Internal links matching these globs are skipped. Example: <code>https://example.com/blog/\*\*</code>

## `respectRobotsTxt` (type: `boolean`):

Skip pages disallowed by robots.txt when discovering internal links.

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

Proxy used for the audit. Consent banners are often geo-targeted: set the country to where your audience is (for example ES, DE, FR) to see the EU banner. Not every country is available on datacenter proxies.

## `saveDetailedDatasets` (type: `boolean`):

Also write 8 raw named datasets per run (pcs-RUNID-pages, -network-requests, -detections, -storage-items, -consent-audit, -tracking-ids, -social-profiles, -sites). Named datasets are kept in your storage until you delete them. Leave off unless you need raw request-level evidence.

## `maxConcurrency` (type: `integer`):

Pages processed in parallel. Higher is faster but needs more memory (4 GB is enough for the default).

## `maxRequestsPerCrawl` (type: `integer`):

Hard cap on total pages requested in the whole run.

## `pageTimeoutSeconds` (type: `integer`):

Navigation timeout for each page load, in seconds.

## `userAgent` (type: `string`):

Leave empty to use the default Chromium user agent.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.ree.es"
    }
  ],
  "maxPagesPerSite": 1,
  "consentStates": [
    "baseline",
    "reject",
    "accept"
  ],
  "locales": [
    "es-ES"
  ],
  "captureRawCookieValues": false,
  "captureRequestPayloadValues": false,
  "respectRobotsTxt": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  },
  "saveDetailedDatasets": false,
  "maxConcurrency": 4,
  "maxRequestsPerCrawl": 100,
  "pageTimeoutSeconds": 45
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with legal entity, compliance score, technologies, security headers and social profiles

# 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 = {
    "startUrls": [
        {
            "url": "https://www.ree.es"
        }
    ],
    "maxPagesPerSite": 1,
    "consentStates": [
        "baseline",
        "reject",
        "accept"
    ],
    "locales": [
        "es-ES"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("rastriq/legal-entity-extractor").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 = {
    "startUrls": [{ "url": "https://www.ree.es" }],
    "maxPagesPerSite": 1,
    "consentStates": [
        "baseline",
        "reject",
        "accept",
    ],
    "locales": ["es-ES"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("rastriq/legal-entity-extractor").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 '{
  "startUrls": [
    {
      "url": "https://www.ree.es"
    }
  ],
  "maxPagesPerSite": 1,
  "consentStates": [
    "baseline",
    "reject",
    "accept"
  ],
  "locales": [
    "es-ES"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyCountry": "US"
  }
}' |
apify call rastriq/legal-entity-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rastriq/legal-entity-extractor"
        }
    }
}
```

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/RyZO5s3scES4a3dEA/builds/HsmbWg1dlkkxRFMJD/openapi.json
