# Europages Company Scraper (`axiomworks/europages-company-scraper`) Actor

Scrape Europages search results into company records with names, descriptions, addresses, websites, phone numbers, employee bands, founding years and supplier types. Optionally fetch company pages for VAT IDs, main business areas and contact persons; filter searches by keyword and country.

- **URL**: https://apify.com/axiomworks/europages-company-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.79 / 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

## Europages Company Scraper

**Returns:** one row per company with name, city, countryCode, homepage, phone, employeeCount, foundingYear, supplierTypes.
**Input:** `{"keywords":["packaging"],"countries":["DE"],"maxItems":20,"includeCompanyDetails":false}`
**Best for:** B2B lead lists, supplier sourcing, market mapping by country and industry.

```json
{
  "id": "646917",
  "sourceUrl": "https://www.europages.co.uk/en/company/vkf-renzel-gmbh-646917",
  "name": "VKF Renzel GmbH",
  "city": "Isselburg",
  "countryCode": "DE",
  "homepage": "https://www.vkf-renzel.de/",
  "employeeCount": "500-999",
  "supplierTypes": [
    "production",
    "service",
    "distribution",
    "wholesaler"
  ]
}
```

### What does Europages Company Scraper do?

Europages Company Scraper is a Europages scraper and Europages API alternative that turns the public Europages B2B directory into structured rows. You give it one or more search keywords, optionally a list of countries, and it returns the matching company profiles: name, description, full address, website, phone number, employee band, founding year, supplier types, map coordinates and the Europages page where the company can be contacted.

It reads the public search result pages and, when you ask for it, the public company pages. It does not log in, it does not use a browser, and it supports Apify Proxy. Each successful page decodes its embedded Nuxt payload once and reuses that data for extraction. Search-only runs avoid the extra company-page requests; detail runs make one additional request per company at a modest request rate. The Actor is an independent tool and is not affiliated with or endorsed by Europages.

Typical uses are building lists of suppliers or manufacturers in a given country, finding distributors for a product category, mapping the companies active in an industry, and feeding a CRM or enrichment pipeline with company names, websites and phone numbers.

### What data can you get?

Search-only results also include `productCount`, `logoUrl`, and `responseRate` when Europages exposes them. A null on the detail page does not erase a value available in the search result. These fields are nullable; unavailable values stay null.

Every record has a stable `id` (the Europages company ID) and a `sourceUrl` (the Europages company page). Fields that a company has not published are returned as null. The fields marked "only with" are added when you switch on the matching option.

| Field | Type | Description |
|---|---|---|
| `id` | string | Europages company ID, unique per company |
| `sourceUrl` | string | Europages company page the record came from |
| `name` | string | Company name |
| `description` | string | Company profile text |
| `street` | string | Street address |
| `postalCode` | string | Postal code |
| `city` | string | City |
| `countryCode` | string | ISO 3166-1 alpha-2 country code |
| `homepage` | string | Company website |
| `phone` | string | Company phone number |
| `employeeCount` | string | Employee count band such as 20-49 |
| `foundingYear` | number | Year the company was founded |
| `supplierTypes` | array | Supplier types such as production, service, wholesaler, distribution |
| `distributionArea` | string | Distribution area such as national or international |
| `latitude` | number | Latitude of the company address |
| `longitude` | number | Longitude of the company address |
| `contactPageUrl` | string | Europages company page, which carries the contact form |
| `mainBusinessArea` | string | Main business category (only with company details) |
| `vatId` | string | VAT identification number (only with company details) |
| `contacts` | array | Business contact persons with name, role and phone (only with company details) |
| `keywords` | array | Europages keywords listed on the company page (only with company details) |
| `certificates` | array | Certificate names, when the company lists any (only with company details) |
| `paymentMethods` | array | Accepted payment method codes and additional labels (company details only); null when unpublished |
| `paymentTerms` | array | Payment terms, when listed (only with company details) |
| `incoterms` | array | Incoterms, when listed (only with company details) |
| `productCount` | number | Number of products reported in search data or the company page, when present |
| `faxNumber` | string | Fax number, when present (only with company details) |
| `logoUrl` | string | Logo image URL from search data or company details, when present |
| `responseRate` | number | Response rate reported in search data or company details, when present |
| `sector` | string | Industry sector classified by AI (only with sector enrichment) |
| catalogUrl | string or null | Public catalog URL from a company detail page. |
| documents | array or null | Public document links, titles, filenames and MIME types. |
| averageResponseTime | string or null | Source response-time label. |
| isQuickResponder | boolean or null | Source quick-responder flag. |

The search result pages do not expose an email address or a revenue figure, so this Actor does not return them. To contact a company, use `contactPageUrl`, which is the Europages company page with its contact form.

Company details include public catalog and document links, response-time labels and quick-responder flags when available. Files are not downloaded. These signals help compare suppliers; they do not promise response speed.

### How to use

1. Open the Actor on Apify and go to the Input tab.
2. Enter one or more keywords, for example `packaging` or `cnc machining`.
3. Optionally add country codes such as `DE` or `FR` to keep only companies from those countries.
4. Set `maxItems` to the number of companies you need.
5. Company details are on by default (main business area, VAT ID and contact persons). This opens one extra page per company; switch `includeCompanyDetails` off for a faster search-only run.
6. Start the run and download the dataset as JSON, CSV, Excel or via the API.

You can also keep only certain supplier types with `supplierTypes` (for example `["production"]`); companies whose `supplierTypes` do not include one of them are skipped. Fields that a company has not filled in on its page are returned as null.

Keywords are turned into the Europages search URL by replacing spaces with hyphens. The country filter is sent to Europages. Search result totals may change between requests. The number of matching companies depends on how specific the keyword is: a narrow term in a single country can match only a handful of companies, while a broad term across all countries returns far more. The search backend of the directory is not fully deterministic, so totals can differ slightly between runs.

You can also paste Europages URLs into `startUrls`. A search URL such as `https://www.europages.co.uk/en/search/packaging.html?countries=DE` is paged through automatically. A company URL such as `https://www.europages.co.uk/en/company/<slug>` returns that single company with its details.

To continue a supplier search, set `startPage` to the next page you want, or supply a search URL with `?page=2`. The URL’s valid page number takes precedence. Set `maxPages` to bound pages fetched per search, including the starting page. For example, `startPage: 2` and `maxPages: 1` reads only page 2; `maxItems` still caps saved companies across all targets. These controls skip earlier pages but do not provide a stable cursor: Europages can reorder results between runs. Pages past the results return no companies. Direct company URLs ignore pagination controls.

### Input

| Field | Type | Description |
|---|---|---|
| `keywords` | array | Products, services or industries to search, e.g. `packaging`. Required unless startUrls is given. |
| `countries` | array | ISO 2-letter country codes to keep, e.g. `DE`, `FR`. Empty means all countries. |
| `startUrls` | array | URL objects, e.g. `[{"url":"https://www.europages.co.uk/en/search/packaging.html"}]`, used alongside keywords. |
| `startPage` | integer | First search page, 1-200, default 1; a valid URL page query overrides it. |
| `maxPages` | integer | Pages per search target, 1-200, default 200; searches stop by page 200. |
| `maxItems` | integer | Maximum companies to save, default 50. |
| `includeCompanyDetails` | boolean | Open each company page to add main business area, VAT ID and contacts. Default true. |
| `employeeCounts` | array | Employee bands to keep, e.g. `20-49`. Empty means all sizes. |
| `supplierTypes` | array | Supplier types to keep, e.g. `production`, `wholesaler`. Empty means all types. |
| `enrichSector` | boolean | Classify each company into an industry sector with a third-party AI processor. Default false. |
| `proxyConfiguration` | object | Apify Proxy settings. Datacenter proxy is the default. |

Example input:

```json
{
  "keywords": ["cnc machining"],
  "countries": ["FR", "IT"],
  "includeCompanyDetails": true,
  "maxItems": 30
}
```

For an AI agent’s first call, use the opening input example: it searches packaging companies in Germany, saves up to 20 unique companies, and skips extra company-page requests. The editor prefill is a convenience for the Input tab; API callers must supply keywords or startUrls explicitly. Both target lists share one result limit, so an earlier search can consume the budget before later targets run.

The filters apply to search results. A search URL with its own `countries` query takes precedence over the top-level country list; otherwise that list is added to the search. Direct company URLs fetch that profile and its details even when `includeCompanyDetails` is false, and do not apply country, employee-band or supplier-type filters. For a URL-only call, omit keywords to avoid adding a second search.

If a run returns no companies, first try a broader keyword or remove employee and supplier filters. Use a path-based search URL such as `/en/search/packaging.html`; the query-only `?q=` form is not supported. For a missing company, replace the URL with its current public profile. For persistent blocks, inspect the warning and adjust `proxyConfiguration` before retrying. Empty targets produce no placeholder records, and other targets can still return results.

The `maxItems` limit is exact: when 7 companies exist and you ask for 7, you get 7 and you are charged for 7. Duplicate companies that appear on several pages or under several keywords are saved once.

### Output

Each run writes one dataset item per company. This is a real record from a run with `includeCompanyDetails` switched off:

```json
{
  "id": "646917",
  "sourceUrl": "https://www.europages.co.uk/en/company/vkf-renzel-gmbh-646917",
  "name": "VKF Renzel GmbH",
  "street": "Im Geer 15",
  "postalCode": "46419",
  "city": "Isselburg",
  "countryCode": "DE",
  "homepage": "https://www.vkf-renzel.de/",
  "phone": "+4928749100",
  "employeeCount": "500-999",
  "foundingYear": 1985,
  "supplierTypes": [
    "production",
    "service",
    "distribution",
    "wholesaler"
  ],
  "distributionArea": "international",
  "latitude": 51.82045,
  "longitude": 6.44758,
  "contactPageUrl": "https://www.europages.co.uk/en/company/vkf-renzel-gmbh-646917"
}
```

With `includeCompanyDetails` on, the record also carries `mainBusinessArea`, `vatId` and `contacts`. A VAT ID or a contact person is only present when the company has published one, so these fields are empty for many companies. The description field is omitted from this example for readability but is returned in full when available.

The same company’s detail run returned these additional fields:

```json
{
  "catalogUrl": "https://wlw-1-company-facts-media20191122174836234900000006.s3.eu-central-1.amazonaws.com/6462285d-eca7-4b41-97d2-74a0b8d5adbd.pdf",
  "documents": [
    {
      "url": "https://wlw-1-company-facts-media20191122174836234900000006.s3.eu-central-1.amazonaws.com/6462285d-eca7-4b41-97d2-74a0b8d5adbd.pdf",
      "title": "Catalog",
      "filename": "Leistungsspektrum-de (2).pdf",
      "mimeType": "application/pdf"
    }
  ],
  "averageResponseTime": null,
  "isQuickResponder": true
}
```

### How much does it cost?

The Actor is charged per result: each company saved to the dataset counts as one result. If you switch on AI sector classification, each company that was classified successfully is charged as an enriched result in addition. Companies where the classification failed are not charged as enriched. See the Pricing tab of the Actor for the current rates. Because the `maxItems` limit is exact, you can cap the cost of any run by setting it.

### Use with AI agents (MCP)

The Actor can be called by AI agents through the Apify MCP server. Add this to your MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/europages-company-scraper"
    }
  }
}
```

Example prompts:

- "Find 30 packaging companies in Germany on Europages and list their websites and phone numbers."
- "Search Europages for CNC machining suppliers in France and Italy, with company details, and group them by employee band."
- "Get the Europages profile for this company URL and tell me its main business area."

### Integrations and API

You can start the Actor from code and read the results from the dataset. Replace `<TOKEN>` with your Apify API token.

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<TOKEN>")
run = client.actor("axiomworks/europages-company-scraper").call(
    run_input={"keywords": ["packaging"], "countries": ["DE"], "maxItems": 50}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["city"], item["homepage"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<TOKEN>' });
const run = await client.actor('axiomworks/europages-company-scraper').call({
    keywords: ['packaging'],
    countries: ['DE'],
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length);
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~europages-company-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["packaging"], "countries": ["DE"], "maxItems": 50}'
```

You can also connect the dataset to Google Sheets, Make, Zapier, n8n or a webhook, and schedule the Actor to refresh a supplier list every week.

### FAQ

**How many companies can I get per keyword?**
It depends on the keyword and the countries. Europages returns 30 companies per page and the Actor reads every page until `maxItems` is reached or the results end. Narrow keywords combined with a country filter can match only a few companies.

**Why is the email address missing?**
Europages does not show email addresses in its public listings. It shows a contact form on each company page, and `contactPageUrl` points to it.

**Why are VAT ID and contacts often empty?**
They are only available on the company page, and only when the company filled them in. They are fetched while `includeCompanyDetails` is on (the default).

**Does it need a login or a browser?**
No. It reads public pages only, with plain HTTP requests through Apify Proxy.

**What happens when a request is blocked?**
The Actor retries with backoff on a fresh proxy session. If a page still cannot be loaded, it logs a warning and continues. It does not solve CAPTCHAs.

**Is my data sent to a third party?**
Only when you switch on `enrichSector`. In that case the company description and main business area are sent to a third-party AI processor to pick the sector. Without that option, no data leaves the Actor except the requests to the directory.

**Can I filter by company size?**
Yes, use `employeeCounts` with the bands as they appear in the output, for example `20-49`. The filter is applied to the band returned by the directory.

### Is it legal to scrape Europages?

The Actor collects only information that anyone can see on public Europages pages without logging in. Company names, addresses and phone numbers are business information, but contact persons named on company pages are personal data under the GDPR and similar laws. If you store or use them, you need a lawful basis, and you should respect opt-out requests. The website's terms of use and robots.txt may restrict automated access, and that is your responsibility to review for your use case. This is general information, not legal advice; ask a lawyer if you are unsure.

### Feedback

If a field is missing, a run fails or you need another output field, open an issue from the Actor page on Apify. Please include the run link and the input you used so the problem can be reproduced.

# Actor input Schema

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

Search terms as strings, e.g. \["packaging","cnc machining"]. Spaces become hyphens in the search URL. Supply keywords or startUrls; both are processed when supplied. No API default; the editor prefill searches packaging.

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

Europages search or company URL objects, e.g. \[{"url":"https://www.europages.co.uk/en/search/packaging.html?countries=DE"}]. Use objects for Apify input validation; the runtime also accepts legacy URL strings. Supply instead of, or alongside, keywords. Use /en/search/<term>.html, not ?q=. Direct company URLs always load details. A valid page query overrides startPage. Default \[].

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

ISO two-letter country codes as strings, e.g. \["DE","FR"]. Default \[] searches all countries. Applies to keywords and search URLs without their own countries query; a URL’s countries query takes precedence. Direct company URL targets ignore this country list.

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

Maximum unique companies saved across all keywords and startUrls together, e.g. 20. Range 1-10000, default 50. Duplicates count once; fewer are returned when matches end. Empty or blocked targets save no error records.

## `includeCompanyDetails` (type: `boolean`):

Boolean, e.g. false for search-only results; default true adds mainBusinessArea, vatId, contacts, keywords and other detail fields when published. Adds one request per search result with a company URL. Direct company URLs always load details. The prefill uses false for a faster run.

## `employeeCounts` (type: `array`):

Employee bands as strings, e.g. \["20-49","50-99"]. Default \[] keeps all sizes. Filters search results by an exact employeeCount match before fetching details; missing bands are skipped when filtering. Does not filter direct company URLs.

## `supplierTypes` (type: `array`):

Supplier types as strings, e.g. \["production","wholesaler","service","distribution"]. Default \[] keeps all types. Search results must match at least one requested type, case-insensitively, before details are fetched. Does not filter direct company URLs.

## `enrichSector` (type: `boolean`):

Boolean, e.g. true to request sector classification; default false leaves sector absent. Sends description and mainBusinessArea to a third-party AI processor when available. At most 500 successful classifications per run; errors save the company without sector and without an enriched-result event.

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

Proxy object, e.g. {"useApifyProxy":true} (default) to use Apify Proxy, or {"useApifyProxy":false} for direct requests. Blocks and rate limits retry with backoff on fresh sessions. Persistent blocks return no records for that target; try another target or adjust proxyConfiguration.

## `startPage` (type: `integer`):

First search page to fetch, 1-200, default 1. Applies to keywords and search URLs without a valid page query. A search URL page query takes precedence. Direct company URLs ignore it; results can shift between runs.

## `maxPages` (type: `integer`):

Maximum search pages to fetch per target, 1-200, default 200. Counting starts at startPage or the URL page query; searches never pass page 200. maxItems still limits saved companies across all targets. Company URLs ignore this limit.

## Actor input object example

```json
{
  "keywords": [
    "packaging"
  ],
  "startUrls": [],
  "countries": [
    "DE"
  ],
  "maxItems": 20,
  "includeCompanyDetails": true,
  "employeeCounts": [],
  "supplierTypes": [],
  "enrichSector": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "startPage": 1,
  "maxPages": 200
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [
        "packaging"
    ],
    "countries": [
        "DE"
    ],
    "maxItems": 20,
    "includeCompanyDetails": false,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/europages-company-scraper").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 = {
    "keywords": ["packaging"],
    "countries": ["DE"],
    "maxItems": 20,
    "includeCompanyDetails": False,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/europages-company-scraper").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 '{
  "keywords": [
    "packaging"
  ],
  "countries": [
    "DE"
  ],
  "maxItems": 20,
  "includeCompanyDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call axiomworks/europages-company-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/europages-company-scraper"
        }
    }
}
```

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/c1j5FBNmc2Cz7VDgw/builds/P4A1LgrUKf9UoI4Dd/openapi.json
