# HolidayCheck Hotel Reviews Scraper (`scrapyx/holidaycheck-reviews-scraper`) Actor

Extracts the full guest review history for any hotel on HolidayCheck (.de/.at/.ch) by hotel URL, including per-topic sentiment and rating facets.

- **URL**: https://apify.com/scrapyx/holidaycheck-reviews-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Travel, Marketing, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## HolidayCheck Hotel Reviews Scraper

Extracts the full guest review history for any hotel listed on HolidayCheck (holidaycheck.de, .at, or .ch) — just give it the hotel page link.

### Why use this actor

- No account, no login, and no API key needed — works on public hotel pages only.
- Returns **every** guest review up to your chosen limit, not just the first page: review title, the guest's own recommendation, travel date, party type, room type, tour operator, and whether the stay was a verified booking.
- Includes HolidayCheck's structured detail you can't get from a plain review list: **per-topic sentiment with the exact quotes behind it** (location, parking, food, cleanliness, service…) and the guest's individual answers to HolidayCheck's rating questionnaire.
- Each hotel also gets a summary row with the star rating, average score, recommendation rate, address and contact details, plus the full rating histogram and traveller-type/season/age-group breakdowns.
- Stable JSON that drops straight into a spreadsheet, database, or analysis pipeline.
- Every hotel you submit gets at least one output row — including a clear diagnostic reason on the rare rows that couldn't be fetched, so nothing silently disappears from your results.

### How it works

1. You give the actor one or more HolidayCheck hotel page links (or bare hotel IDs).
2. For each hotel, it reads the hotel profile and then pages through that hotel's review history until it reaches your limit or runs out of reviews.
3. Results are streamed to your dataset as they finish, with automatic retries when HolidayCheck is temporarily unresponsive.
4. You export the finished dataset as JSON, CSV, or Excel straight from the Apify Console — no scrapers, browsers, or blocks to babysit.

### Input

```json
{
  "hotelUrls": [
    "https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6"
  ],
  "maxReviewsPerHotel": 300,
  "maxConcurrency": 3,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

| Field | Type | Description |
|---|---|---|
| `hotelUrls` | array of strings | HolidayCheck hotel page URLs (.de, .at or .ch). Both the reviews tab (`/hr/...`) and the hotel-info tab (`/hi/...`) work, and a bare hotel ID such as `454268e5-f1bb-304e-a92d-d4c994ae43c6` is also accepted. |
| `maxReviewsPerHotel` | integer | Stop after this many reviews per hotel. HolidayCheck serves 10 reviews per page, so a hotel with 1,000+ reviews needs 100+ page reads — hence the default cap. Set to `0` to fetch every review. Default `300`. |
| `maxConcurrency` | integer | How many hotels to process at the same time. Default `3`. |
| `proxyConfiguration` | object | Proxy settings. Off by default; Residential is recommended for large production runs. |

### Output

Each hotel produces one **summary** row plus one **review** row per guest review. Real examples from a live run:

**Summary row** (`recordType: "SUMMARY"`) — truncated:

```json
{
  "_input": "https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6",
  "_source": "S1-fluxible-state",
  "_scrapedAt": "2026-08-10T18:14:28Z",
  "recordType": "SUMMARY",
  "reviewUrl": "https://www.holidaycheck.de/hr/454268e5-f1bb-304e-a92d-d4c994ae43c6",
  "totalReviewCount": 1089,
  "indexedReviewsCount": 71,
  "hotelId": "454268e5-f1bb-304e-a92d-d4c994ae43c6",
  "name": "centrovital Hotel Berlin",
  "stars": 4.5,
  "rating": 4.975282211088373,
  "recommendation": 0.8662317836962519,
  "reviewCount": 1089,
  "pictureCount": 444,
  "phone": "+49 30 818750",
  "email": "info@centrovital-berlin.de",
  "address": "Brauereihof 6\r\n13585\r\nBerlin\r\nBerlin\r\nDeutschland",
  "geo": { "type": "Point", "coordinates": [13.2108027, 52.5467968] },
  "reviewFacets": {
    "season": { "spring": { "count": 236 }, "summer": { "count": 301 }, "autumn": { "count": 289 }, "winter": { "count": 263 } },
    "traveledWith": { "COUPLE": { "count": 571 }, "SINGLE": { "count": 288 }, "FAMILY": { "count": 133 }, "FRIENDS": { "count": 95 } },
    "ratingRounded": { "1": { "count": 10 }, "2": { "count": 18 }, "3": { "count": 42 }, "4": { "count": 105 }, "5": { "count": 446 }, "6": { "count": 468 } }
  }
}
```

**Review row** (`recordType: "REVIEW"`) — truncated:

```json
{
  "_input": "https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6",
  "_source": "S1-fluxible-state",
  "_scrapedAt": "2026-08-10T18:14:28Z",
  "recordType": "REVIEW",
  "id": "495fa2b2-4da6-442a-a3da-99c11aba7ec2",
  "title": "Gutes Konzept, aber mittlerweile verbesserungswürdig",
  "traveledWith": "COUPLE",
  "user": {
    "id": "ab40ab36-6411-3183-be4d-dec0d334f972",
    "firstName": "Uwe",
    "ageGroup": "FROM_61_TO_65",
    "hasPublicProfile": true,
    "hotelReviewCount": 260
  },
  "entryDate": 1780910793000,
  "travelDate": 1780272000000,
  "hotel": { "id": "454268e5-f1bb-304e-a92d-d4c994ae43c6", "name": "centrovital Hotel Berlin" },
  "originalLocale": "de",
  "recommendation": true,
  "proofedReservation": false,
  "additional": { "costPerformance": "ACCEPTABLE", "roomType": null, "roomView": null },
  "topics": [
    {
      "id": "LOCATION_AND_SURROUNDING",
      "name": "Lage und Umgebung",
      "sentiment": 1,
      "quotes": [
        "Es handelt sich um ein ans ich schönes Hotel an den Spandauer Seen gelegen auf einem alten Brauerei - Gelände.",
        "Die öffentlichen Verkehrsmittel fahren fast direkt vor der Tür und man ist auch schnell an der U-Bahn."
      ]
    },
    { "id": "PARKING", "name": "Parken", "sentiment": -1, "quotes": ["Parkplätze sind jedoc …"] },
    "… 16 more"
  ],
  "contributions": {
    "ROOM_SIZE": { "value": "1", "text": "Zimmergröße", "inputType": "RATING", "rating": { "sentiment": 1 } },
    "PUBLIC_TRANSPORT": { "value": "YES", "text": "ÖPNV-Erreichbar", "inputType": "CHOICES" },
    "SERVICE_OPINION": { "value": "Personal war freundlich und hilfsbereit, jedoch …", "text": "Erfahrungen mit dem Service", "inputType": "TEXT" }
  },
  "hasMedia": true,
  "mediaList": ["… 13 items"]
}
```

When the input isn't a recognisable HolidayCheck hotel link, the actor still emits one row for that input with a clear reason:

```json
{
  "_input": "https://example.com/nope",
  "_source": "none",
  "_scrapedAt": "2026-08-10T18:14:28Z",
  "recordType": "ERROR",
  "_error": "invalid_input",
  "_errorDetail": "Expected a holidaycheck.de/.at/.ch hotel URL containing a hotel UUID (e.g. https://www.holidaycheck.de/hr/bewertungen-<slug>/<uuid>) or a bare hotel UUID."
}
```

| Field | Type | Description |
|---|---|---|
| `_input` | string | The hotel URL or ID you submitted. |
| `_source` | string | Which internal strategy produced this row. `"none"` on a failed row. |
| `_scrapedAt` | string | UTC timestamp of when this row was produced. |
| `recordType` | string | `"SUMMARY"`, `"REVIEW"`, or `"ERROR"`. |
| `totalReviewCount` | integer | How many reviews this hotel has in total (summary row). |
| `reviewFacets` | object | Rating histogram plus season / traveller-type / age-group / room-type breakdowns (summary row). |
| `id` | string | HolidayCheck's stable ID for this review — safe to de-duplicate on. |
| `title` | string | The review headline written by the guest. |
| `recommendation` | boolean | Whether the guest recommends the hotel. |
| `proofedReservation` | boolean | Whether HolidayCheck verified the stay against a real booking. |
| `travelDate` / `entryDate` | integer | When the guest travelled / posted, as Unix milliseconds. |
| `topics` | array | Per-topic sentiment (`1`, `0`, `-1`) with the exact quotes from the review that produced it. |
| `contributions` | object | The guest's individual answers to HolidayCheck's rating questionnaire, keyed by question. |
| `mediaList` | array | Photos the guest uploaded with the review. |
| `_error` | string | Present only on rows that couldn't be fetched, e.g. `invalid_input`, `fetch_failed`. |
| `_errorDetail` | string | Human-readable detail for the error, present only alongside `_error`. |
| *(all other fields)* | — | On a successful row, every field HolidayCheck publishes for that hotel/review is passed through unchanged. |

### Notes / limits

- HolidayCheck is a German-language site: review text, titles, and topic names come back in German (the review's own language is reported in `originalLocale`).
- Reviews are served 10 per page, so a hotel with 1,000+ reviews is a long run. Keep `maxReviewsPerHotel` at a sensible cap unless you really need the whole history.
- Reviewer names are first names only — that is all HolidayCheck publishes.
- The same hotel ID works on all three country sites (.de/.at/.ch) and returns the same reviews; the actor keeps whichever host you submitted.
- A `partial_*` error row means pagination stopped partway through a hotel after already returning some real reviews — you still get what was fetched, plus a diagnostic explaining why it stopped early.

### Other actors in this collection

| Actor | What it returns |
|---|---|
| Priceline Hotel Reviews Scraper | Guest reviews for hotels listed on Priceline.com |
| Agoda Reviews Scraper | Guest reviews for hotels listed on Agoda.com |
| Booking.com Reviews Scraper | Guest reviews for hotels listed on Booking.com |
| Trip.com Reviews Scraper | Guest reviews for hotels listed on Trip.com |
| Orbitz Hotel Reviews Scraper | Guest reviews for hotels listed on Orbitz.com |
| Viator Reviews Scraper | Guest reviews for tours/activities listed on Viator |
| GetYourGuide Reviews Scraper | Guest reviews for tours/activities listed on GetYourGuide |

# Actor input Schema

## `hotelUrls` (type: `array`):

HolidayCheck hotel page URLs (.de, .at or .ch). Both the reviews tab (/hr/...) and the hotel-info tab (/hi/...) work, and a bare hotel UUID is also accepted.

## `maxReviewsPerHotel` (type: `integer`):

Stop paginating a hotel after this many reviews. HolidayCheck serves 10 reviews per page, so a popular hotel with 1,000+ reviews needs 100+ requests — hence the default cap. Set to 0 for unlimited (fetch every review).

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

Maximum number of hotels processed in parallel.

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

Proxy settings. HolidayCheck was not observed to gate on IP reputation during recon, so a proxy is optional — but Residential is recommended for large production runs from shared platform IPs.

## Actor input object example

```json
{
  "hotelUrls": [
    "https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6"
  ],
  "maxReviewsPerHotel": 300,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "hotelUrls": [
        "https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/holidaycheck-reviews-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 = { "hotelUrls": ["https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/holidaycheck-reviews-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 '{
  "hotelUrls": [
    "https://www.holidaycheck.de/hr/bewertungen-centrovital-hotel-berlin/454268e5-f1bb-304e-a92d-d4c994ae43c6"
  ]
}' |
apify call scrapyx/holidaycheck-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/holidaycheck-reviews-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/LyfmrVpe3pQWjvmZL/builds/d7eUs1u1R3ZnTQVFA/openapi.json
