# Treatwell UK Scraper - Salons, Spas & Barbers (`abotapi/treatwell-co-uk-scraper`) Actor

Scrape Treatwell UK salon, spa and barber listings by city and treatment: ratings, address and coordinates, phone, opening hours, galleries, full service menus with prices, amenities, staff and customer reviews. Search by location or paste venue and results page links.

- **URL**: https://apify.com/abotapi/treatwell-co-uk-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 venue records

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Treatwell UK Scraper: Salons, Spas and Barbers

Treatwell UK Scraper turns Treatwell (treatwell.co.uk) into a clean beauty and wellness data feed. Get salon, spa and barber listings by city and treatment with ratings and sub-scores, full addresses with coordinates, opening hours, photo galleries and service menus with prices and durations. Search by location or paste venue and results page links.

### Why This Scraper?

- **Two ways in.** Search by city and treatment with plain names (haircuts in London, massage in Manchester), or paste Treatwell links: results pages, brand and chain pages, single venue pages and service group pages.
- **Rich venue rows.** Name, venue type, tags, awards, full address, postcode, map coordinates and phone on every row.
- **Ratings with detail.** Average rating, review count and the sub-scores, the whole photo gallery and opening hours for all seven weekdays.
- **Complete service menus with prices.** Every service with sale and full prices, discount flags and durations, plus amenities, staff and a price range per venue.
- **Customer reviews on the venue row.** The newest reviews (default 20) with reviewer, rating, text, visit date, treatments and staff member, nested on each venue.
- **Recurring updates.** Run the same search on a schedule and get only new, changed or removed venues.
- **Filters that narrow before the limit.** Minimum rating and minimum review count are applied before Max items, so a capped run returns qualifying venues only.

### Use Cases

- **Lead generation for suppliers:** build lists of salons, spas and barbers by city and treatment with addresses and ratings.
- **Market research:** map venue density, price ranges and ratings across UK cities and treatment types.
- **Price benchmarking:** compare service prices, discounts and durations across venues.
- **Local SEO and directories:** enrich a directory with photos, opening hours and coordinates.
- **AI agents and dashboards:** feed structured venue data into your own tools.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `venueId` | `100000` |
| `name` / `businessName` | `"Sample Hair Studio"` |
| `url` / `placeUrl` | Link to the venue page |
| `businessType` / `category` / `subCategory` | `"Hair Salon"` / `"Hair"` / `"Beauty Salon"` |
| `tags` / `accolades` | `["Top Rated 2026", "Hair Salon"]` / `["Top Rated 2026"]` |
| `address` / `street` / `city` / `region` | full address / `"1 Sample Road"` / `"London"` / `"London"` |
| `postalCode` / `country` / `countryCode` | `"AA1 1AA"` / `"United Kingdom"` / `"GB"` |
| `latitude` / `longitude` / `coordinates` / `location` | `51.5` / `-0.12` / `{ "lat": 51.5, "lon": -0.12 }` / address, coordinates, postal code and area |
| `rating` | average, count and per-dimension scores |
| `ratingValue` / `reviewCount` / `ratingDimensions` | `4.6` / `120` / `Cleanliness`, `Staff`, `Ambience` scores |
| `imageUrl` / `images` | main photo / full gallery |
| `openingHours` | seven weekdays with open flag and times |
| `descriptionHtml` / `basicInfo` | description as HTML / id, name, description text, venue link |
| `services` / `allServices` | name, description, prices, discount, duration, categories |
| `treatments` / `topTreatments` / `priceFrom` / `priceTo` / `priceRange` / `currency` | service names / top three / `10` / `90` / `"£10 - £90"` / `"GBP"` |
| `newVenue` / `mobile` | `false` / `false` |
| `phone` | Venue phone number |
| `chainName` / `chainId` / `chainUrl` | Chain the venue belongs to, when it does |
| `amenities` / `amenityGroups` | `["Free Wifi", "Wheelchair access"]` / the same grouped |
| `staff` | Team members with name, title and photo |
| `menu` / `menuItemCount` | Complete menu grouped by section, with prices and durations / number of services |
| `reviews` / `reviewsDelivered` | Nested customer reviews, newest first / how many are on the row |
| `publishedDate` / `searchUrl` / `scrapedAt` | Listing date / the page the venue came from / collection time |
| `changeType` / `changedFields` / `firstSeenAt` / `lastSeenAt` | Incremental mode only |

### How to Use

1. Pick a **mode**: `search` for city and treatment, or `url` for pasted results page links.
2. For search, enter one or more locations and optional treatments. For links, paste Treatwell results pages, or leave the shipped example in place for a first test run.
3. Set **Max items** to control run size, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API.

**Search by city and treatment:**

```json
{
  "mode": "search",
  "locations": ["London"],
  "treatments": ["Haircuts and hairdressing"],
  "maxItems": 20
}
```

**Best discounts in several cities, well-rated only:**

```json
{
  "mode": "search",
  "locations": ["Manchester", "Leeds"],
  "sortBy": "DISCOUNT",
  "minRating": 4.5,
  "minReviews": 50,
  "maxItems": 40
}
```

**Paste any Treatwell link (results page, brand page, chain page, venue page or service group page):**

```json
{
  "mode": "url",
  "urls": [
    "https://www.treatwell.co.uk/places/brand-olaplex/in-london-uk/",
    "https://www.treatwell.co.uk/place/lili-london/",
    "https://www.treatwell.co.uk/hairdressers-and-hair-salons/"
  ],
  "maxItems": 30
}
```

**Daily monitoring of one search (only what changed):**

```json
{
  "mode": "search",
  "locations": ["London"],
  "treatments": ["Haircuts and hairdressing"],
  "incrementalMode": true,
  "maxItems": 200
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/treatwell-co-uk-scraper").call(run_input={"mode": "search", "locations": ["London"], "maxItems": 20})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["ratingValue"], item["reviewCount"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/treatwell-co-uk-scraper').call({ mode: 'search', locations: ['London'], maxItems: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Locations and treatments

Locations are UK cities or areas typed as plain names (`London`, `Manchester`, `Clapham London`). Leave them empty or type `UK` to search the whole country. Treatments accept plain names (`Massage`, `Gel nails`) or slugs; several treatments are combined into one search. A name that does not match is reported in the run log, and a run where nothing matches fails with a message instead of returning an empty dataset; paste a results page link in URL mode as the fallback.

#### Which links work in URL mode

Results pages (`/places/...` with a treatment and city, an optional sort and `page-N`), brand, chain and venue-type pages, single venue pages (`/place/...`) and service group pages such as `/hairdressers-and-hair-salons/`. A results page continues forward from the page in the link, and a link without its own sort uses the **Sort results by** input. Other pages (home, gift cards, information pages, other countries) are skipped with a warning.

#### Reviews

With full details on, each venue carries its newest reviews (**Max reviews per venue**, default 20, `0` skips them). Reviews are nested on the venue row, never separate dataset items.

#### Recurring updates (incremental mode)

Turn on **Incremental changes for scheduled runs** to run the same search every day and receive only `NEW`, `UPDATED` and `REAPPEARED` venues. `changedFields` names what changed. A new review alone does not make a venue `UPDATED`; a change in `reviewCount` or `rating` does. Venues that disappeared are returned as `EXPIRED` once a run has scanned the whole search (not when **Max items**, **Max pages** or **Resume** cut it short). **Emit unchanged venues** returns the unchanged rows as well. Venues left out as unchanged are neither returned nor billed. **Resume from a previous run** continues one interrupted run by its run or dataset id.

#### How `maxItems` shapes a run

Results come in pages of 20 venues. A run stops once `maxItems` is reached. With several locations the limit is shared evenly so every location gets a turn. Set `maxItems` to `0` to collect everything the searches return.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape: the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record, not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

At most `maxNotifyListings` items (default 50) are written to each connector per run; this cap never affects the dataset. The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip the export.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` by location and treatment, or `url` for pasted results page links. |
| `locations` | array | `["London"]` | UK cities or areas (search mode). Empty or `UK` means the whole country. |
| `treatments` | array | (none) | Treatment names or slugs; several are combined into one search. Empty means every venue type. |
| `sortBy` | string | `RECOMMENDED` | `RECOMMENDED`, `PRICE_ASC`, `PRICE_DESC` or `DISCOUNT`. |
| `minRating` | number | (none) | Keep venues with an average rating at or above this value, applied before Max items. |
| `minReviews` | integer | (none) | Keep venues with at least this many reviews, applied before Max items. |
| `urls` | array | one link per kind | Treatwell venue, results, brand, chain and group page links (URL mode). Results start from the page in the link. |
| `fetchDetails` | boolean | `true` | Include phone, amenities, staff, the complete menu, full gallery, description and reviews. Off gives compact rows. |
| `maxReviews` | integer | `20` | Reviews per venue, newest first (`0` skips, up to 1000). Needs full details on. |
| `maxPages` | integer | unlimited | Results pages per search; blank or `0` means unlimited and does not cap results. |
| `maxItems` | integer | `20` | Stop after this many venues (`0` means no limit). The only result limit. |
| `proxy` | object | Apify proxy | Connection settings (see Plan Requirement). |
| `resumeFromRunId` | string | (none) | Continue one interrupted run by its run or dataset id. |
| `incrementalMode` | boolean | `false` | Return only new, updated and reappeared venues on repeat runs. |
| `stateKey` | string | (auto) | Name a monitoring campaign (incremental mode). |
| `emitUnchanged` | boolean | `false` | Also return unchanged venues (incremental mode). |
| `emitExpired` | boolean | `true` | Return venues that disappeared after a complete scan (incremental mode). |
| `ignoreFieldsForChanges` | array | (none) | Fields that never count as a change (incremental mode). |
| `mcpConnectors` | array | (none) | Optional: send a summary of each record to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which records are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

**Venue record:**

```json
{
  "venueId": 100000,
  "name": "Sample Hair Studio",
  "url": "https://www.treatwell.co.uk/place/sample-hair-studio/",
  "businessType": "Hair Salon",
  "category": "Hair",
  "subCategory": "Beauty Salon",
  "tags": ["Top Rated 2026", "Hair Salon"],
  "address": "1 Sample Road, Sample Area, London, AA1 1AA",
  "city": "London",
  "postalCode": "AA1 1AA",
  "country": "United Kingdom",
  "latitude": 51.5,
  "longitude": -0.12,
  "rating": { "average": 4.6, "count": 120, "dimensions": [{ "name": "Staff", "average": 4.6, "count": 100 }] },
  "ratingValue": 4.6,
  "reviewCount": 120,
  "openingHours": [{ "day": "monday", "open": true, "from": "09:00", "to": "18:00" }],
  "services": [{ "name": "Haircut and blow dry", "priceFrom": 40, "priceTo": 60, "durationMinutesFrom": 60, "durationMinutesTo": 75 }],
  "priceFrom": 10,
  "priceTo": 90,
  "priceRange": "£10 - £90",
  "currency": "GBP"
}
```

### Plan Requirement

The default connection is Apify Proxy, and it needs a plan that includes proxy access. The actor tries these connections in order and tells you in the run log what it used:

1. Apify datacenter proxy (the default).
2. Apify residential proxy, tried when the datacenter connection is refused or fails. Apify free plans do not include residential proxies.
3. A backup residential connection.
4. A backup datacenter connection as the last resort.

What you will see in the run log:

- When the residential connection is refused for your account, a boxed warning once: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs."
- When a request is served by a backup connection: "Served over the backup connection (the default connection was unavailable)."

A run that could not read any page ends as failed, never as an empty success, with one of these messages:

- Every connection refused: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid."
- Free plan, backup connection reachable but no usable page: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Treatwell pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again."
- Any other run where no page loaded: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

### FAQ

#### How much does it cost?

You pay per venue returned, plus a detail charge for each venue returned with full details and a charge for each review returned on it. Switch **Include full details** off for a compact row with neither. The charges are only for rows you actually receive: in incremental mode, unchanged venues left out are not billed. The **Pricing** tab shows the current rates. Use **Max items** and **Max reviews per venue** to cap the cost of any run.

#### Is it legal to scrape Treatwell?

This actor collects only publicly available listing data: venue names, addresses, ratings, opening hours, photos and service prices. You are responsible for how you use it: follow Treatwell's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.

#### Can I run it on a schedule?

Yes. Schedule the actor from the **Schedules** tab with the same input to refresh a city on a regular basis.

#### Why did a run return fewer venues than the website shows?

The run stops at **Max items**, and the minimum rating and review filters remove venues that do not qualify. Raise the limit, or set it to `0`, to collect more.

#### Why did my run fail instead of returning an empty dataset?

If not a single page could be read, the run fails with a message describing the connection problem, so "no results" is never confused with "nothing could be read". Try again later or switch the Connection setting.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

### 🔗 More scrapers you might like

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🧩 <a href="https://apify.com/abotapi/fresha-salon-spa-scraper"><b>Fresha Scraper</b></a><br>Scrape Fresha salon and spa listings: business profiles, service menus with prices and...</td><td>🧩 <a href="https://apify.com/abotapi/booksy-beauty-business-scraper"><b>Booksy Scraper</b></a><br>Scrape Booksy beauty businesses across the US, UK and Poland by category, location or...</td></tr>
<tr><td>🏠 <a href="https://apify.com/abotapi/rightmove-scraper"><b>Rightmove UK Scraper</b></a><br>Fast, reliable Rightmove.co.uk scraper for UK properties for sale, rent and sold-price...</td><td>🔌 <a href="https://apify.com/abotapi/currys-co-uk"><b>Currys UK Scraper</b></a><br>Scrape Currys UK products, including electronics, home appliances, computers, TVs and...</td></tr>
<tr><td>💼 <a href="https://apify.com/abotapi/jobsite-co-uk-scraper"><b>Jobsite UK Scraper</b></a><br>Scrape Jobsite.co.uk job listings at scale by keyword, location, filters or URL. Extract...</td><td>🧩 <a href="https://apify.com/abotapi/zoopla-co-uk-scraper"><b>Zoopla Scraper</b></a><br>Scrape UK property from Zoopla: for sale, to rent and Land Registry sold prices. Search...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/treatwell-co-uk-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

Search mode builds results from the locations and treatments below. URL mode reads the venue and results page links you paste.

## `locations` (type: `array`):

Cities or areas in the UK, typed as plain names, e.g. London, Manchester, Clapham. Leave empty or type UK for the whole country. A name Treatwell does not recognise is reported in the log; paste a results page link in URL mode instead. Search mode only.

## `treatments` (type: `array`):

Treatment names, e.g. Haircuts and hairdressing, Massage, Gel nails, Facials. Several treatments are combined into one search. Leave empty for every venue type. A name Treatwell does not recognise is reported in the log; paste a results page link in URL mode instead.

## `sortBy` (type: `string`):

Ordering of the results pages.

## `minRating` (type: `number`):

Keep only venues with an average rating at or above this value (0 to 5). Filtered before the item limit.

## `minReviews` (type: `integer`):

Keep only venues with at least this many reviews. Filtered before the item limit.

## `urls` (type: `array`):

Multi-URL. Treatwell links (treatwell.co.uk): a results page (a treatment and city, with an optional sort or page-N), a brand or chain page, a single venue page (/place/...), or a service group page such as /hairdressers-and-hair-salons/. A results page starts from the page in the link, and a link without its own sort uses the Sort input. Search fields other than Sort are ignored in this mode.

## `fetchDetails` (type: `boolean`):

Adds the phone number, amenities, staff, the complete service menu with prices and durations, the full photo gallery, the description and customer reviews to every venue. Turn off for a compact row per venue.

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

Customer reviews to attach to each venue, newest first (reviewer, rating, text, visit date, treatments). 0 skips reviews. Needs full details switched on.

## `maxPages` (type: `integer`):

Optional. Empty or 0 means unlimited pages. This does NOT cap results and defers to Max items.

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

The only result limit. Total venues returned across all searches. 0 means unlimited.

## `proxy` (type: `object`):

Datacenter proxies are the default and work on every plan (measured working on every page this actor reads). Residential proxies are recommended for the most reliable results on large or frequent runs. If the connection is refused, the actor escalates automatically through backup connections, including residential ones; that residential traffic is billed to your Apify plan when it engages. The run always uses a proxy unless you explicitly turn it off here or supply your own proxy URLs.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large pull without returning or charging for venues already collected there. Use this after an interrupted run. For recurring daily monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns every matching venue as NEW. Later runs return only NEW, UPDATED and REAPPEARED venues, which is how a new menu price or a changed rating is spotted. Turn on Emit unchanged only when you also want unchanged venues returned (and billed). State is kept separately for each search, filter and detail setup; use State key to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search, filters and detail settings, so different searches never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return venues that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you want the full snapshot every run.

## `emitExpired` (type: `boolean`):

On by default. Returns venues that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, so never when Max items or Max pages capped it or when Resume was used. Turn off to skip these rows.

## `ignoreFieldsForChanges` (type: `array`):

Incremental mode only. Fields whose changes do not count as an update: a change in them alone leaves the venue UNCHANGED and they are not listed in changedFields. They are still returned in every row. Use a dotted path for a nested field, for example rating.count. Customer reviews and the scrape time are always ignored; a new review still shows through reviewCount and rating. Add more field names here to ignore them as well, for example openingHours.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify → Settings → API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "locations": [
    "London"
  ],
  "treatments": [
    "Haircuts and hairdressing"
  ],
  "sortBy": "RECOMMENDED",
  "urls": [
    "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-london-uk/",
    "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-manchester-uk/sort-price-asc/page-2/",
    "https://www.treatwell.co.uk/places/brand-olaplex/in-london-uk/",
    "https://www.treatwell.co.uk/places/chain-live-true-london/",
    "https://www.treatwell.co.uk/place/lili-london/",
    "https://www.treatwell.co.uk/hairdressers-and-hair-salons/"
  ],
  "fetchDetails": true,
  "maxReviews": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": true,
  "ignoreFieldsForChanges": [],
  "mcpConnectors": [],
  "notionParentPageUrl": "",
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `detail` (type: `string`):

No description

## `changes` (type: `string`):

No description

# 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 = {
    "mode": "search",
    "locations": [
        "London"
    ],
    "treatments": [
        "Haircuts and hairdressing"
    ],
    "urls": [
        "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-london-uk/",
        "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-manchester-uk/sort-price-asc/page-2/",
        "https://www.treatwell.co.uk/places/brand-olaplex/in-london-uk/",
        "https://www.treatwell.co.uk/places/chain-live-true-london/",
        "https://www.treatwell.co.uk/place/lili-london/",
        "https://www.treatwell.co.uk/hairdressers-and-hair-salons/"
    ],
    "fetchDetails": true,
    "maxReviews": 20,
    "maxItems": 20,
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/treatwell-co-uk-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 = {
    "mode": "search",
    "locations": ["London"],
    "treatments": ["Haircuts and hairdressing"],
    "urls": [
        "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-london-uk/",
        "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-manchester-uk/sort-price-asc/page-2/",
        "https://www.treatwell.co.uk/places/brand-olaplex/in-london-uk/",
        "https://www.treatwell.co.uk/places/chain-live-true-london/",
        "https://www.treatwell.co.uk/place/lili-london/",
        "https://www.treatwell.co.uk/hairdressers-and-hair-salons/",
    ],
    "fetchDetails": True,
    "maxReviews": 20,
    "maxItems": 20,
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": True,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/treatwell-co-uk-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 '{
  "mode": "search",
  "locations": [
    "London"
  ],
  "treatments": [
    "Haircuts and hairdressing"
  ],
  "urls": [
    "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-london-uk/",
    "https://www.treatwell.co.uk/places/treatment-haircuts-and-hairdressing/offer-type-local/in-manchester-uk/sort-price-asc/page-2/",
    "https://www.treatwell.co.uk/places/brand-olaplex/in-london-uk/",
    "https://www.treatwell.co.uk/places/chain-live-true-london/",
    "https://www.treatwell.co.uk/place/lili-london/",
    "https://www.treatwell.co.uk/hairdressers-and-hair-salons/"
  ],
  "fetchDetails": true,
  "maxReviews": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": true
}' |
apify call abotapi/treatwell-co-uk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/treatwell-co-uk-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/kCoqgEcXT8JupomGl/builds/W4oMFbE8wxa1q07zp/openapi.json
