# Zoover Reviews Scraper (`reviewly/zoover-reviews-scraper`) Actor

Scrapes every review from any Zoover accommodation page, plus the full accommodation record — rating, per-aspect scores, address, coordinates, facilities, images and awards. Includes an automatic Cloudflare bypass.

- **URL**: https://apify.com/reviewly/zoover-reviews-scraper.md
- **Developed by:** [Reviewly](https://apify.com/reviewly) (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.50 / 1,000 reviews

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Zoover Reviews Scraper — Export Every Hotel Review from Zoover to JSON, CSV or Excel

**Paste a Zoover accommodation URL, get every review as clean, structured data — full text, scores out of 10, per-aspect ratings, traveller type, dates and photos. No coding, no login, no blocked requests.**

- ✅ **All reviews, not just page 1** — the scraper paginates to the last review automatically
- ✅ **Built-in bot-protection bypass** — Zoover sits behind Cloudflare; this Actor handles it for you
- ✅ **Rich accommodation data included** — rating, star rating, aspect scores, address, GPS, phone, email, website, facilities, photos and awards
- ✅ **Incremental runs** — set a target date and only pull reviews newer than your last run
- ✅ **Works on every Zoover market** — 🇳🇱 .nl 🇧🇪 .be 🇩🇪 .de 🇫🇷 .fr 🇪🇸 .es 🇮🇹 .it 🇬🇧 .co.uk
- ✅ **Export anywhere** — JSON, CSV, Excel, XML, or straight to your app via the Apify API

***

### 📌 What This Actor Does

**Zoover Reviews Scraper** is an [Apify Actor](https://apify.com/actors) — a ready-made cloud scraper — that turns any Zoover accommodation page into a structured dataset.

Zoover is one of Europe's largest travel review platforms, with millions of guest reviews for hotels, apartments, campsites and resorts. That review data is public, but it is locked inside a JavaScript site protected by Cloudflare: copy-pasting is slow, and a normal web scraping script gets blocked within seconds.

This Actor solves both problems. You give it a URL like:

```
https://www.zoover.nl/a/167199/w-suites-by-estia
```

…and it returns the complete accommodation profile plus **every guest review** attached to it, ready for analysis in a spreadsheet, a BI tool, or an AI model.

#### Who it's for

| You are… | You use it to… |
|---|---|
| **Hotel & campsite owners** | Track your own reputation, read every complaint, benchmark against nearby competitors |
| **Hospitality & revenue managers** | Compare aspect scores (hygiene, location, price/quality) across a whole portfolio |
| **Market researchers & analysts** | Build datasets on European travel sentiment by region, season or traveller type |
| **Data scientists & AI teams** | Feed real, multilingual review text into sentiment analysis, LLM fine-tuning or RAG |
| **Marketers & agencies** | Mine authentic guest quotes for landing pages, ads and social proof |
| **Lead generation teams** | Extract accommodation contact details (phone, email, website) for outreach lists |
| **Developers** | Skip weeks of anti-bot work and call a stable API endpoint instead |

***

### ✨ Key Features

- **Complete review extraction** — title, full review text, score out of 10, per-aspect scores, reviewer name, verified badge, traveller type, publish date, stay date, likes, photos and owner replies.
- **Full accommodation record in the same item** — you don't need a second scraper for hotel details.
- **Cloudflare handled automatically** — a real hardened browser earns the clearance, then requests continue on the same IP. You never see a CAPTCHA.
- **Automatic IP rotation on blocks** — if an exit IP is refused, the Actor rotates and retries (up to 8 times) before giving up.
- **Multi-URL runs** — scrape a whole list of accommodations in a single run.
- **Review limits** — cap reviews per accommodation to keep test runs cheap.
- **Date cut-off for incremental scraping** — perfect for daily or weekly monitoring.
- **Locale-aware** — the scraper matches the language and country of the Zoover domain you give it, so you get the reviews exactly as travellers wrote them.
- **Never loses partial data** — if the site cuts a run short, everything collected up to that point is still saved.
- **Clean, predictable schema** — the same fields every run, so your pipeline never breaks.

***

### 🧠 Why This Actor Is Different

Most "review scrapers" break on Zoover for one of three reasons. Here's how this one is built differently:

| Common problem | How this Actor handles it |
|---|---|
| **Cloudflare blocks the request** (`403`, "Just a moment…") | A real, anti-fingerprint Firefox browser passes the device check, then hands the session to a fast HTTP client — no CAPTCHA service, no manual cookies |
| **Scrapers grab only the first 6–10 reviews** | Uses Zoover's own cursor pagination to walk the entire review list to the end |
| **Reviews arrive as messy HTML text** | Data comes from Zoover's structured review API, so scores, dates and aspects are typed values, not scraped strings |
| **Hotel details need a second run** | Accommodation profile and reviews land in a single dataset item |
| **Slow, browser-heavy scraping of every page** | The browser is used *once* to unlock access; every review batch after that is a lightweight request — far faster and cheaper than a full browser crawl |
| **Runs die halfway and lose everything** | Partial results are always pushed; blocked IPs are rotated and retried automatically |

**In short:** browser-grade access with API-grade speed and data quality.

***

### ⚙️ Input Configuration

You can configure the run in the visual **Input** form, or with JSON via the API.

#### Input fields

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `startUrls` | Array | ✅ Yes | – | Zoover accommodation URLs to scrape. Sub-pages (photos, prices, reviews tabs) are accepted and automatically normalised to the main page. |
| `maxReviews` | Integer | No | `0` | Max reviews **per accommodation**. `0` = all of them. Great for cheap test runs. |
| `targetDate` | String (ISO date) | No | – | Stop when reviews get older than this date, e.g. `2025-01-01`. Zoover returns newest first, so this is the cheapest way to run incrementally. |
| `reviewsPageSize` | Integer | No | `25` | How many reviews to request per API call (1–100). Bigger batches = fewer requests = faster runs. Falls back to 6 automatically if a batch is refused. |
| `proxyConfiguration` | Object | No | Apify Residential, NL | Proxy settings. **Residential proxies are strongly recommended** — see tips below. |

#### Example input (single hotel, everything)

```json
{
  "startUrls": [
    { "url": "https://www.zoover.nl/a/167199/w-suites-by-estia" }
  ],
  "maxReviews": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "NL"
  }
}
```

#### Example input (multiple hotels, incremental daily run)

```json
{
  "startUrls": [
    { "url": "https://www.zoover.nl/a/167199/w-suites-by-estia" },
    { "url": "https://www.zoover.de/a/123456/hotel-beispiel" }
  ],
  "targetDate": "2026-07-01",
  "reviewsPageSize": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

#### 💡 Tips for best results

1. **Match the proxy country to the domain.** Scraping `zoover.nl`? Use `NL`. `zoover.de`? Use `DE`. A German page loaded from a US IP looks suspicious and gets challenged more often.
2. **Always use residential proxies.** Datacenter IPs are refused far more frequently on Cloudflare-protected pages.
3. **Start with `maxReviews: 10`** to validate the output format before running a full portfolio.
4. **Give the run 4 GB of memory.** The Actor launches a real browser to unlock access; less memory makes runs slower and flakier.
5. **Use `targetDate` for monitoring.** Set it to the date of your last successful run and each new run pulls only what's new.

***

### 📤 Output Format

The Actor pushes **one dataset item per accommodation URL**. Each item contains the full accommodation record and a nested `reviews` array.

Download it as **JSON, CSV, Excel, XML or HTML**, or fetch it from the Apify API:

```
https://api.apify.com/v2/datasets/{DATASET_ID}/items?format=json
```

> 💡 Exporting to CSV? Apify flattens nested fields automatically (`reviews/0/text`, `reviews/1/text`, …). If you want one row per review, use the "unwind" option on the export and set it to `reviews`.

#### Sample output (abridged)

```json
{
  "zooverId": "90757553-66d5-4596-af34-7f47f7fb0867",
  "heliosId": 167199,
  "giataId": 19913,
  "name": "W Suites by Estia",
  "url": "https://www.zoover.nl/a/167199/w-suites-by-estia",
  "type": "Appartement",
  "isBookable": true,
  "merchandisingLabel": "best_reviewed",
  "rating": 9.1,
  "ratingScale": 10,
  "starRating": 4,
  "reviewCount": 198,
  "ratingsPerAspect": {
    "childFriendly": { "rating": 9.15, "count": 198 },
    "hygiene":       { "rating": 9.26, "count": 198 },
    "interior":      { "rating": 8.68, "count": 198 },
    "location":      { "rating": 9.20, "count": 198 },
    "priceQuality":  { "rating": 9.05, "count": 198 },
    "space":         { "rating": 8.86, "count": 198 }
  },
  "totalReviewsAvailable": 198,
  "ratingDistribution": [
    { "score": 10, "count": 113 },
    { "score": 9,  "count": 47 },
    { "score": 8,  "count": 19 }
  ],
  "travelPartyDistribution": [
    { "travelParty": "COUPLE", "count": 84 },
    { "travelParty": "FAMILY_WITH_OLDER_CHILDREN", "count": 44 },
    { "travelParty": "FRIENDS", "count": 40 }
  ],
  "country": "Griekenland",
  "countryCode": "GR",
  "region": "Kreta",
  "city": "Stalis",
  "address": { "street": "El.Venizelou Street", "zipcode": "GR-70007" },
  "coordinates": { "latitude": 35.288956, "longitude": 25.446648 },
  "breadcrumb": [
    { "name": "Griekenland", "type": "COUNTRY", "url": "https://www.zoover.nl/griekenland" },
    { "name": "Kreta", "type": "REGION", "url": "https://www.zoover.nl/griekenland/kreta" }
  ],
  "phone": "+30 6945713100",
  "email": "info@example.com",
  "website": "https://wsuites.gr/",
  "description": "W Suites by Estia ligt centraal in Stalida, nog geen 300 meter van het zandstrand…",
  "images": ["https://storage.googleapis.com/images_trvl-portfolio-prod/…/f519a265.webp"],
  "facilities": [
    { "group": "building-information", "name": "number-of-apartments", "value": "12" }
  ],
  "features": ["childrens_pool", "pool", "airco", "pets_allowed", "wifi"],
  "awards": [
    { "year": 2025, "awardType": "gold", "rank": 241, "regionAward": false }
  ],
  "cheapestOffer": { "price": 296.25, "lengthOfStay": 5 },
  "scrapedAt": "2026-08-08T09:12:44.108Z",

  "reviews": [
    {
      "reviewId": 80111,
      "accommodationId": "90757553-66d5-4596-af34-7f47f7fb0867",
      "accommodationName": "W Suites by Estia",
      "accommodationUrl": "https://www.zoover.nl/a/167199/w-suites-by-estia",
      "title": "super gezellig verblijf gehad",
      "text": "Warm welkom door Ans wat erg fijn was. Klein maar fijn appartement. Alles schoon…",
      "textLength": 837,
      "language": "nl",
      "score": 9,
      "scoreScale": 10,
      "aspects": {
        "childFriendly": 10,
        "hygiene": 10,
        "interior": 8,
        "location": 8,
        "priceQuality": 8,
        "space": 8
      },
      "reviewerName": "Ilse",
      "reviewerVerified": true,
      "traveledWith": "FAMILY_WITH_OLDER_CHILDREN",
      "publishedAt": "2026-08-02T09:37:46.475Z",
      "updatedAt": "2026-08-02T09:37:52.024Z",
      "travelDate": "2026-07-01T00:00:00.000Z",
      "likes": 0,
      "images": [],
      "replies": [],
      "parentType": "accommodation"
    }
  ]
}
```

#### Accommodation fields

| Field | Type | Description |
|---|---|---|
| `zooverId` | String | Zoover's internal UUID for the accommodation — the stable primary key |
| `heliosId` | Number | The numeric ID visible in the page URL |
| `giataId` / `goalId` | Number | Industry IDs, handy for matching against other travel datasets |
| `name` | String | Accommodation name |
| `url` / `canonicalUrl` | String | The page scraped |
| `type` | String | Property type (hotel, apartment, campsite…), in the site's language |
| `isBookable` | Boolean | Whether Zoover sells this property |
| `merchandisingLabel` | String | Zoover badge, e.g. `best_reviewed` |
| `rating` | Number | Overall guest rating **out of 10** |
| `ratingScale` | Number | Always `10` — so your charts never guess |
| `starRating` | Number | Official star classification |
| `reviewCount` | Number | Review count shown on the page |
| `totalReviewsAvailable` | Number | Review count reported by the review API (the number available to scrape) |
| `ratingsPerAspect` | Object | Average score + count per aspect (hygiene, location, price/quality, space, interior, child-friendly) |
| `ratingDistribution` | Array | How many reviews gave each score 1–10 |
| `travelPartyDistribution` | Array | Review counts by traveller type (couple, family, friends, business, single) |
| `country`, `countryCode`, `region`, `city` | String | Location |
| `address` | Object | `street`, `zipcode` |
| `coordinates` | Object | `latitude`, `longitude` |
| `breadcrumb` | Array | Country → region → city hierarchy with Zoover URLs |
| `phone`, `email`, `website` | String | Public contact details, when the property publishes them |
| `socialLinks` | Object | Social profiles, when available |
| `description` | String | Full property description |
| `descriptionSections` | Array | The same description split into titled sections |
| `images` | Array | Photo URLs |
| `facilities` | Array | Structured facility list (`group`, `name`, `value`) |
| `features` / `distanceFeatures` | Array | Amenity tags (`wifi`, `pool`, `airco`…) and distance-based tags |
| `awards` | Array | Zoover awards by year with rank and type |
| `cheapestOffer` | Object | Lowest advertised `price` and `lengthOfStay`, when shown |
| `priceRange` | String | Price range, when published |
| `scrapedAt` | ISO date | When the record was collected |
| `reviews` | Array | Every review collected (see below) |

#### Review fields

| Field | Type | Description |
|---|---|---|
| `reviewId` | Number | Zoover's review ID — use with `accommodationId` to deduplicate across runs |
| `accommodationId`, `accommodationName`, `accommodationUrl` | String | Parent property, repeated on each review so the array works standalone |
| `title` | String | Review headline |
| `text` | String | Full review text, in the language the guest wrote it |
| `textLength` | Number | Character count — useful for filtering out one-liners |
| `language` | String | Review language code (`nl`, `de`, `fr`…) |
| `score` | Number | Guest score **out of 10** |
| `scoreScale` | Number | Always `10` |
| `aspects` | Object | Per-aspect scores given by this guest |
| `reviewerName` | String | Display name as shown publicly on Zoover |
| `reviewerVerified` | Boolean | Whether Zoover marks the reviewer as verified |
| `reviewerLevel` | String | Zoover's internal reviewer level token |
| `traveledWith` | String | `COUPLE`, `FAMILY_WITH_YOUNG_CHILDREN`, `FRIENDS`, `BUSINESS`, `SINGLE`… |
| `publishedAt` | ISO date | When the review was posted |
| `updatedAt` | ISO date | Last edit |
| `travelDate` | ISO date | Month of the actual stay (Zoover collects month precision) |
| `likes` | Number | Helpful votes |
| `images` | Array | Guest photos (`id`, `url`, `status`, `createdAt`) |
| `replies` | Array | Owner responses (`text`, `userName`, `publishedAt`) |
| `parentType` | String | What the review is attached to, e.g. `accommodation` |

***

### ▶️ How to Use

#### Option 1 — In the Apify Console (no code)

1. **Open the Actor** in Apify Store and click **Try for free**.
2. **Paste your Zoover URLs** into *Start URLs* — one per line, or click *Add* for each.
3. *(Optional)* Set **Max reviews** to `10` for a quick test run.
4. *(Optional)* Under **Advanced**, pick a **proxy country** matching the site (NL for zoover.nl).
5. Click **Start**.
6. When the run finishes, open the **Dataset** tab and **Export** as CSV, Excel or JSON.

That's it — no installation, no browser automation, no proxy setup.

#### Option 2 — Schedule it

Use **Schedules** in Apify to run the Actor every day or week, with `targetDate` set to keep runs incremental. Add a **webhook** to push new reviews into Slack, a database, or your own API the moment a run completes.

#### Option 3 — Call it from your code

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR~zoover-reviews-scraper/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{ "url": "https://www.zoover.nl/a/167199/w-suites-by-estia" }],
    "maxReviews": 100
  }'
```

```javascript
// Node.js — apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('YOUR~zoover-reviews-scraper').call({
    startUrls: [{ url: 'https://www.zoover.nl/a/167199/w-suites-by-estia' }],
    targetDate: '2026-01-01',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].reviews.length, 'reviews');
```

```python
## Python — apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("YOUR~zoover-reviews-scraper").call(run_input={
    "startUrls": [{"url": "https://www.zoover.nl/a/167199/w-suites-by-estia"}],
    "maxReviews": 500,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], len(item["reviews"]))
```

The Actor also works with **Zapier, Make, n8n, LangChain** and any tool that speaks the Apify API.

***

### 📈 Use Cases

#### 1. Reputation monitoring for hotels and campsites

Schedule a daily run with `targetDate` set to yesterday. Every new review lands in your dataset within hours — pipe it to Slack so your front-desk team can respond the same day instead of a week later.

#### 2. Competitor benchmarking

Feed 20 competitor URLs into one run and compare `ratingsPerAspect` side by side. You'll see exactly where you win (location) and where you lose (price/quality) — with the review text explaining why.

#### 3. AI sentiment analysis and LLM training data

Review text arrives clean, typed, and tagged with score, aspect, traveller type and stay date. Drop it straight into a sentiment model, a topic classifier, or an LLM summarisation pipeline. Multilingual out of the box.

#### 4. Travel market research

Scrape accommodations across a region and analyse `ratingDistribution` and `travelPartyDistribution` by destination or season — the kind of dataset that normally costs thousands to license.

#### 5. Lead generation for travel-tech and hospitality suppliers

Every accommodation record carries public contact details — phone, email, website, address and GPS — alongside rating and review volume. Build a targeted prospect list of, say, every 3-star property in Crete rated below 7.5 that clearly needs help with guest experience.

#### 6. Marketing content and social proof

Filter for `score >= 9` and long `textLength`, and you have a library of genuine, quotable guest praise for landing pages, ads and review widgets.

***

### 🛠️ Advanced Tips

**Speed**

- Raise `reviewsPageSize` to `50` or `100`: fewer round-trips means faster runs. The Actor automatically falls back to a safe batch size if the site refuses a large one.
- Getting the page unlocked takes up to ~90 seconds per URL; after that, reviews stream quickly. Long review lists are therefore much cheaper *per review* than short ones.

**Reliability**

- Use **Apify Residential proxies** and set the country to match the Zoover domain. This is the single biggest factor in run success.
- Allocate **4 GB memory** to the run.
- If a proxy IP is blocked, the Actor rotates and retries automatically up to 8 times — no action needed.

**Scaling to hundreds of properties**

- Split large URL lists across several runs (e.g. 20–30 URLs each) so a single problem URL never holds up the batch.
- Use Apify **Schedules** to spread runs across the day rather than one giant run.
- Deduplicate downstream on `reviewId` + `accommodationId`; those two are stable across runs.

**Cost control**

- Use `maxReviews` while testing.
- Use `targetDate` in production so you never re-scrape reviews you already have.

***

### ❓ FAQ & Troubleshooting

**Is scraping Zoover legal?**
This Actor collects only publicly available information — the same content any visitor sees without logging in. It does not access private data or bypass any login. You are responsible for using the data in line with applicable laws (including GDPR when handling reviewer names) and Zoover's terms. For personal data, scrape only what you have a lawful basis to process.

**Do I need a Zoover account or API key?**
No. No login, no cookies, nothing to configure.

**Which Zoover websites are supported?**
zoover.nl, zoover.be, zoover.de, zoover.fr, zoover.es, zoover.it and zoover.co.uk. The Actor automatically matches the language and locale of the domain you provide.

**What URL should I paste?**
Any accommodation page, e.g. `https://www.zoover.nl/a/167199/w-suites-by-estia`. Tab URLs (photos, prices, reviews) work too — they're normalised automatically. Destination and search pages are **not** supported; give it the accommodation page itself.

**"Unrecognised Zoover URL" in the log.**
The URL isn't an accommodation page. Open the property on Zoover and copy the URL that contains `/a/<number>/<name>`.

**The run says the site blocked every connection.**
This means every proxy IP tried was refused. Fix it by: (1) enabling **Apify Residential** proxies, (2) setting the proxy country to match the domain, and (3) re-running — IP availability varies through the day. Datacenter proxies and no-proxy runs will fail often.

**I got fewer reviews than the `reviewCount` on the page.**
Check `totalReviewsAvailable` in the output — that's the number the review API actually serves, and it can be lower than the headline count (some reviews are ratings without text). Also check whether `maxReviews` or `targetDate` capped the run.

**Reviews aren't in English.**
Correct — reviews are returned exactly as guests wrote them, with a `language` field on each. This preserves data fidelity. Translate downstream (e.g. with an LLM or a translation API) if you need one language.

**Can I get one row per review instead of one row per hotel?**
Yes. On the dataset **Export** screen, use the *unwind* option with the field `reviews`, or set `?unwind=reviews` on the API export URL.

**How do I run this daily without duplicates?**
Set `targetDate` to your last run date and deduplicate on `reviewId`.

**How long does a run take?**
Unlocking access takes up to ~90 seconds per URL, then reviews are fetched in batches. A property with a few hundred reviews typically completes in a couple of minutes.

**Why does it need so much memory?**
The Actor launches a real browser to pass the site's protection check. 4 GB keeps that fast and stable.

**Can I get more detailed logs when something goes wrong?**
Yes — switch the input editor to JSON and add `"debug": true`. The run log will then show every internal step (proxy rotation, HTTP status codes, protection handling), which is exactly what to attach to a support request.

**What does it cost?**
You are charged per review scraped, plus standard Apify platform usage. Use `maxReviews` for cheap test runs.

***

### 📞 Support

Questions, bug reports or feature requests are welcome — I actively maintain this Actor.

- 💬 **Issues tab in Apify Console** — the fastest way to report a problem with a specific run. Please include the **run ID** and the URL you scraped.
- 📧 **Email:** <me@ahmedhrid.com>
- 🛠️ **Custom scraping work:** need another review platform, a different data shape, or a private integration? Get in touch — custom Actors are available on request.

If a website change ever breaks the scraper, report it and it will be fixed quickly.

***

### 🔎 Related Keywords

Zoover scraper · Zoover reviews scraper · Zoover API · hotel reviews scraping · travel review data · web scraping Apify actor · guest review extraction · hotel data scraping · leads scraping for hospitality · accommodation data export · review sentiment dataset · scrape hotel reviews to CSV

***

*Not affiliated with, endorsed by, or connected to Zoover. All trademarks belong to their respective owners.*

# Actor input Schema

## `startUrls` (type: `array`):

Zoover accommodation URLs to scrape, e.g. https://www.zoover.nl/a/167199/w-suites-by-estia. Sub-pages of an accommodation (photos, prices, …) are accepted and normalised to the main page.

## `maxReviews` (type: `integer`):

Maximum number of reviews to scrape per URL. 0 means all of them.

## `targetDate` (type: `string`):

Stop once reviews get older than this date (ISO 8601, e.g. 2025-01-01). Zoover returns newest first, so this is the cheap way to run incrementally: set it to the date of your last run.

## `reviewsPageSize` (type: `integer`):

How many reviews to request per call to Zoover's reviews API. Larger batches mean fewer requests through the Cloudflare-protected endpoint. Falls back to 6 (the size Zoover's own site uses) if the API rejects a larger batch.

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

Residential proxy is strongly recommended — the same session is shared between the Cloudflare bypass browser and every reviews request, and the clearance cookie is bound to that exit IP. Pick the country matching the Zoover market you are scraping (NL for zoover.nl) so the IP, timezone and locale all agree.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.zoover.nl/a/167199/w-suites-by-estia"
    }
  ],
  "maxReviews": 0,
  "reviewsPageSize": 25,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NL"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Each record holds the accommodation (zooverId, heliosId, giataId, name, rating out of 10, starRating, reviewCount, per-aspect ratings, rating and travel-party distributions, address, coordinates, breadcrumb, contact details, description, images, facilities, awards, cheapest offer) and a `reviews` array — each review with reviewId, title, text, score out of 10, per-aspect scores, reviewer name/level/verified flag, travel party, published/updated/travel dates, likes, and image URLs.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.zoover.nl/a/167199/w-suites-by-estia"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "NL"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("reviewly/zoover-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 = {
    "startUrls": [{ "url": "https://www.zoover.nl/a/167199/w-suites-by-estia" }],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "NL",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("reviewly/zoover-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 '{
  "startUrls": [
    {
      "url": "https://www.zoover.nl/a/167199/w-suites-by-estia"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NL"
  }
}' |
apify call reviewly/zoover-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reviewly/zoover-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/bgrAq7mNeWCahUNWC/builds/VW3D9zTz5tktjTed2/openapi.json
