kestrel actors › Guest & customer reviews
Hostelworld Reviews Scraper — Hostel Guest Reviews
This hostelworld reviews scraper turns any hostel on Hostelworld into structured hostel guest reviews: the 0-100 overall score with its seven sub-ratings, the guest's own words, the hostel's public reply, who was travelling and where they came from. Point it at Hostelworld URLs or property ids and it returns every review the site lists, newest first — hostel reviews as rows you can filter, chart and diff, not a page you have to read. Because it reads Hostelworld's own public JSON API there is no browser, no login and no key, so budget travel reviews arrive at a few hundred rows a second and review monitoring on a daily schedule costs cents.
Run Hostelworld Reviews Scraper on Apify →
Hostelworld reviews scraper pricing: what one row costs
| Event | What it is | Price | Charged for |
|---|---|---|---|
review | Review row | $0.003 | One Hostelworld guest review: the 0-100 overall score with its seven sub-ratings (value, safety, location, staff, atmosphere, cleanliness, facilities), the text, the owner's reply, group type, age band, trip types, reviewer nickname and nationality. Hostels with no reviews, unknown property ids, property rows and filtered reviews are free. |
$0.003 per review row. Hostel rows, status rows, duplicate targets, unknown ids and every review a filter dropped are free. A thousand reviews is $3; a daily 30-day watch over ten hostels is usually a few cents a day. Compute is included in the event price.
Hostelworld reviews scraper input reference
Every field of Hostelworld Reviews, straight from the actor's input schema.
| Field | Type | Default | What it does |
|---|---|---|---|
startUrls | array | [] | Hostelworld property pages, e.g. https://www.hostelworld.com/hostels/p/15529/home-lisbon-hostel/ or the older https://www.hostelworld.com/pwa/hosteldetails.php/Home-Lisbon-Hostel/Lisbon/15529 — every URL form Hostelworld serves carries the numeric property id, so no page has to be loaded first. Any query string is fine. |
propertyIds | array | [] | Hostelworld's numeric property ids, e.g. 15529 — the number in /hostels/p/<id>/ and the last path segment of a hosteldetails.php URL, and what an earlier run's property_id gives you. The fastest path: no lookup at all. |
maxReviewsPerProperty | integer | 100 | 0 = every review the hostel has (Hostelworld pages them 50 at a time; a busy hostel runs to a few thousand). N = the first N in the order below. The main cost control. Range 0-20000. |
reviewsSort | string (enum) | "-date" | The order Hostelworld returns reviews in. -date = newest first (the default, and the only order in which sinceDate can stop paging early), date = oldest first, rating = lowest rated first (a complaints feed), -rating = highest rated first. These four are the only values the API really honours — anything else is silently served as newest first. One of: -date, date, rating, -rating. |
minRating | integer | 0 | Hostelworld scores each review 0-100 (100 = perfect); every row also carries the same score on the 0-5 scale as rating_5. 0 = no floor. 90 keeps only the raves. Filtered reviews are never charged. Range 0-100. |
maxRating | integer | 0 | The other end of the same 0-100 overall score: 0 = no ceiling, 70 gives a complaints feed. Combine with reviewsSort = lowest rated first so the worst reviews arrive on page one. Filtered reviews are never charged. Range 0-100. |
requireText | boolean | false | Drop score-only reviews (an empty notes field) before billing. Hostelworld reviews nearly always carry a sentence or two, so this rarely removes much. |
groupTypes | array | [] | Keep only reviews from these group types: MALE and FEMALE (solo travellers), COUPLE, ALLFEMALEGROUP, ALLMALEGROUP, MIXEDGROUP, FAMILY. Friendly spellings work too (solo_female, female_group, mixed_group). Empty = all. Hostelworld's API has no server-side filter for this, so the filter runs here in the actor — the pages are still read, the filtered reviews are simply never charged. |
sinceDate | string | "" | YYYY-MM-DD, or relative so schedules never go stale: "30 days", "2 weeks", "6 months". With the default newest-first order the run stops reading once a whole page predates the date, so a daily schedule reads one page per hostel. Empty = no date limit. |
includePropertyRow | boolean | true | Also emit one free row per hostel with its name, type, city, country, address, coordinates, star rating, the aggregate 0-100 ratings, total ratings, facilities, what it is best for and its lowest nightly price. The hostel record is read either way — it is what gives review rows their hostel name and URL — and is never charged. |
sessions | integer | 2 | How many proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately. Range 1-16. |
perIp | number | 1 | Pace for each session. Hostelworld's API answered 10 of 10 requests at 1 req/s from a single datacenter IP with no throttling at all; 1-2 is comfortable. Range 0.1-5. |
proxyConfiguration | object | {"useApifyProxy": true} | Apify Proxy with the datacenter group is enough: the API answers plain HTTP requests from datacenter ranges with no key, no auth and no bot gate. Residential works too and costs more. Keep the default. |
Example input
{
"propertyIds": ["15529"],
"reviewsSort": "rating",
"maxRating": 70,
"requireText": true,
"sinceDate": "30 days",
"maxReviewsPerProperty": 0,
"includePropertyRow": true,
"proxyConfiguration": { "useApifyProxy": true }
}
{
"startUrls": [
"https://www.hostelworld.com/hostels/p/15529/home-lisbon-hostel/",
"https://www.hostelworld.com/pwa/hosteldetails.php/Yes-Lisbon-Hostel/Lisbon/45010"
],
"maxReviewsPerProperty": 0,
"reviewsSort": "-date",
"includePropertyRow": true,
"sessions": 4,
"perIp": 1
}
Hostelworld reviews scraper output fields
One row per hostel guest review (charged), plus a free hostel context row and a free status row per target.
Dataset views in the Apify Console: Overview, Reviews, Complaints, Hostels, Status.
| Field | Type | What it holds |
|---|---|---|
type | string | review | property | status |
target | string | The input value (URL or property id) this row came from |
property_id | string | Hostelworld's numeric property id (the number in /hostels/p/<id>/) |
property_name | string | Hostel name as Hostelworld lists it |
property_url | string | The hostel's page on hostelworld.com |
review_id | string | Hostelworld's numeric review id |
review_date | string | Publication date, YYYY-MM-DD |
text | string | The review text (Hostelworld's notes field); null when the guest scored without writing |
language | string | Language code of the text Hostelworld serves (always en today) |
machine_translated | boolean | true when Hostelworld machine-translated the review into the served language |
rating | integer | Overall score on Hostelworld's 0-100 scale (100 = perfect); on property rows, the hostel's aggregate score |
rating_5 | number | The same score converted to the 0-5 star scale, e.g. 94 -> 4.7 |
sub_ratings | object | The seven 0-100 sub-scores: value, safety, location, staff, atmosphere, cleanliness, facilities |
liked | string | What the guest liked, when Hostelworld splits the review that way (legacy field, usually null) |
disliked | string | What the guest disliked, when Hostelworld splits the review that way (legacy field, usually null) |
recommended | boolean | Whether the guest recommends the hostel (legacy field, usually null) |
owner_comment | string | The hostel's public reply to the review, if any |
group_type | string | MALE | FEMALE (solo travellers) | COUPLE | ALLFEMALEGROUP | ALLMALEGROUP | MIXEDGROUP | FAMILY |
age_group | string | Reviewer age band: 18-24, 25-30, 31-40 or 41+ |
trip_types | array | Why they were travelling: REGULARVACATION, WEEKENDAWAY, GAPYEAR, RTWTRIP, COLLEGEBREAK, OTHER |
reviewer_id | string | Hostelworld's numeric user id |
reviewer_nickname | string | Reviewer display name ("Anonymous" when they hid it) |
reviewer_gender | string | Male | Female when the reviewer published it |
reviewer_country | string | Reviewer nationality, e.g. "Ireland" |
reviewer_country_code | string | Hostelworld's nationality code, e.g. IE |
reviewer_reviews | integer | How many reviews this guest has written on Hostelworld |
reviewer_image | string | Reviewer avatar URL, when there is one |
property_type | string | HOSTEL | GUESTHOUSE | HOTEL | APARTMENT | CAMPSITE (property rows) |
star_rating | integer | Star rating where the property has one, else 0 (property rows) |
city | string | City (property rows) |
country | string | Country (property rows) |
region | string | Region or district Hostelworld files the property under (property rows) |
address | string | Street address (property rows) |
latitude | number | Latitude (property rows) |
longitude | number | Longitude (property rows) |
total_ratings | integer | How many guests have rated the hostel in total, scores without text included (property rows) |
currency | string | Currency the hostel prices in (property rows) |
lowest_price_per_night | number | Hostelworld's lowest advertised nightly price (property rows) |
best_for | array | What Hostelworld says the hostel is best for, e.g. ["Home Cooking", "Meeting People"] (property rows) |
facilities | array | Every facility Hostelworld lists for the hostel (property rows) |
description | string | Hostelworld's own write-up of the hostel, else the hostel's description (property rows) |
positive_count | integer | Reviews Hostelworld counts as positive (property rows) |
negative_count | integer | Reviews Hostelworld counts as negative (property rows) |
solo_percentage | number | Share of reviewers travelling solo (property rows) |
couples_percentage | number | Share of reviewers travelling as a couple (property rows) |
groups_percentage | number | Share of reviewers travelling in a group (property rows) |
reviews_listed | integer | Reviews Hostelworld lists for the hostel (property rows) |
reviews_fetched | integer | Reviews read in this run for the hostel before filters (property rows) |
status | string | ok | no_reviews | not_found | duplicate | error (status rows) |
reviews | integer | Reviews delivered and charged for this target (status rows) |
filtered | integer | Reviews dropped by the filters, never charged (status rows) |
pages | integer | Review pages read (status rows) |
total | integer | Reviews Hostelworld lists for the hostel (status rows) |
duplicates | integer | 1 when this target resolved to a hostel another target already covers (status rows) |
error | string | Why a target failed (status rows) |
fetched_at | string | UTC timestamp of the request |
Hostelworld reviews scraper in Python, JavaScript and curl
Python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/hostelworld-reviews-scraper").call(run_input={
"propertyIds": ["15529"],
"maxReviewsPerProperty": 200,
"reviewsSort": "-date",
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
reviews = [r for r in rows if r["type"] == "review"]
print(len(reviews), "reviews", sum(r["rating"] for r in reviews) / len(reviews))
JavaScript (Node)
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/hostelworld-reviews-scraper').call({
startUrls: ['https://www.hostelworld.com/hostels/p/15529/home-lisbon-hostel/'],
maxReviewsPerProperty: 0,
maxRating: 70,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((r) => r.type === 'review').length);
curl
curl -X POST "https://api.apify.com/v2/acts/kestrel~hostelworld-reviews-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"propertyIds":["15529"],"maxReviewsPerProperty":50,"reviewsSort":"-date"}'
The same three calls are runnable files in the examples repository: examples/hostelworld-reviews-scraper.py|.js|.sh.
Limits and honest notes
- One language. Hostelworld serves a single machine-translated English set. It accepts a
languagesparameter and then ignores it, so this actor deliberately offers no language filter rather than one that does nothing.languageandmachine_translatedare on every row so you can see exactly what you got. liked,dislikedandrecommendedare legacy. Hostelworld's schema still carries them; the data no longer fills them. They are kept so nothing is lost if the site starts writing them again.groupTypes,minRating,maxRating,requireTextandsinceDateare actor-side. The API has no server-side filter, so the pages are read and the rows are then dropped before billing.- Page size is capped at 50 by the API, which is what the actor asks for.
sinceDateonly stops paging early on a date sort. With-datea run stops as soon as a whole page predates the cut; with a rating sort the dates are not ordered, so the filter still applies but every page is read.- Scores are 0-100, not 1-5.
rating_5is there for joins with other review sources.
FAQ
Does it need a Hostelworld API key or login?
No. This is hostelworld reviews without an api key: the endpoint is public and unauthenticated, and the actor sends no cookie, token or Origin header.
Can I download Hostelworld reviews as CSV or Excel?
Yes. Every Apify dataset exports to CSV, Excel, JSON, XML or JSONL from the run's Storage tab or the API, and the run-sync-get-dataset-items call above takes &format=csv directly.
How do I get only the bad reviews?
Set reviewsSort to rating and maxRating to about 70. The worst arrive first and everything above the ceiling is filtered before it is charged.
Can I get Hostelworld reviews by property id instead of URL?
Yes — that is propertyIds, and it is the fastest path because nothing has to be resolved. Get hostelworld reviews by property id straight from an earlier run's property_id column.
How many reviews can one hostel return?
All of them. A busy city hostel carries one to three thousand; the actor pages through the lot at 50 per request and stops on its own at the end of the list.
Does it include the hostel's reply?
Yes — owner_comment. Hostelworld owner replies are common on hostels that manage their reputation and absent on the ones that do not, which is itself a signal.
Can I scrape Hostelworld reviews without an API of my own?
Yes. That is what this actor is: no infrastructure, no proxies to buy, no browser to keep alive. Run it from the Console, the API, a schedule or an agent.
Is the reviewer data really that detailed?
Yes. Group type, age band, trip type and nationality come from Hostelworld itself, which is why backpacker reviews here support demand analysis and not only sentiment.
What do bulk hostel reviews cost?
$0.003 each, filters applied first. Bulk hostel reviews across a fifty-hostel city at 200 reviews per hostel is 10,000 rows, or $30.
Can I use it for hostel sentiment analysis?
Yes. text is clean, review_date is exact and rating gives you a numeric label to train or evaluate against, per hostel and per group type.
How to use Hostelworld Reviews Scraper
Related scrapers
Run Hostelworld 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/hostelworld-reviews-scraper