# Herold At $0.8💰 URL Search | Keyword Filters | Enriched Output (`abotapi/herold-at-scraper`) Actor

From $0.8/1K. Scrape company listings from herold.at, into a clean, structured dataset. Pull names, full addresses, GPS coordinates, telephone numbers, emails, websites, ratings, reviews, opening hours, payment methods, and founding dates, for any category in any Austrian city or region.

- **URL**: https://apify.com/abotapi/herold-at-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Lead generation, Automation, Agents
- **Stats:** 4 total users, 1 monthly users, 94.3% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.80 / 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?

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

## Herold.at Scraper, Austrian Yellow Pages Listings

Scrape company listings from **herold.at**, the largest Austrian directory portal, into a clean structured dataset. Pull names, full addresses, GPS coordinates, telephone numbers, emails, websites, ratings, reviews, opening hours, payment methods, and founding dates, for any category in any Austrian city or region.

Use it to build local lead lists, enrich CRM records with verified contacts, monitor competitor coverage by region, or feed a directory aggregator. Two start modes (search-builder and URL-paste) and forward auto-pagination keep large pulls effortless.

### Why This Scraper?

- **Full contact info on every listing without `fetchDetails`**: name, street address, postal code, city, region, telephone, email, website, rating, verified status, logo, branch code (~17 fields). The detail toggle adds GPS, opening hours, payment methods, founding date, reviews, and description (~25 fields total).
- **Two start modes**, pick categories and locations through the input panel, or paste any herold.at SERP URL straight from your browser
- **Multi-search batching**, categories × locations cartesian product in one run
- **Forward auto-pagination**, walks `/seite/N/` until the limit is reached
- **Detail enrichment toggle**, SERP-only happy path is fast and cheap (already includes street address, phone, email, website, rating); turn on `fetchDetails` to add GPS coordinates, opening hours, payment methods, founding date, and reviews
- **Resilient pagination**, picks up the page number from any pasted URL and walks forward
- **Post-fetch filters**, `verifiedOnly`, `ratedOnly`, `minRating` apply client-side without breaking the URL grammar

### Data You Get

> Sample shape, values are illustrative placeholders, not from a live listing.

The "Source" column shows where each field comes from. **SERP** fields are always populated (every run). **Detail** fields require `fetchDetails: true` and add ~30× the request count per page.

| Field | Source | Example | Notes |
|---|---|---|---|
| `id` | SERP | `"00000"` | 5-char herold.at branch code |
| `url` | SERP | `"https://www.herold.at/gelbe-seiten/wien/00000/sample-company/"` | Detail page URL |
| `name` | SERP | `"Sample Company"` | Company name |
| `category` | SERP | `"restaurant"` | Category slug from input or inferred from URL |
| `regionSlug` | SERP | `"wien"` | Location slug from URL path |
| `position` | SERP | `1` | Position in original SERP |
| `isVerified` | SERP | `true` | "Verifiziert" badge present on SERP card |
| `streetAddress` | SERP | `"Sample Street 1"` | Hidden popover on each card (always present) |
| `postalCode` | SERP | `"1010"` | Visible address line |
| `addressLocality` | SERP | `"Wien"` | City |
| `addressRegion` | SERP | `"Wien"` | Federal state |
| `addressCountry` | SERP | `"AT"` | Always "AT" |
| `telephone` | SERP | `"+43 1 0000000"` | International format, from `tel:` link in popover |
| `email` | SERP | `"contact@example.com"` | From `mailto:` link in popover (when company supplied one) |
| `website` | SERP | `"https://example.com/"` | External link in popover (when company supplied one) |
| `logoUrl` | SERP | `"https://images.herold.at/optimize?url=...&width=320"` | Logo image (some categories show an icon instead) |
| `primaryImage` | SERP | `"https://images.herold.at/..."` | First image (logo or hero) |
| `ratingValue` | SERP | `4.8` | Average rating (1-5) |
| `ratingCount` | SERP | `42` | Number of ratings |
| `bestRating` | SERP | `5` | Rating scale max |
| `worstRating` | SERP | `1` | Rating scale min |
| `branchCode` | SERP | `"00000"` | Same as id, exposed for downstream joins |
| `latitude` | Detail | `48.0000` | Geo coordinate |
| `longitude` | Detail | `16.0000` | Geo coordinate |
| `imageCount` | Detail | `1` | Number of detail-page images |
| `foundingDate` | Detail | `"2020"` | When the company was founded |
| `paymentAccepted` | Detail | `["Cash", "Card"]` | Accepted payment methods |
| `openingHours` | Detail | `[{ "day": "Monday", "opens": "09:00", "closes": "18:00" }]` | When the company supplied them |
| `reviewCount` | Detail | `12` | Number of detailed reviews |
| `reviews` | Detail | `[{ "author": "Sample Reviewer", "body": "Sample review text.", "rating": 5, "datePublished": "2026-01-01" }]` | Detailed review list |
| `description` | Detail | `"Sample seller description text appears here when fetchDetails=true."` | Company-supplied description text under the "Beschreibung" heading |
| `breadcrumb` | Detail | `["Home", "Wien", "Restaurant"]` | Category breadcrumb |
| `services` | Detail | `["Gastronomie", "Internationale Küche", "Gastgarten"]` | Tag chips from the Leistungen section (cuisine, amenities, special services) |
| `branchen` | Detail | `[{"name": "Restaurant", "slug": "restaurant"}, {"name": "Bierlokale-Pubs", "slug": "bierlokale-pubs"}]` | Company-specific industry memberships, populated from "Sie finden dieses Unternehmen in den Branchen" |
| `scrapedAt` | runtime | `"2026-01-01T00:00:00.000Z"` | ISO timestamp of when this record was extracted |
| `changeType` | runtime | `"NEW"` | `NEW`/`UPDATED`/`UNCHANGED`/`REAPPEARED`/`EXPIRED`. Only present when `incrementalMode: true` |
| `changedFields` | runtime | `["telephone"]` | Which fields changed since the last run. Only present when `incrementalMode: true` |
| `firstSeenAt` | runtime | `"2026-01-01T00:00:00.000Z"` | When this listing was first tracked. Only present when `incrementalMode: true` |
| `lastSeenAt` | runtime | `"2026-01-02T00:00:00.000Z"` | When this listing was last scraped. Only present when `incrementalMode: true` |

### How to Use

#### Search mode, single category in Vienna (fast, SERP-only)

```json
{
  "mode": "search",
  "categories": ["restaurant"],
  "locations": ["wien"],
  "maxPages": 5,
  "maxListings": 100
}
```

#### Search mode, multi-category × multi-location with detail enrichment

```json
{
  "mode": "search",
  "categories": ["elektriker", "installateur"],
  "locations": ["wien", "graz", "linz"],
  "fetchDetails": true,
  "maxPages": 3,
  "maxListings": 200
}
```

#### Search mode, Austria-wide for a category (no location filter)

```json
{
  "mode": "search",
  "categories": ["zahnarzt"],
  "locations": [],
  "maxPages": 10
}
```

#### URL mode, paste prepared URLs

```json
{
  "mode": "url",
  "urls": [
    "https://www.herold.at/gelbe-seiten/wien/restaurant/",
    "https://www.herold.at/gelbe-seiten/graz/elektriker/"
  ],
  "maxPages": 5,
  "maxListings": 100
}
```

#### Search mode with post-filters (verified, rated 4+ stars)

```json
{
  "mode": "search",
  "categories": ["frisör"],
  "locations": ["wien"],
  "verifiedOnly": true,
  "ratedOnly": true,
  "minRating": 4,
  "maxListings": 50
}
```

### Input Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mode` | enum `search`/`url` | `search` | Pick search-builder or URL-paste mode |
| `categories` | string\[] | `["restaurant"]` | Category URL slugs, e.g. `restaurant`, `elektriker`, `zahnarzt` |
| `locations` | string\[] | `["wien"]` | Austrian location slugs, e.g. `wien`, `graz`, `linz`. Empty = Austria-wide |
| `verifiedOnly` | boolean | `false` | Keep only "Verifiziert" listings (post-filter) |
| `ratedOnly` | boolean | `false` | Keep only listings with at least one rating (post-filter) |
| `minRating` | integer 1-5 | (none) | Drop listings below this average rating (post-filter) |
| `urls` | string\[] | example URL | Full herold.at URLs (URL mode only) |
| `maxPages` | integer | (none) | SERP pages to walk per search. Leave empty to walk every result page — the walk stops naturally once a page repeats already-collected listings or herold.at signals no more pages, or sooner once Max listings is reached |
| `maxListings` | integer | `20` | Total cap across all searches. Defaults to 20 so a run stays small unless you raise it; `0` = unlimited (still bounded by Max pages) |
| `fetchDetails` | boolean | `false` | Also fetch each listing's detail page (full address, phone, email, GPS, hours, reviews). Multiplies request count ~30× per page |
| `resumeFromRunId` | string | (none) | Previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already saved there (matched by listing id) are skipped |
| `incrementalMode` | boolean | `false` | Recurring monitoring of the SAME search: classify every listing as NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED against this actor's own remembered baseline |
| `stateKey` | string | (none) | Manually name the incremental baseline. Leave empty to auto-derive one from the search scope |
| `emitUnchanged` | boolean | `false` | Also save UNCHANGED listings to the dataset (returns and bills every listing every run) |
| `emitExpired` | boolean | `false` | Also save an EXPIRED row for a previously-tracked listing that no longer appears, once a run reaches a complete scan |
| `proxy` | object | Apify residential AT | Proxy configuration |

#### Resuming a full-catalogue walk

For an unbounded pull (`maxPages` left empty, `maxListings: 0`), two things protect a long run:

- **`resumeFromRunId`** lets you continue in a brand-new run: paste the ID of a previous run (or its dataset), and this run skips every listing `id` already saved there, appending only new listings.
- A **checkpoint** is saved automatically as the run progresses. If the run is interrupted by an Apify platform migration or you click **Resurrect** on a failed run, it picks back up from where it left off in the *same* run, without re-saving already-collected listings. No input is needed for this; it's automatic.

#### Incremental mode, recurring monitoring of the same search

`incrementalMode` is a **different feature from `resumeFromRunId`**: resume continues *one* interrupted crawl; incremental mode monitors the *same* search across separate scheduled runs (e.g. a daily/weekly schedule) and reports only what changed.

```json
{
  "mode": "search",
  "categories": ["restaurant"],
  "locations": ["wien"],
  "maxListings": 200,
  "incrementalMode": true
}
```

- The actor remembers a baseline for this search in its own key-value store, keyed by `stateKey` (or an automatic hash of categories/locations/urls/post-fetch filters/`fetchDetails` — **not** `maxListings`, `maxPages`, `maxNotifyListings`, `resumeFromRunId`, `proxy`, or MCP connector settings, so raising a cap tomorrow does not start a new baseline).
- Every scraped listing gets `changeType`: `NEW` (never seen before), `UPDATED` (a real field changed), `UNCHANGED` (nothing changed — **not saved to the dataset by default**), `REAPPEARED` (was previously marked `EXPIRED`, now seen again), or `EXPIRED` (previously tracked, no longer found — only emitted after a *complete* scan; a run capped by `maxListings`/`maxPages` or continuing via `resumeFromRunId` skips `EXPIRED` detection for that run, since it did not prove the listing is actually gone).
- Turn on `emitUnchanged` / `emitExpired` only if you want those extra rows — both increase dataset size and cost, so they default off.
- Combining `incrementalMode` with `resumeFromRunId` is only supported to bootstrap the very first incremental run from a prior full-catalogue crawl; once a baseline exists for a state key, the run fails fast asking you to remove `resumeFromRunId` or pick a different `stateKey`.
- **Volatility note:** `scrapedAt` and SERP ranking `position` never count toward a change — they vary on every scrape regardless of whether the listing itself changed.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape — the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record — not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Output Example

> Sample shape, values are illustrative placeholders, not from a live listing.

```json
{
  "id": "00000",
  "url": "https://www.herold.at/gelbe-seiten/wien/00000/sample-company/",
  "name": "Sample Company",
  "category": "restaurant",
  "regionSlug": "wien",
  "position": 1,
  "isVerified": true,
  "breadcrumb": ["Home", "Gelbe Seiten", "Restaurant", "Wien"],
  "streetAddress": "Sample Street 1",
  "postalCode": "1010",
  "addressLocality": "Wien",
  "addressRegion": "Wien",
  "addressCountry": "AT",
  "latitude": 48.0000,
  "longitude": 16.0000,
  "telephone": "+43 1 0000000",
  "email": "contact@example.com",
  "website": "https://example.com/",
  "logoUrl": "https://images.herold.at/optimize?url=...&width=320",
  "primaryImage": "https://images.herold.at/optimize?url=...&width=320",
  "imageCount": 1,
  "foundingDate": "2020",
  "branchCode": "00000",
  "paymentAccepted": ["Cash", "Card"],
  "openingHours": [
    { "day": "Monday", "opens": "09:00", "closes": "18:00" },
    { "day": "Tuesday", "opens": "09:00", "closes": "18:00" }
  ],
  "ratingValue": 4.8,
  "ratingCount": 42,
  "reviewCount": 12,
  "bestRating": 5,
  "worstRating": 1,
  "reviews": [
    { "author": "Sample Reviewer", "body": "Sample review text.", "rating": 5, "datePublished": "2026-01-01" }
  ],
  "description": "Sample seller description text appears here when fetchDetails=true.",
  "scrapedAt": "2026-01-01T00:00:00.000Z"
}
```

### Plan Requirement

- **Apify Free plan**: works for small runs but does not include residential proxy access, set the proxy field to your own proxy URLs if available.
- **Apify Starter plan and above**: includes Apify residential, set `proxy.apifyProxyGroups: ["RESIDENTIAL"]` and `proxy.apifyProxyCountry: "AT"` for stable Austrian routing. The default input prefill already does this.
- **Datacenter proxies**: usually work but may be rate-limited under load. Residential is recommended for any run with `maxListings > 200`.
- **Memory**: 256 MB default is sufficient for most runs (peak ~80 MB).

### Finding category and location slugs

The simplest way to learn valid slugs is to browse herold.at in your browser and copy URL fragments:

- Visit `https://www.herold.at/gelbe-seiten/` and click any category, note the slug after `/gelbe-seiten/` (e.g. `restaurant`, `elektriker`).
- Open a SERP URL like `https://www.herold.at/gelbe-seiten/wien/restaurant/`, the first path segment is the location slug (`wien`).
- Pass `mode=url` and paste the URL directly if you prefer to skip the slug discovery.

### Known limitations

- **Not every city × category combination has a SEO page.** Herold only generates `/<location>/<category>/` URLs where there is enough listing volume. Wien, Salzburg, and Bregenz work for most popular categories; Graz, Linz, Innsbruck, and Klagenfurt usually return 404 even though those cities appear in detail-page addresses. When a combo 404s, the actor logs a warning and moves to the next search. To get coverage for those cities, omit `locations` (Austria-wide search) and post-filter the dataset by `addressLocality` or `regionSlug`.
- **`openedNow` filter is not supported.** Herold's "Jetzt geöffnet" toggle is a client-side JavaScript filter; the URL grammar does not carry it. To get currently-open listings, run with `fetchDetails: true` (which populates `openingHours`) and post-filter the dataset against the current Europe/Vienna time.
- **GPS, opening hours, reviews, payment methods, and founding date require `fetchDetails: true`.** SERP cards already include name, full street address, postal code, city/region, phone, email, website, logo, rating, and verified status, so most use cases work without detail fetching. Turning detail fetch on multiplies request count ~30× per page. Even on detail pages, fields like `description`, `openingHours`, and `website` are populated only when the company supplied them to Herold.

### Verification

- 2026-09-01: search narrowing re-derived live: `restaurant` Austria-wide shows
  3,591 entries, `wien/restaurant` shows 1,062, `wien/zahnarzt` shows 765;
  `/seite/2/` pagination serves the next card page; the known city x category
  404s (e.g. `graz/restaurant`) still hold. Post-fetch rating filters
  re-derived on live cards: page 1 of `wien/restaurant` carries 30 cards, 11
  rated, 8 rated 4.0 or higher (`ratedOnly` + `minRating 4`).

# Actor input Schema

## `mode` (type: `string`):

Search mode = pick categories + locations + filters below. URL mode = paste any herold.at URL refined in a browser (recommended for filters not exposed below).

## `categories` (type: `array`):

Category URL slugs as they appear on herold.at, e.g. "restaurant", "elektriker", "installateur", "frisör", "zahnarzt", "rechtsanwalt". Open https://herold.at/gelbe-seiten/ → click any category → copy the slug from the URL path. The cartesian product of categories × locations is searched.

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

Austrian city/region URL slugs (verified working combos: "wien", "salzburg", "bregenz"). Note: herold.at only generates SEO pages for some city × category combinations; cities like graz, linz, innsbruck, klagenfurt return 404 on the combined URL even though they appear in result addresses. Leave empty to search Austria-wide for each category, which always works. Open a herold.at SERP and copy the location segment from the URL path to verify before running large jobs.

## `urls` (type: `array`):

One or more full herold.at URLs. Tip: open herold.at in your browser, navigate to a category (e.g. /gelbe-seiten/wien/restaurant/), then paste the resulting URL here. Multi-URL supported. Category slugs and Location slugs above are ignored, they only build a Search-mode URL. The post-fetch filters below (Verified/Rated/Minimum rating) still apply to whatever this URL returns. Pagination starts at the page in the URL and walks forward.

## `verifiedOnly` (type: `boolean`):

Keep only listings flagged "Verifiziert" on herold.at. Applied after fetch as a client-side filter (the site does not expose a server-side URL filter for this), so it narrows whichever mode above fetched the listings.

## `ratedOnly` (type: `boolean`):

Keep only listings that have at least one rating. Applied after fetch as a client-side filter, so it narrows whichever mode above fetched the listings.

## `minRating` (type: `integer`):

Drop listings with an average rating below this value (1-5). Listings without a rating are also dropped. Applied after fetch as a client-side filter, so it narrows whichever mode above fetched the listings.

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

How many SERP pages to walk per category/location combination (or per pasted URL). Each page returns up to ~30 listings. Leave empty to walk every result page — the walk stops naturally once a page repeats listings already collected or herold.at signals no more pages, or sooner once Max listings is reached.

## `maxListings` (type: `integer`):

Stop after this many listings across all searches. Defaults to 20 so a run stays small unless you raise it. 0 = unlimited (still bounded by Max pages).

## `fetchDetails` (type: `boolean`):

When ON, also fetch each listing's detail page for GPS coordinates, opening hours, payment methods, founding date, full review list, description, and breadcrumb. SERP cards already carry name, full street address, postal code, city, region, telephone, email, website, rating, and verified status, so most use cases work fine with this OFF. Multiplies request count ~30× per SERP page when ON. Default OFF.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already collected there (matched by listing id) are skipped, so this run only saves the new ones. Leave empty for a normal fresh run. Distinct from Incremental mode below — this continues one specific interrupted run, not recurring monitoring.

## `incrementalMode` (type: `boolean`):

When ON, this actor remembers the previous run of the SAME search (see State key) and classifies each listing as NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED. UNCHANGED and EXPIRED rows are not saved to the dataset unless enabled below — this is what keeps a scheduled recurring run cheap. Default OFF (every run returns every listing, as today). Combining with Resume from a previous run above is only safe on the very first incremental run (no baseline yet) — once a baseline exists, remove Resume from a previous run or set a different State key.

## `stateKey` (type: `string`):

Manually name the incremental baseline for this search, e.g. "wien-restaurants". Leave empty to auto-derive one from mode + categories/locations/urls + the post-fetch filters + Fetch detail pages — two runs with the exact same search settings then share a baseline automatically. Set this explicitly if you want to run several DIFFERENT search configs against the SAME named baseline, or keep configs that happen to match fully separate.

## `emitUnchanged` (type: `boolean`):

When ON, incremental mode also saves listings with no detected change (changeType="UNCHANGED") to the dataset, instead of only NEW/UPDATED/REAPPEARED. This returns — and bills for — every listing every run, defeating the point of incremental mode for most use cases. Default OFF.

## `emitExpired` (type: `boolean`):

When ON, incremental mode also saves a row (changeType="EXPIRED") for each previously-tracked listing that no longer appears, once this run reaches the natural end of the search results (skipped on a capped, resumed, or otherwise incomplete run — those cannot tell "gone" apart from "not reached yet"). This returns — and bills for — an extra row per disappeared listing. Default OFF.

## `proxy` (type: `object`):

Herold.at accepts naked Apify residential out of the box. Use country=AT for stable Austrian routing. Datacenter proxies usually work too but may be rate-limited under load.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "categories": [
    "restaurant"
  ],
  "locations": [
    "wien"
  ],
  "urls": [
    "https://www.herold.at/gelbe-seiten/wien/restaurant/"
  ],
  "verifiedOnly": false,
  "ratedOnly": false,
  "maxListings": 20,
  "fetchDetails": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AT"
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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 = {
    "mode": "search",
    "categories": [
        "restaurant"
    ],
    "locations": [
        "wien"
    ],
    "urls": [
        "https://www.herold.at/gelbe-seiten/wien/restaurant/"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "AT"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/herold-at-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 = {
    "mode": "search",
    "categories": ["restaurant"],
    "locations": ["wien"],
    "urls": ["https://www.herold.at/gelbe-seiten/wien/restaurant/"],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "AT",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/herold-at-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 '{
  "mode": "search",
  "categories": [
    "restaurant"
  ],
  "locations": [
    "wien"
  ],
  "urls": [
    "https://www.herold.at/gelbe-seiten/wien/restaurant/"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AT"
  }
}' |
apify call abotapi/herold-at-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/herold-at-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/M5l0zBCZV6G7l9czg/builds/hPoi5Zmy6c55H2TDr/openapi.json
