# Gelbe Seiten Scraper (`automation-lab/gelbe-seiten-germany-business-listings`) Actor

Search Gelbe Seiten by business category and German location, then export public company contacts, addresses, ratings, listing URLs, and retrieval provenance.

- **URL**: https://apify.com/automation-lab/gelbe-seiten-germany-business-listings.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.77 / 1,000 business extracteds

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

## Gelbe Seiten Scraper

Build and refresh German business lists by category and location from public **Gelbe Seiten** listings. The Actor exports clean business identity, address, phone, email and website when exposed, rating context, listing URL, the originating query, and retrieval time.

Use it for one-time local market research or repeat the same input on an Apify schedule to refresh a CRM, spreadsheet, or directory dataset.

### What does this Gelbe Seiten scraper do?

Provide German business terms such as `Zahnarzt`, `Restaurant`, or `Klempner` and locations such as Berlin, Bremen, Hamburg, Munich, districts, regions, or postal codes. Every term is combined with every location.

You can also provide real `gelbeseiten.de/branchen/...` search URLs. The Actor reads the server-rendered listings, deduplicates businesses by their source UUID, and optionally visits public profiles for email, structured address, opening hours, coordinates, and richer context.

### Who is it for?

- Sales teams building location-specific German lead lists
- Agencies researching local categories and contact coverage
- Market analysts comparing categories across cities
- Directory operators refreshing public business records
- Data teams feeding structured Gelbe Seiten records into a pipeline

### Why use this Actor?

- Search many category-location combinations in one run
- Keep stable business IDs and source URLs for repeat comparisons
- Capture contacts only when Gelbe Seiten publicly exposes them
- Choose fast search-card extraction or richer profile enrichment
- Export through the default Apify dataset as JSON, CSV, Excel, XML, or RSS
- Use HTTP extraction with low memory rather than a browser

### What data can I extract?

| Field | Meaning |
| --- | --- |
| `businessId` | Stable Gelbe Seiten listing UUID |
| `name` | Public business name |
| `category`, `categories` | Directory category context |
| `address` | Combined public address |
| `streetAddress`, `postalCode`, `city`, `country` | Structured profile address when exposed |
| `phone`, `email`, `website` | Public contacts; nullable when absent |
| `rating`, `reviewCount` | Rating context displayed by the source |
| `openingHours` | Public profile opening-hours strings |
| `description` | Listing/profile description |
| `latitude`, `longitude` | Public profile coordinates when exposed |
| `listingUrl` | Canonical Gelbe Seiten profile URL |
| `query` | Search term, location, and exact search URL |
| `retrievedAt`, `source` | ISO retrieval time and `gelbeseiten.de` provenance |

### How do I get started?

1. Open the Actor input.
2. Add one or more business categories or keywords.
3. Add one or more German locations.
4. Set the total and per-search limits.
5. Keep profile enrichment on when you need emails or structured fields.
6. Click **Start**.
7. Open the default dataset and export the records.

A useful first input is:

```json
{
  "searchTerms": ["Zahnarzt"],
  "locations": ["Berlin"],
  "maxItems": 20,
  "extractDetails": true
}
```

### Input reference

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `searchTerms` | string\[] | `[]` | Categories or keywords; German terms work best |
| `locations` | string\[] | `[]` | German cities, districts, regions, or postal codes |
| `startUrls` | Request\[] | `[]` | Real Gelbe Seiten `/branchen/` result URLs |
| `maxItems` | integer | `100` | Maximum unique businesses across the run |
| `maxResultsPerSearch` | integer | `20` | Maximum accepted records per search page |
| `extractDetails` | boolean | `true` | Visit profiles for richer public fields |
| `maxConcurrency` | integer | `5` | Concurrent detail requests, from 1 to 15 |
| `maxRequestRetries` | integer | `2` | Transient retries, from 0 to 5 |
| `proxyConfiguration` | object | none | Optional Apify Proxy configuration |

Provide either at least one search URL or both non-empty `searchTerms` and `locations`. Unsupported domains and non-search Gelbe Seiten URLs fail validation.

### Example output

This shortened record reflects the current output shape:

```json
{
  "businessId": "5f06ccb6-068f-4b36-91a4-63113f066676",
  "name": "Zahnarztpraxis Petra Hartmann",
  "category": "Zahnärzte",
  "address": "Friedelstr. 14, 12047 Berlin",
  "phone": "030 6 24 31 33",
  "email": null,
  "website": "https://www.zahnaerztin-neukoelln.de",
  "rating": 4.9,
  "listingUrl": "https://www.gelbeseiten.de/gsbiz/5f06ccb6-068f-4b36-91a4-63113f066676",
  "query": {
    "searchTerm": "Zahnarzt",
    "location": "Berlin",
    "searchUrl": "https://www.gelbeseiten.de/branchen/zahnarzt/berlin"
  },
  "retrievedAt": "2026-09-11T20:10:00.000Z",
  "source": "gelbeseiten.de"
}
```

Null means the source did not expose the field for that listing. It is not an extraction error by itself.

### How much does it cost to extract Gelbe Seiten businesses?

Pay-per-event pricing includes one **Run started** charge of $0.00005 per run and one **Business listing** event for each unique row saved.

| Tier | Per business |
| --- | ---: |
| FREE | $0.001472 |
| BRONZE | $0.00128 |
| SILVER | $0.0009984 |
| GOLD | $0.000768 |
| PLATINUM | $0.000768 |
| DIAMOND | $0.000768 |

At FREE tier, 10 businesses cost about **$0.01477**, 50 cost about **$0.07365**, and 100 cost about **$0.14725**. Profile enrichment is bundled into the business event; it does not create another charge event. Actual source coverage can be below the requested maximum.

### Search and refresh workflows

For a recurring directory refresh, keep the input stable and schedule the Actor daily, weekly, or monthly. Use `businessId` as the durable comparison key, `retrievedAt` as the snapshot time, and `query` to preserve why each business entered the dataset.

Apify datasets are run-specific. Compare exports in your destination system or trigger a webhook after each successful run. The Actor does not claim to maintain an internal history, monitor in the background, or emit change alerts by itself.

### Spreadsheet and CRM integrations

- Export the dataset directly to CSV or Excel.
- Use the Apify Google Sheets integration for analyst review.
- Send a webhook to Make, Zapier, n8n, or your own API.
- Map `businessId` to your external unique key before upserting CRM accounts.
- Keep `listingUrl` and `retrievedAt` for source auditing.

### JavaScript API example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/gelbe-seiten-germany-business-listings').call({
  searchTerms: ['Restaurant'],
  locations: ['Bremen'],
  maxItems: 50,
  extractDetails: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Python API example

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("automation-lab/gelbe-seiten-germany-business-listings").call(run_input={
    "searchTerms": ["Klempner"],
    "locations": ["Hamburg", "München"],
    "maxItems": 100,
    "extractDetails": True,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### cURL API example

```bash
curl -X POST \
  'https://api.apify.com/v2/acts/automation-lab~gelbe-seiten-germany-business-listings/runs?token=YOUR_APIFY_TOKEN' \
  -H 'content-type: application/json' \
  -d '{"searchTerms":["Zahnarzt"],"locations":["Berlin"],"maxItems":20}'
```

Do not commit an Apify token into source control. Prefer an environment variable or secret manager.

### Use with MCP and AI assistants

Add this Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/gelbe-seiten-germany-business-listings"
```

#### Claude Desktop, Cursor, and VS Code setup

Use this equivalent desktop/editor configuration:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=automation-lab/gelbe-seiten-germany-business-listings",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

Example prompts:

- “Find 20 dentists in Berlin and return phones and websites.”
- “Extract the supplied Gelbe Seiten Bremen restaurant search URL.”
- “Build a Hamburg and Munich plumber list with profile enrichment.”

### Reliability, limits, and failure behavior

Gelbe Seiten currently returns up to 50 server-rendered cards for one search page, so `maxResultsPerSearch` is capped at 50. Broader coverage requires multiple meaningful locations or narrower category searches.

The Actor retries transient timeouts, rate limits, and selected server failures. It fails loudly for invalid input, unsupported URLs, non-HTML responses, and recognizable blocked or changed page shapes. If one profile enrichment request fails, the useful search-card record is preserved and a warning is logged.

Direct HTTP is the low-cost default. Configure Apify Proxy when your execution environment cannot access the source. Large query matrices can take longer because every term is combined with every location.

### Tips for better results

- Prefer German category names such as `Zahnarzt` over translations.
- Search districts separately when city-wide results exceed 50.
- Turn `extractDetails` off for faster name/address/phone snapshots.
- Keep it on when email, structured address, opening hours, or coordinates matter.
- Deduplicate future runs with `businessId`, not business name.
- Treat absent emails and ratings as normal source coverage differences.

### Responsible use and legality

This Actor accesses public business-directory pages. You are responsible for complying with Gelbe Seiten terms, applicable database rights, GDPR, marketing rules, and the laws governing your use. Do not use exported phone or email data for unlawful spam, harassment, or automated decisions about people. Minimize collection, retain provenance, secure exports, and honor applicable deletion or objection requests.

### Frequently asked questions

#### Does it expose every business email?

No. `email` is populated only when the public Gelbe Seiten profile exposes one. The Actor does not guess, purchase, or infer contact details.

#### Why did I receive fewer than 50 rows?

The directory can expose fewer matching cards, overlapping searches can resolve to the same `businessId`, and the global `maxItems` limit stops the run once reached.

#### Can I use a Gelbe Seiten URL directly?

Yes. Supply a public `https://www.gelbeseiten.de/branchen/...` URL in `startUrls`. Profile URLs are output records, not supported search inputs.

#### Why did a run fail instead of returning an empty dataset?

Invalid input, blocked pages, and changed upstream HTML are errors. Failing closed prevents an inaccessible page from being mistaken for a real zero-result market.

#### Is a proxy required?

No for the currently verified direct route. It remains optional for environments that need a different network path.

### Related automation-lab Actors

- [German Impressum Leads Scraper](https://apify.com/automation-lab/german-imprint-leads) can enrich supplied German business websites with public statutory imprint fields.
- [Apple Maps Business Listings Scraper](https://apify.com/automation-lab/apple-maps-business-listings-scraper) supports a different source for location-based business discovery.

These are separate sources and workflows; no cross-source matching is performed automatically.

# Actor input Schema

## `searchTerms` (type: `array`):

German terms work best, for example Zahnarzt, Restaurant, or Klempner.

## `locations` (type: `array`):

Cities, districts, regions, or German postal codes to combine with every search term.

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

Optional gelbeseiten.de/branchen/... search URLs. They are processed in addition to term-location combinations.

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

Maximum unique businesses saved across all searches.

## `maxResultsPerSearch` (type: `integer`):

Maximum listings taken from each Gelbe Seiten result page (site maximum: 50).

## `extractDetails` (type: `boolean`):

Visit each listing profile to collect email, structured address, website, hours, coordinates, and richer rating context when exposed.

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

Concurrent profile requests. Reduce this if the source becomes unstable.

## `maxRequestRetries` (type: `integer`):

Retries for transient timeout, rate-limit, and server failures.

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

Optional Apify Proxy. Direct HTTP is the default; use a German proxy if your environment cannot reach the source.

## Actor input object example

```json
{
  "searchTerms": [
    "Zahnarzt"
  ],
  "locations": [
    "Berlin"
  ],
  "maxItems": 20,
  "maxResultsPerSearch": 20,
  "extractDetails": true,
  "maxConcurrency": 5,
  "maxRequestRetries": 2
}
```

# Actor output Schema

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

API URL for business records in the overview dataset view.

# 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 = {
    "searchTerms": [
        "Zahnarzt"
    ],
    "locations": [
        "Berlin"
    ],
    "maxItems": 20,
    "maxResultsPerSearch": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/gelbe-seiten-germany-business-listings").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 = {
    "searchTerms": ["Zahnarzt"],
    "locations": ["Berlin"],
    "maxItems": 20,
    "maxResultsPerSearch": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/gelbe-seiten-germany-business-listings").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 '{
  "searchTerms": [
    "Zahnarzt"
  ],
  "locations": [
    "Berlin"
  ],
  "maxItems": 20,
  "maxResultsPerSearch": 20
}' |
apify call automation-lab/gelbe-seiten-germany-business-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/gelbe-seiten-germany-business-listings"
        }
    }
}
```

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/MHnKfvmHdeFrqHim9/builds/QqkSaIK7kl2In6Yeb/openapi.json
