kestrel actors docs

kestrel actors › Guest & customer reviews

Kurzurlaub Reviews Scraper — Hotel- & Gästebewertungen

A kurzurlaub reviews scraper that returns every guest rating a hotel has on Kurzurlaub.de, as structured rows: the overall score on the site's 1–6 scale (6 is the best), the per-area scores the guest gave for the hotel, rooms, service, food, leisure, location and value, the title, the comment when the guest wrote one, the reviewer's first name and the date. Hotelbewertungen and gästebewertungen are what the site calls them; this turns kurzurlaub hotel reviews into hotel review data you can sort, filter and export — a hotel review scraper for the German short-break market, built for bulk work rather than one page at a time. If you have been searching for kurzurlaub bewertungen as a dataset instead of a web page, this is it.

Run Kurzurlaub Reviews Scraper on Apify →

Kurzurlaub reviews scraper pricing: what one row costs

EventWhat it isPriceCharged for
reviewRating row$0.003One guest rating: overall score on Kurzurlaub's 1-6 scale, the per-area scores the guest gave, title, comment when there is one, reviewer and date. Hotels with no ratings are free.

$0.003 per rating row. Hotel rows, status rows, filtered ratings, hotels with no ratings, unknown ids and failed hotels are free. A 205-rating property costs $0.62 in full; the same property as a daily complaints feed costs a fraction of a cent per day. Apify's platform usage (a second or two of compute per hotel) is separate and small: the verified runs below used well under a cent each.

Bulk hotel reviews at scale: 3,000 hotels × 100 newest ratings = 300,000 rows = $900, delivered in an afternoon with 16 sessions. The pocket's other actor charges about the same per row; the difference is the per-area scores, the date stop and what you never pay for.

Kurzurlaub reviews scraper input reference

Every field of Kurzurlaub Reviews, straight from the actor's input schema.

FieldTypeDefaultWhat it does
startUrlsarray[]Kurzurlaub.de hotel pages, e.g. https://www.kurzurlaub.de/hotel/rhein_lahn_taunus/hachenburg/parkhotel-hachenburg.html — the page is read once for the hotel's id, name, stars and address.
hotelIdsarray[]Kurzurlaub's numeric hotel ids (the o_id of the ratings modal), e.g. 15699 — what an earlier run's hotel_id gives you. Skips the page read.
maxReviewsPerHotelinteger2000 = every rating the hotel has (Kurzurlaub pages them 10-20 at a time, newest first). N = the newest N. The main cost control. Range 0-20000.
maxScorenumber00 = keep every rating. 1-6 = keep only ratings at or below it — the complaints feed (a 4 is a middling stay on Kurzurlaub's scale; 6 is the best). Filtered ratings are never charged. Range 0-6.
minScorenumber00 = keep every rating. 1-6 = keep only ratings at or above it — the praise feed. Combine with maxScore for a band. Filtered ratings are never charged. Range 0-6.
sinceDatestring""Empty = no date limit. YYYY-MM-DD, or relative so schedules never go stale: "30 days", "6 weeks", "3 months". Ratings come newest first, so paging stops as soon as the date is passed and older ratings are never fetched or charged.
includeHotelRowbooleantrueAlso emit one row per hotel with its id, name, stars, address, overall score and word, review count and the per-area averages. Never charged.
sessionsinteger2How many proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately. Range 1-16.
perIpnumber1Pace for each session. Kurzurlaub answered 10 of 10 requests at 1/s from one IP in testing; 1/s per IP is the default. Range 0.1-3.
proxyConfigurationobject{"useApifyProxy": true}Apify Proxy so runs rotate IPs. The default datacenter group is enough for Kurzurlaub.

Example input

{
  "startUrls": ["https://www.kurzurlaub.de/hotel/rhein_lahn_taunus/hachenburg/parkhotel-hachenburg.html"],
  "maxReviewsPerHotel": 0,
  "maxScore": 4,
  "sinceDate": "30 days"
}
{
  "hotelIds": ["15699", "5382", "9813"],
  "maxReviewsPerHotel": 0
}

Kurzurlaub reviews scraper output fields

One row per guest rating (charged), plus a free hotel context row and a free status row per property.

Dataset views in the Apify Console: Overview, Ratings, Low scores, Hotels, Run status.

FieldTypeWhat it holds
typestringRow type: review, hotel or status.
hotel_idstringKurzurlaub's numeric hotel id (its o_id).
hotel_namestringHotel name.
urlstringThe Kurzurlaub hotel page, when the run was given one.
starsintegerHotel rows: star class (Hotelstars Union).
streetstringHotel rows: street address (when the hotel page was read).
postal_codestringHotel rows: postal code.
citystringHotel rows: town.
regionstringHotel rows: Kurzurlaub's holiday region, e.g. Rhein / Lahn / Taunus.
countrystringHotel rows: country, in German (Deutschland, Österreich, Italien…).
ratingnumberHotel rows: the property's overall score, 1-6 (6 is best).
rating_wordstringHotel rows: Kurzurlaub's word for the overall score (Exzellent, Sehr gut, Gut…).
review_countintegerHotel rows: how many ratings the property has.
category_averagesobjectHotel rows: the property's per-area averages — hotel, room, service, food, leisure, location, value — each 1-6.
price_rangestringHotel rows: the price range of the hotel's current offers, as the page states it.
reviews_fetchedintegerHotel rows: how many ratings were taken for the property.
review_idstringA stable id for the rating (Kurzurlaub gives ratings none; this is a hash of hotel, date, score, title, reviewer and comment — use it to dedupe scheduled runs).
scorenumberThe guest's overall score, 1-6 (6 is best).
category_scoresobjectThe per-area scores the guest gave — overall, hotel, room, service, food, leisure, location, value — only the areas rated appear.
titlestringThe rating's title, as the guest wrote it (German).
textstringThe guest's comment, when there is one. Many Kurzurlaub ratings are a title and scores only.
reviewerstringThe guest's first name, or Gast when the guest stayed anonymous.
review_datestringDate of the rating (YYYY-MM-DD).
targetstringStatus rows: the input this row is about.
statusstringStatus rows: ok, no_reviews or error.
reviewsintegerStatus rows: rating rows delivered for the property.
filteredintegerStatus rows: ratings dropped by maxScore / minScore / sinceDate (never charged).
pagesintegerStatus rows: rating pages read.
totalintegerStatus rows: how many ratings Kurzurlaub shows for the property.
duplicatesintegerStatus rows: 1 when this input pointed at a property already harvested in the run.
errorstringStatus rows: why the property failed, if it did.
fetched_atstringWhen the row was fetched (UTC, ISO 8601).

Example row from a real run

Taken from the actor's README — this is the shape your dataset holds.

{
  "type": "review",
  "review_id": "0c7efb112a9c5d7d",
  "hotel_id": "5382",
  "hotel_name": "Astralis Hotel Domizil",
  "url": "https://www.kurzurlaub.de/hotel/unterer_neckar/walldorf_neckar/astralis-hotel-domizil-walldorf.html",
  "score": 5.7,
  "category_scores": {"hotel": 6.0, "room": 6.0, "service": 6.0, "food": 5.3, "leisure": 6.0, "location": 5.0},
  "title": "Heidelberg - Ich hab mein Herz verloren... - 2 Tage",
  "text": "Es war alles super 👍",
  "reviewer": "Elke",
  "review_date": "2026-08-24",
  "fetched_at": "2026-08-29T10:20:00+00:00"
}
{
  "type": "hotel",
  "hotel_id": "5382",
  "hotel_name": "Astralis Hotel Domizil",
  "url": "https://www.kurzurlaub.de/hotel/unterer_neckar/walldorf_neckar/astralis-hotel-domizil-walldorf.html",
  "stars": 4,
  "street": "Schwetzinger Str. 50",
  "postal_code": "69190",
  "city": "Walldorf",
  "region": "Unterer Neckar",
  "country": "Deutschland",
  "rating": 5.2,
  "rating_word": "Sehr gut",
  "review_count": 289,
  "category_averages": {"hotel": 5.3, "room": 5.2, "service": 5.4, "food": 5.2, "leisure": 4.8, "location": 5.4},
  "price_range": "79,00 EUR - 578,00 EUR",
  "reviews_fetched": 289,
  "fetched_at": "2026-08-29T10:20:00+00:00"
}

Kurzurlaub reviews scraper in Python, JavaScript and curl

Python

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/kurzurlaub-reviews-scraper").call(run_input={
    "hotelIds": ["15699"],
    "maxReviewsPerHotel": 0,
    "maxScore": 4,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "review":
        print(row["score"], row["review_date"], row["title"], row["category_scores"])

JavaScript (Node)

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/kurzurlaub-reviews-scraper').call({
    startUrls: ['https://www.kurzurlaub.de/hotel/rhein_lahn_taunus/hachenburg/parkhotel-hachenburg.html'],
    maxReviewsPerHotel: 200,
    sinceDate: '90 days',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const ratings = items.filter((r) => r.type === 'review');
console.log(ratings.length, 'ratings; with a comment:', ratings.filter((r) => r.text).length);

curl

curl -X POST "https://api.apify.com/v2/acts/kestrel~kurzurlaub-reviews-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"hotelIds": ["15699"], "maxReviewsPerHotel": 50}'

The same three calls are runnable files in the examples repository: examples/kurzurlaub-reviews-scraper.py|.js|.sh.

Limits and honest notes

  • Many ratings on the site are a title and scores only. text is filled when the guest wrote a comment and null when not; the actor does not invent prose. Do not expect every row to carry a paragraph.
  • The site gives ratings no id. review_id is a stable hash of hotel, date, score, title, reviewer and comment, so the same rating hashes the same on every run; two identical anonymous ratings on the same day would collapse into one row.
  • Pages carry 10 to 20 ratings depending on the property. The actor follows the site's own "next" link until it runs out, so it never guesses page counts.
  • A page that is not a ratings fragment (an error page, an empty answer) is retried on a fresh IP with backoff, and the hotel is reported as error if every attempt fails. It is never reported as no_reviews, because a false "no reviews" corrupts your dataset silently while a false error costs one retry.
  • An unknown id is reported as an error on its status row, free, without retrying. A hotel page with no ratings block is a hotel with no ratings: no_reviews, total: 0, free.
  • The site is German. Titles, comments, rating words and region names come back in German; the column names and the area keys in category_scores are English.
  • The star class is the Hotelstars Union rating the site displays; a few properties carry none.

FAQ

Does it need a Kurzurlaub API key or login?

No. It loads the same ratings fragment the site's own "Alle Bewertungen" button loads. There is no public API for kurzurlaub bewertungen, and this is how to get kurzurlaub reviews without api access.

Can I download Kurzurlaub reviews as CSV or Excel?

Yes. Every run writes an Apify dataset; open the Ratings view and export it as CSV, Excel, JSON or XML, or fetch it from the API with ?format=csv.

How do I get only Kurzurlaub negative reviews?

Set maxScore to 4 (or whatever your threshold is). Only the low ratings are delivered and billed; the site orders ratings newest first, so pair it with sinceDate for a rolling feed.

What does the 1–6 score mean?

The site scores on a six-point scale where 6 is the best ("Exzellent" starts around 5.5, "Sehr gut" around 5) and 1 is the worst. It is points, not German school grades — do not invert it. rating_word on the hotel row is the site's own label for the property's average.

Do I need the hotel id, or can I use the URL?

Either. A URL is read once for the id and the hotel's details; the id skips that read. The id is also hotel_id on every row, so a first run by URL gives you the ids for every run after.

How many ratings can one hotel return?

All of them — set maxReviewsPerHotel to 0. The actor walks the site's pages, newest first, until the last one and dedupes by review_id.

Are the reviews in German?

Yes, as written: titles, comments and the site's own labels are German. The row structure, the area keys and the status words are English, so the dataset slots into an English pipeline without translation.

Does it include the hotel's replies?

No — the site does not publish hotel replies on the ratings it lists, so there is nothing to scrape. Trip.com and Agoda do; see the related actors below.

Can I use it as a general hotel review aggregator?

For the German short-break market, yes. For a true hotel review aggregator across OTAs, pair it with the Agoda, Trip.com and Airbnb review scrapers below — the rows share the same shape, so one table holds all four.

What does bulk work cost?

$0.003 per rating, nothing else from the actor. 10,000 ratings is $30. See the cost section above for the platform-usage note.

Why does a run report fewer ratings than the site's total?

total is what the site states for the property; reviews is what you asked for and kept. maxReviewsPerHotel, maxScore, minScore and sinceDate all reduce the delivered count, and filtered on the status row says how many rows the filters removed.

Run Kurzurlaub Reviews Scraper

The actor lives on the Apify Store, where the pricing tab carries the live per-row price and the input form has every field above: apify.com/kestrel/kurzurlaub-reviews-scraper