# Booksy Scraper - Beauty Salons, Services, Prices & Reviews (`abotapi/booksy-beauty-business-scraper`) Actor

Scrape Booksy beauty businesses across the US, UK and Poland by category, location or URL. Extract business profiles, service menus, prices, durations, photos, opening hours, ratings and client reviews. Supports resume, incremental updates and MCP export.

- **URL**: https://apify.com/abotapi/booksy-beauty-business-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.50 / 1,000 business 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

## Booksy Scraper: Beauty Businesses, Services, Prices & Reviews

Booksy Scraper turns Booksy into a clean beauty-business data API. Get barbershops, hair salons, nail studios, spas and massage therapists with their full priced service menus, durations and discounts, photo galleries, opening hours, business profiles, ratings and nested client reviews. Search by plain category and location names across the United States, United Kingdom and Poland, or paste business links and results links, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

### Why This Scraper?

- **Search the way people talk.** Enter `barber` in `Orlando` or `hair salon` in `London`; the actor resolves plain names through the marketplace's own lookup. No raw ids needed.
- **Full priced service menus by default.** Every business row carries its bookable services with price, duration, deposit and discount fields. No extra toggle, no per-service requests.
- **Nested client reviews.** Reviews attach to the business record as a structured list (rating, text, appointment date, business reply, verified flag), read up to 20 per business by default.
- **Three markets, one actor.** United States, United Kingdom and Poland. A pasted link's locale prefix picks the market automatically; every record carries the marketplace's own resolved location.
- **Every URL shape.** Business links, bare business ids, category-and-location results links with pagination. A link's numeric identifiers decide what it points at, never its readable slug.
- **Built for schedules.** Resume, incremental change detection (NEW / UPDATED / UNCHANGED / EXPIRED) and MCP connector export are built in, and a refused run fails loudly instead of returning an empty dataset.

### Use Cases

- **Beauty suppliers and distributors:** build lead lists of barbershops, salons and spas per city with size signals (review counts, ratings, service counts) and contact links.
- **Service-pricing analysts:** pull full priced menus across cities and markets to benchmark what a fade, balayage or gel manicure costs.
- **Directory builders:** feed marketplace pages, city pages or category pages into the actor and get normalized business records with photos, hours and geolocation.
- **Reputation monitoring:** track ratings, review counts and review text per business on a schedule; incremental mode reports only what changed.
- **Market researchers:** compare category density and pricing between the US, UK and Polish marketplaces with one input change.

### Data You Get

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

| Field | Example |
| --- | --- |
| `recordId` | `"booksy:us:business:147413"` |
| `businessId` | `147413` |
| `name` | `"Sample Barber Shop"` |
| `url` / `bookingUrl` | Booksy link to the business page |
| `market` / `currency` | `"us"` / `"USD"` (also `gb`, `pl`) |
| `primaryCategoryName` | `"Barber"` |
| `address` / `city` / `state` / `zipCode` / `country` | `"2709 Sample Ave."` / `"Orlando"` / `"Florida"` / `"32805"` / `"United States"` |
| `latitude` / `longitude` | `28.51` / `-81.38` |
| `rating` / `reviewsCount` | `4.9` / `329` |
| `serviceCount` / `priceFrom` / `priceTo` | `9` / `30` / `60` |
| `services` | one entry per bookable variant: name, price, durationMin, priceText, discountPercent, deposit, onlineBookable |
| `imageUrl` / `imageCoverUrl` / `imageUrls` | logo, cover and full gallery URLs |
| `description` / `contactName` | profile text and contact person (when profile fetching is on) |
| `openHours` / `openHoursText` | 7-day normalized hours with explicit closed days |
| `website` / `instagramUrl` / `facebookUrl` | business contact links (when profile fetching is on) |
| `bookingPolicy` / `depositPolicy` / `depositCancelDays` | booking and cancellation terms (when profile fetching is on) |
| `staff` / `topServices` / `categories` / `amenities` | profile staff and taxonomy (when profile fetching is on) |
| `reviews` | nested list: reviewId, reviewAuthor, reviewRating, reviewText, reviewCreated, reviewReply, reviewVerified |
| `changeType` / `changedFields` / `firstSeenAt` / `lastSeenAt` | incremental-mode change tracking |

The Output tabs include unwound views: one row per service (Service menus) and one row per review (Client reviews), so flat exports need no post-processing.

### How to Use

1. Pick a **mode**: `search` (category and location names) or `urls` (paste links).
2. Fill in the fields for that mode, and switch on the enrichment you need (profile fetching, reviews).
3. Set **Max items** to control run size and cost, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API.

**Search a category and location:**

```json
{
  "mode": "search",
  "market": "us",
  "locations": ["Orlando", "Tampa"],
  "category": "barber",
  "maxItems": 50,
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviews": 20
}
```

**Two Florida barbershop sweeps with profiles and 20 reviews per business.**

**Paste links:**

```json
{
  "mode": "urls",
  "urls": [
    "https://booksy.com/en-us/s/barber-shop/134763_orlando",
    "https://booksy.com/en-us/147413_sam-at-the-barber-spot_barber-shop_134763_orlando",
    "https://booksy.com/en-gb/s/barber/311817_london",
    "147413"
  ],
  "maxItems": 30,
  "fetchDetails": true,
  "fetchReviews": true
}
```

**A results walk, a US business profile, a London results walk and a bare business id in one run.**

**Narrow a search with a keyword and filters:**

```json
{
  "mode": "search",
  "market": "gb",
  "locations": ["London"],
  "category": "hair salon",
  "searchQuery": "balayage",
  "minRating": 4.5,
  "sortOrder": "price",
  "maxItems": 30,
  "fetchDetails": false,
  "fetchReviews": false
}
```

**London hair salons offering balayage, rated 4.5+, cheapest first, card shape only.**

**Monitor for changes on a schedule:**

```json
{
  "mode": "urls",
  "urls": ["https://booksy.com/en-us/s/barber-shop/134763_orlando"],
  "maxItems": 100,
  "incrementalMode": true,
  "stateKey": "orlando-barbers-weekly",
  "fetchDetails": true,
  "fetchReviews": true
}
```

**A weekly watch of one results page: unchanged businesses are suppressed, changes ship with changedFields.**

#### Run it from your code

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("abotapi/booksy-beauty-business-scraper").call(run_input={
    "mode": "search",
    "locations": ["Orlando"],
    "category": "barber",
    "maxItems": 50,
    "fetchDetails": True,
    "fetchReviews": True,
    "maxReviews": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_dataset_items():
    print(item["name"], item["rating"], item["priceFrom"])
```

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('abotapi/booksy-beauty-business-scraper').call({
    mode: 'search',
    locations: ['Orlando'],
    category: 'barber',
    maxItems: 50,
    fetchDetails: true,
    fetchReviews: true,
    maxReviews: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    console.log(item.name, item.rating, item.priceFrom);
}
```

#### Card vs profile fields

The results feed already carries service menus with prices, galleries and the review summary. Profile fetching adds the written description, opening hours, contacts, booking and deposit policies, amenities and staff. Turn it off for large cheap sweeps; every row carries `detailFetched` so you can tell the shapes apart.

#### Resume and recurring updates

Set `incrementalMode` with a stable `stateKey` on scheduled runs: unchanged businesses are suppressed, changed ones carry `changeType: UPDATED` with `changedFields`, and businesses that disappeared from a complete scan ship as `EXPIRED`. Fields that move without the business changing (the feed's relevance score, promoted flags, review counters, availability flags) are excluded from change detection by default.

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

Add connector IDs under "Send results into your apps" and every collected record is exported after the run (Notion, Google Sheets, Airtable and dozens more through Apify MCP). The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (category and location) or `urls` (paste links). |
| `locations` | array | `["Orlando"]` | Plain city or area names (search mode). |
| `market` | string | `us` | `us`, `gb` or `pl`; which marketplace to search (search mode; pasted links pick their own market). |
| `category` | string | `"barber"` | Plain category name, for example barber, hair salon, nails, massage. Empty searches every category. |
| `searchQuery` | string | (none) | Optional keyword filter, for example `fade` or `balayage`. |
| `sortOrder` | string | `score` | `score`, `price` or `distance`. |
| `minRating` | number | (none) | Keep only businesses rated at least this many stars. |
| `onlineOnly` | boolean | `false` | Keep only businesses that take online bookings. |
| `travelingOnly` | boolean | `false` | Keep only mobile businesses that travel to the client. |
| `urls` | array | one sample per link type | Booksy links (url mode): results links, business links or bare business ids. |
| `fetchDetails` | boolean | `true` | Read each business's own page for description, hours, contacts, policies, staff and the full gallery. |
| `fetchReviews` | boolean | `true` | Collect client reviews into the business record. |
| `maxReviews` | integer | `20` | Upper bound on reviews per business (reviews serve 10 per page); `0` skips review collection. |
| `maxItems` | integer | `20` | Hard cap on business records for the whole run. |
| `maxPages` | integer | `0` | Bounds results pages per location walk; `0` defers to Max items. |
| `proxyConfiguration` | object | Apify Proxy | Connection settings. |
| `resumeFromRunId` | string | (none) | Treat a previous run's records as already collected and skip them. |
| `incrementalMode` | boolean | `false` | Classify NEW / UPDATED / UNCHANGED / EXPIRED against the saved baseline. |
| `stateKey` | string | (none) | Name or share an incremental-mode state. |
| `emitUnchanged` | boolean | `false` | Also return unchanged records. |
| `emitExpired` | boolean | `false` | Also return records a complete scan no longer saw. |
| `ignoreFieldsForChanges` | array | `[]` | Incremental mode only: extra fields excluded from change detection. |
| `mcpConnectors` | array | (none) | Optional: send 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

The Output tab offers one table per view: **Results** (every business), **Business details** (profile fields), **Service menus** (one row per service variant), **Client reviews** (one row per review), plus a **Changes** table (change type, changed fields, first and last seen) for incremental runs.

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

```json
{
  "recordId": "booksy:us:business:147413",
  "kind": "business",
  "businessId": 147413,
  "name": "Sample Barber Shop",
  "market": "us",
  "currency": "USD",
  "primaryCategoryName": "Barber",
  "address": "2709 Sample Ave., Orlando, 32805",
  "city": "Orlando",
  "state": "Florida",
  "zipCode": "32805",
  "country": "United States",
  "latitude": 28.51,
  "longitude": -81.38,
  "rating": 4.9,
  "reviewsCount": 329,
  "serviceCount": 9,
  "priceFrom": 30,
  "priceTo": 60,
  "services": [
    {
      "name": "Sample Cut",
      "price": 40,
      "durationMin": 30,
      "priceText": "$40.00+",
      "discountPercent": 10,
      "onlineBookable": true
    }
  ],
  "openHoursText": "Monday: closed; Tuesday: 12:00-17:00; ...",
  "detailFetched": true,
  "reviewsCollected": true
}
```

### Plan Requirement

The actor ships with the default Apify datacenter connection, which this marketplace serves reliably; for the most reliable long scheduled runs pick Residential under Proxy & connection instead. The run falls back to a backup connection automatically when the default is refused (it logs "Served over the backup connection (the default connection was unavailable)." when that happens). Apify proxy access needs a paid Apify plan. On a plan without residential access the run stops with a clear message instead of an empty result: "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". If nothing could be loaded for another reason you get "Could not load any results page ... This is a connection problem, not an empty search."

This actor is a pay-per-event actor: you are charged per collected business record, per enriched business profile and per business with collected reviews. There are no free-tier claims here; check the Pricing tab on Apify for the exact per-event prices and your plan's tiered rates.

### FAQ

#### How much does it cost to run?

You pay the pay-per-event charges on the Pricing tab (per business record, per enriched profile, per business with reviews) plus your plan's platform usage for compute and proxy. A default 20-business run with profiles and reviews costs a fraction of a cent of platform usage. The actor charges nothing for businesses it could not read or that were suppressed as unchanged.

#### Is it legal to scrape Booksy?

The actor reads publicly available business pages that Booksy serves to every visitor without login. It does not access private accounts, bookings, client records or anything behind authentication. As with any scraper, use the data responsibly and in line with applicable law and the marketplace's terms.

#### Can I get the businesses' phone numbers and email addresses?

No. The marketplace keeps direct phone and email behind its authenticated booking flow, which this actor does not touch. Business websites and social links are included in the profile fields, so you can follow the business's own contact channels.

#### Why do scheduled incremental runs report many NEW records?

The marketplace's recommended feed re-shuffles between runs and rotates which businesses appear first. A run capped below the location's total business count legitimately meets different slices each time. For stable change detection, set Max items at or above the location's business count, or keep incremental mode with a stable State key and treat NEW rows as discovery.

#### Why did my run return fewer results than the location's total?

Max items stops the walk once reached, and a location's total includes businesses that match the category filter less well. Raise Max items or run the same input on a schedule; the marketplace's feed rotates, so successive runs surface additional businesses.

#### How do I monitor businesses for changes?

Turn on incremental mode and keep the same inputs (locations, category, links, toggles) and State key across scheduled runs. A run then logs how many unchanged records it suppressed, and UPDATED means the business actually changed: a price moved, hours changed, the rating dropped.

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

A run that could not read any page fails loudly with a connection message rather than pretending the search was empty. Check the run log: proxy refusals name your plan's connection options, and everything else is a temporary connection problem worth retrying.

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

Yes. The actor works as an MCP server tool through Apify's MCP integration: point your agent at the actor and it can query businesses, service prices and reviews directly. The MCP connectors input also exports collected records to your own apps after each run.

### 🔗 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/pagesjaunes-fr-scraper"><b>PagesJaunes Scraper</b></a><br>Scrape PagesJaunes.fr (French Yellow Pages) business listings across France. Extract...</td></tr>
<tr><td>📇 <a href="https://apify.com/abotapi/hipages-business-scraper"><b>HiPages Scraper</b></a><br>Scrape business listings from HiPages Australia by category, location, or URL. Extract...</td><td>✈️ <a href="https://apify.com/abotapi/naver-map-scraper"><b>Naver Map Scraper</b></a><br>Scrape Naver Map places by keyword or URL: names, categories, ratings, phones, addresses...</td></tr>
<tr><td>🧩 <a href="https://apify.com/abotapi/yandex-maps-scraper"><b>Yandex Maps Scraper</b></a><br>Scrape Yandex Maps businesses and places by keyword or URL for lead generation, research...</td><td>🛒 <a href="https://apify.com/abotapi/doordash-scraper"><b>DoorDash Scraper</b></a><br>Extract structured doordash.com data at scale. Search by keyword or paste store URLs to...</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/booksy-beauty-business-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 by category and location names, or paste your own links: category-and-location results pages walk forward, a business link (or a bare business id) is always read in full.

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

Plain city or area names, for example Orlando, London, Warszawa. Each location runs on the selected market. Supported markets: United States, United Kingdom, Poland.

## `market` (type: `string`):

The marketplace to search (each market has its own businesses, locations and categories). Search mode uses this market; pasted links pick their own market from their locale prefix.

## `category` (type: `string`):

Plain category name, for example barber, hair salon, nails, massage, skin care, brows and lashes, makeup, tattoo, braids and locs. Leave empty to search every category.

## `searchQuery` (type: `string`):

Optional keyword filter, for example 'fade', 'balayage', 'gel'. Narrow the results feed server-side.

## `sortOrder` (type: `string`):

Order of the results feed.

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

Keep only businesses rated at least this many stars (applied to the collected rows).

## `onlineOnly` (type: `boolean`):

Keep only businesses that take online bookings.

## `travelingOnly` (type: `boolean`):

Keep only businesses that travel to the client.

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

Category-and-location results links (they walk forward), business links (always read in full; the link's locale also picks the market) or bare business ids. A link's numeric identifiers decide what it points at - its readable slug never does.

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

Read each collected business's own page for the written description, opening hours, contacts (website, social), booking and deposit policies, amenities, staff, categories and the full photo gallery. Turning this off returns the faster results-card shape (service menus with prices are on the card either way).

## `fetchReviews` (type: `boolean`):

Read each collected business's client reviews (rating, text, appointment date, business reply) and attach them to the business record as a nested list. Applies to both modes; a business with no published reviews ships without them.

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

Upper bound on client reviews collected per business (reviews serve 10 per page). 0 skips review collection entirely.

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

Hard cap on business records for the whole run. The walk stops once it is reached.

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

Does NOT cap the run on its own: 0 or empty walks every results page and defers to Max items. A positive value bounds how many results pages each location walk covers.

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

The marketplace is served worldwide from every connection type; the default datacenter connection keeps runs cheap. For the most reliable long scheduled runs pick Residential instead - the run falls back to a backup connection automatically and tells you in the log.

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

A previous run's ID whose records are treated as already collected: they are seeded as seen and skipped this run.

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

Compare each business against the saved baseline and classify NEW / UPDATED / UNCHANGED / EXPIRED. Unchanged businesses are suppressed unless Emit unchanged is on. Fields that move without the business changing (the feed's relevance score and promoted flags, review counters, availability flags) are excluded from change detection; the locations, category, market, links and toggles you run with are part of the scope, so changing them starts a fresh baseline.

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

Optional name for the incremental baseline. Leave empty to derive it from the run's scope (locations, category, market, links, toggles); set the same key on every scheduled run to share one baseline.

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

Also push businesses whose tracked fields did not change (changeType UNCHANGED) instead of suppressing them.

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

After a complete scan, push baseline businesses this run did not see (changeType EXPIRED, for example businesses that closed). Never fires on a capped, resumed or partially failed walk.

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

Extra record fields excluded from change detection beyond the built-in volatile set (relevance score, distance, promoted flag, review counters, availability flags).

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

Connector IDs to export the collected records to after the run (Apify MCP). Leave empty to skip the export.

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

Parent page URL when one of the connectors is Notion.

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

Upper bound on records handed to each connector.

## Actor input object example

```json
{
  "mode": "search",
  "locations": [
    "Orlando"
  ],
  "market": "us",
  "category": "barber",
  "sortOrder": "score",
  "onlineOnly": false,
  "travelingOnly": false,
  "urls": [
    "https://booksy.com/en-us/s/barber-shop/134763_orlando",
    "https://booksy.com/en-us/147413_sam-at-the-barber-spot_barber-shop_134763_orlando",
    "https://booksy.com/en-gb/s/barber/311817_london",
    "https://booksy.com/en-gb/59331_bobby-khokhar-celebrity-barber_barber_311817_london",
    "147413"
  ],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviews": 20,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

Every business collected by the run.

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

Profile fields from each business's own page.

## `services` (type: `string`):

Every bookable service variant, one row per service.

## `reviews` (type: `string`):

Client reviews unwound one row per review.

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

Change classification per business when incremental mode is on.

# 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 = {
    "locations": [
        "Orlando"
    ],
    "category": "barber",
    "urls": [
        "https://booksy.com/en-us/s/barber-shop/134763_orlando",
        "https://booksy.com/en-us/147413_sam-at-the-barber-spot_barber-shop_134763_orlando",
        "https://booksy.com/en-gb/s/barber/311817_london",
        "https://booksy.com/en-gb/59331_bobby-khokhar-celebrity-barber_barber_311817_london",
        "147413"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/booksy-beauty-business-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 = {
    "locations": ["Orlando"],
    "category": "barber",
    "urls": [
        "https://booksy.com/en-us/s/barber-shop/134763_orlando",
        "https://booksy.com/en-us/147413_sam-at-the-barber-spot_barber-shop_134763_orlando",
        "https://booksy.com/en-gb/s/barber/311817_london",
        "https://booksy.com/en-gb/59331_bobby-khokhar-celebrity-barber_barber_311817_london",
        "147413",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/booksy-beauty-business-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 '{
  "locations": [
    "Orlando"
  ],
  "category": "barber",
  "urls": [
    "https://booksy.com/en-us/s/barber-shop/134763_orlando",
    "https://booksy.com/en-us/147413_sam-at-the-barber-spot_barber-shop_134763_orlando",
    "https://booksy.com/en-gb/s/barber/311817_london",
    "https://booksy.com/en-gb/59331_bobby-khokhar-celebrity-barber_barber_311817_london",
    "147413"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/booksy-beauty-business-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/booksy-beauty-business-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/IN09G8TKGYIqw50hS/builds/B7bpzfatOYnkDOVYp/openapi.json
