# HRS Hotel Extractor (`kawsar/hrs-hotel-extractor`) Actor

HRS hotel scraper that extracts live hotel listings, nightly rates, star ratings, and guest scores for any city, so SEO and travel teams can track competitor pricing and build hotel datasets without copying results by hand.

- **URL**: https://apify.com/kawsar/hrs-hotel-extractor.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (community)
- **Categories:** Travel, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 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/platform/actors/running/actors-in-store#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

## HRS Hotel Extractor: Scrape HRS Hotel Listings, Prices, and Ratings

HRS hotel scraper that extracts hotel listings, live nightly rates, star ratings, and guest scores from HRS for any city you search. Give it a destination and a date range and it returns a structured dataset: names, addresses, coordinates, prices, amenities, and direct hotel links. City names are resolved for you, so `Berlin` works the same as a numeric HRS location ID.

The actor runs a real Chromium session, scrolls the page the way a visitor would, then reads the same hotel data the HRS results page renders. You get the full result set rather than whatever happened to be on screen.

### Use cases

- **Hotel price monitoring**: track nightly rates across a city on a schedule and catch competitor price moves early
- **SEO content generation**: build hotel landing pages and city guides from real listing data, star ratings and amenities included
- **Revenue management research**: compare your property against every bookable hotel in the market for the same dates
- **Travel affiliate sites**: populate a hotel directory with names, photos, coordinates, and links, no manual entry
- **Market analysis**: measure hotel supply, chain penetration, and star distribution across dozens of cities in one run
- **Sustainability reporting**: pull green certification classes and per-night carbon estimates for corporate travel policies

### Input

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `destinations` | array | (required) | City names or numeric HRS location IDs, one per line. Names are resolved automatically. |
| `checkInDate` | string | tomorrow | Arrival date as `YYYY-MM-DD`. Left empty, it points at tomorrow so scheduled runs stay valid. |
| `nights` | integer | 1 | Length of stay used to price every hotel. |
| `checkOutDate` | string | derived | Departure date as `YYYY-MM-DD`. Overrides `nights` when set. |
| `roomType` | string | `SINGLEROOM` | `SINGLEROOM`, `DOUBLEROOM`, `THREEBEDROOM`, or `FOURBEDROOM`. |
| `adultsPerRoom` | integer | 1 | Adults sharing each room. |
| `roomCount` | integer | 1 | Number of rooms requested. |
| `language` | string | `en` | Output language for names and amenity labels. |
| `includeUnavailable` | boolean | false | Keep hotels with no bookable rate for wider market coverage. |
| `maxItems` | integer | 100 | Cap on hotels saved across all destinations. |
| `timeoutSecs` | integer | 300 | Total run budget in seconds. |
| `requestTimeoutSecs` | integer | 60 | Per-search timeout in seconds. |
| `proxyConfiguration` | object | Datacenter (Anywhere) | Proxy type and location for requests. Supports Datacenter, Residential, Special, and custom proxies. Optional. |

#### Example input

```json
{
    "destinations": ["Berlin", "Munich", "Paris"],
    "checkInDate": "2026-09-10",
    "nights": 2,
    "roomType": "DOUBLEROOM",
    "adultsPerRoom": 2,
    "roomCount": 1,
    "language": "en",
    "maxItems": 300,
    "proxyConfiguration": { "useApifyProxy": true }
}
```

### What data does this actor extract?

Results land in a dataset, one row per hotel. Here is a real record, trimmed for length:

```json
{
    "hotelId": 875998,
    "hotelName": "Capri by Fraser Berlin",
    "hotelUrl": "https://www.hrs.com/en/hotel/875998",
    "stars": 4,
    "ratingScore": 9.1,
    "reviewCount": 15,
    "recommendationRate": 80,
    "street": "Scharrenstraße 22",
    "zipCode": "10178",
    "city": "Berlin",
    "district": "Berlin",
    "countryCode": "DEU",
    "latitude": 52.513894,
    "longitude": 13.405057,
    "distanceToCityCenterKm": 2.0,
    "cityCenterName": "Alexanderplatz",
    "distanceToRailwayKm": 5.0,
    "distanceToAirportKm": 12.0,
    "chainName": "Frasers Hospitality",
    "roomTypeOffered": "DOUBLEROOM",
    "totalPrice": 545.0,
    "totalPriceNet": 502.0,
    "pricePerNight": 272.5,
    "currency": "EUR",
    "breakfastIncluded": true,
    "breakfastPrice": 19.5,
    "availableRooms": 16,
    "amenities": ["CITY", "BUSINESS", "PARKING", "AIRCONDITION", "RESTAURANT"],
    "parkingAvailable": true,
    "wifiInRoom": true,
    "nonSmokingHotel": true,
    "constructionYear": 2017,
    "greenStayCertified": true,
    "greenEfficiencyClass": "A",
    "carbonPerNightKg": 8.85,
    "checkInDate": "2026-09-10",
    "checkOutDate": "2026-09-12",
    "nights": 2,
    "scrapedAt": "2026-08-08T12:04:11.905+00:00"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `hotelId` | integer | Stable HRS identifier, useful as a join key across runs |
| `hotelName` | string | Hotel name in the selected language |
| `hotelUrl` | string | Direct link to the hotel page |
| `stars` | integer | HRS star classification, 1 to 5 |
| `ratingScore` | number | Average guest rating out of 10 |
| `reviewCount` | integer | Number of guest reviews behind the average |
| `recommendationRate` | number | Share of reviewers who recommend the hotel |
| `street`, `zipCode`, `city`, `district` | string | Postal address parts |
| `countryCode`, `countryAlpha2` | string | ISO country codes |
| `latitude`, `longitude` | number | Coordinates in decimal degrees |
| `locationId`, `locationName` | integer, string | HRS location the hotel sits in |
| `distanceToCityCenterKm` | number | Distance to the city centre |
| `cityCenterName` | string | Reference point used as the centre |
| `distanceToRailwayKm` | number | Distance to the nearest station |
| `distanceToAirportKm` | number | Distance to the nearest airport |
| `chainName`, `brandName` | string | Chain and brand, empty for independents |
| `hotelStatus` | string | Operating status reported by HRS |
| `roomTypeOffered` | string | Room category the rate applies to |
| `totalPrice`, `totalPriceNet` | number | Gross and net total for the whole stay |
| `pricePerNight` | number | Gross rate per night and room |
| `wasPricePerNight` | number | Previous rate, handy for spotting discounts |
| `priceWithBreakfast` | number | Stay total with breakfast included |
| `currency` | string | Currency for every price in the record |
| `breakfastIncluded` | boolean | Whether breakfast is in the quoted rate |
| `breakfastPrice` | number | Breakfast cost when charged separately |
| `availableRooms` | integer | Rooms still bookable at that rate |
| `amenities`, `hotelTypes` | array | Amenity and property classification codes |
| `paymentTypes` | array | Accepted payment methods |
| `receptionServices` | array | Reception hours and language coverage |
| `parkingAvailable`, `freeParking`, `evChargingAvailable` | boolean | Parking and charging facts |
| `wifiInRoom`, `freeWifi` | boolean | In-room internet availability and cost |
| `nonSmokingHotel` | boolean | Whether the whole property is non-smoking |
| `restaurantCount`, `conferenceRoomCount` | integer | On-site restaurants and meeting rooms |
| `singleRoomCount`, `doubleRoomCount` | integer | Room inventory by type |
| `constructionYear` | integer | Year built or last rebuilt |
| `greenStayCertified`, `greenEfficiencyClass` | boolean, string | Sustainability certification and class |
| `carbonPerNightKg` | number | Estimated carbon per occupied room night |
| `thumbnailUrl` | string | Hotel photo hosted by HRS |
| `checkInDate`, `checkOutDate`, `nights` | string, integer | Stay the rate was priced for |
| `searchDestination` | string | Your input value that produced the row |
| `searchResultsUrl` | string | HRS results page for the same search |
| `scrapedAt` | string | UTC extraction timestamp, ISO 8601 |

### How it works

1. Opens a Chromium session on the HRS site and declines non-essential cookies.
2. Auto-scrolls the page until deferred content has loaded, the same way a visitor moves through it.
3. Resolves each destination you entered into an HRS location and picks the closest match by relevance score.
4. Runs the hotel search for your dates, room type, and occupancy from inside that browser session.
5. Flattens every hotel into one row and writes it to the dataset. If a destination fails, it is logged and the run carries on.

### Tips for better results

- Add a region when a city name is ambiguous. `Paris` and `Paris Texas` resolve to different places.
- Large cities return several hundred hotels for one date range. Raise `maxItems` before sweeping capitals.
- Turn on `includeUnavailable` when you want full market coverage rather than only bookable inventory. Price fields stay empty for sold-out hotels.
- Three-bed and four-bed rooms are rare across the inventory. Single and double rooms return far more hotels.
- Schedule daily runs on the same dates to build a rate history you can chart.

### FAQ

**How do I find the HRS location ID for a city?**
You do not need one. Type the city name and the actor resolves it, then logs the location it matched so you can confirm the choice.

**How many hotels can one run return?**
A single city search commonly returns 250 to 500 bookable hotels. The `maxItems` cap defaults to 100 and goes up to 1000 per run across every destination you list.

**Can I get prices in a specific currency?**
Prices come back in the currency the hotel quotes, given in the `currency` field on every row. Convert afterwards if you need one reporting currency.

**Does it work outside Germany?**
Yes. Coverage spans HRS inventory worldwide, including Paris, London, and New York.

**Why are some fields empty for a hotel?**
Smaller and independent properties often have no reviews, no chain, and no sustainability audit on file. Those fields come back empty rather than guessed.

**Do I need a proxy?**
Not for typical use. Add a proxy if you run large sweeps or hit rate limits, and switch to Residential if datacenter IPs get blocked.

### Integrations

Connect HRS Hotel Extractor with other apps and services using [Apify integrations](https://apify.com/integrations). You can integrate with Make, Zapier, Slack, Airbyte, GitHub, Google Sheets, Google Drive, and many more. You can also use [webhooks](https://docs.apify.com/integrations/webhooks) to trigger actions whenever results are available.

Point the HRS hotel scraper at a city, pick your dates, and you have a hotel dataset with live prices and ratings you can query or publish the same day.

# Actor input Schema

## `destinations` (type: `array`):

City names or numeric HRS location IDs, one per line. City names are resolved automatically, so 'Berlin' and '55133' both work. Add a region or country when a name is ambiguous, for example 'Paris' versus 'Paris Texas'.

## `checkInDate` (type: `string`):

Arrival date in YYYY-MM-DD format. Leave empty to use tomorrow, which keeps scheduled runs pointing at a valid future date.

## `nights` (type: `integer`):

Length of stay used to price every hotel. Ignored when you set a check-out date explicitly.

## `checkOutDate` (type: `string`):

Departure date in YYYY-MM-DD format. Leave empty to derive it from the check-in date and the number of nights.

## `roomType` (type: `string`):

Room category to price. Single and double rooms return the widest inventory; three-bed and four-bed rooms are far rarer and return fewer hotels.

## `adultsPerRoom` (type: `integer`):

Number of adults sharing each room. Use 2 with a double room for standard couple or colleague pricing.

## `roomCount` (type: `integer`):

How many rooms to request. Group bookings shrink the pool of hotels that can serve the whole request.

## `language` (type: `string`):

Language for hotel names, amenity labels, and location names in the output.

## `includeUnavailable` (type: `boolean`):

Turn on to keep hotels that have no rate for your dates. You get far wider coverage of the local hotel market, but price fields stay empty for sold-out properties.

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

Cap on hotels saved across all destinations. Keeps a run over a large city from consuming more compute than you planned.

## `timeoutSecs` (type: `integer`):

Total wall-clock budget for the run. The actor saves everything collected so far when the budget runs out.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a single search before moving on to the next destination. Large cities need more time than small ones.

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

Select proxies to use for requests. HRS blocks datacenter IPs on its live-pricing endpoint, so Residential proxies are required for the search to return results. The default below is already set to Residential.

## Actor input object example

```json
{
  "destinations": [
    "Berlin",
    "Paris",
    "70801"
  ],
  "checkInDate": "2026-09-10",
  "nights": 1,
  "checkOutDate": "2026-09-11",
  "roomType": "SINGLEROOM",
  "adultsPerRoom": 1,
  "roomCount": 1,
  "language": "en",
  "includeUnavailable": false,
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All extracted hotel records from the default dataset, in JSON.

## `datasetItemsCsv` (type: `string`):

All extracted hotel records from the default dataset, in CSV.

## `runInConsole` (type: `string`):

View this run, its log, and its output in the Apify Console.

# 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 = {
    "destinations": [
        "Berlin"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/hrs-hotel-extractor").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 = {
    "destinations": ["Berlin"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("kawsar/hrs-hotel-extractor").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 '{
  "destinations": [
    "Berlin"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call kawsar/hrs-hotel-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kawsar/hrs-hotel-extractor"
        }
    }
}

```

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/ypDdWM8DBNlEXbh3V/builds/43dbZHLWYdUSsrBlh/openapi.json
