# Bokadirekt Scraper (`normdata/bokadirekt-scraper`) Actor

Scrape 17,000+ beauty and wellness businesses from Bokadirekt, Sweden's biggest booking marketplace: phone, email, website, Instagram, org numbers, opening hours, full price list, and ratings. Filter by service, city, free slots, payment options, rating, and missing website.

- **URL**: https://apify.com/normdata/bokadirekt-scraper.md
- **Developed by:** [Norm Data](https://apify.com/normdata) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.40 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/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

![Norm Data](https://i.ibb.co/rGbhM5Y8/Chat-GPT-Image-Sep-8-2026-02-20-50-PM.png)

## 💇 Bokadirekt Beauty & Wellness Businesses Scraper

Search **Bokadirekt**, Sweden's biggest booking marketplace for beauty and wellness, and get a clean list of salons, barbers, massage therapists, nail and lash studios, clinics, and more. Every business comes with its phone, email, website, Instagram, company organisation numbers, opening hours, full price list, ratings, and booking options. No login, no account.

Built for B2B lead generation, local market research, and price benchmarking across more than 17,000 Swedish businesses.

### 🎯 Who uses it?

#### 🧴 Suppliers and wholesalers

Build a call list of salons and clinics by service and city, with a direct phone number and email on almost every row.

#### 💻 SaaS and marketing agencies

Find businesses by Bokadirekt plan, rating, review volume, or missing website, and pitch the ones that need you most.

#### 📊 Market researchers

Compare prices, opening hours, and service mix across cities and categories from each business's own price list.

#### 🏦 Payments and finance teams

See which businesses already offer pay later, gift cards, or the employer wellness allowance, and which do not.

### ✨ What it does

- **Search:** 27 service categories plus any other service keyword in Swedish, in any city, municipality, or district, or around a map point.
- **Availability filters:** only businesses with a free slot on chosen dates and time of day, or only last-minute deals.
- **Offer and payment filters:** active campaigns, multi-visit bundles, pay later with Klarna or Qliro, gift cards, the employer wellness allowance, and trade association membership.
- **Lead quality filters:** minimum rating, minimum number of reviews, only businesses with an email, a website, or Instagram, or only those without their own website.
- **Sorting:** most popular, best rated, closest, soonest availability, highest discount, or highest last-minute discount.
- **Look up:** resolve known business profiles directly from their Bokadirekt URL or ID.
- **Location check:** a misspelled place name stops the run with suggestions, instead of quietly returning all of Sweden.

Missing source values are returned as `null`, never invented.

### Why this scraper

- **Direct contact details on almost every row.** Phone on every business, email on over 90%, website and Instagram where published.
- **Company organisation numbers,** ready to match against company registers and your CRM.
- **The full price list,** every service with price, duration, and category, plus lowest and highest price per business.
- **Booking and payment signals** you won't find in a map listing: Bokadirekt plan, pay later, wellness allowance, gift cards, campaigns, and last-minute discounts.
- **Privacy by design.** Business data only: no staff names, no reviewer names, and no sole trader personal identity numbers.

### How it compares

| Capability | This actor | Generic maps or directory scrapers |
|---|:--:|:--:|
| Phone and website | yes | yes |
| **Email address** | **yes, over 90%** | rarely |
| **Company organisation numbers** | **yes** | no |
| **Full price list with durations** | **yes** | no |
| **Opening hours per day** | **yes** | yes |
| Rating and review count | yes | yes |
| **Rating distribution, 1 to 5 stars** | **yes** | no |
| **Pay later, wellness allowance, gift card, campaign flags** | **yes** | no |
| **Free slot by date and time of day** | **yes** | no |
| Staff count and roles | yes | no |

### 📦 What data you get

| Entity | Useful fields |
| --- | --- |
| Business | Name, logo, description, categories, trade associations, notices, group name, and Bokadirekt plan. |
| Contact | Phone, email, website, Instagram, and the Bokadirekt profile link. |
| Location | Street, post code, city, latitude, and longitude. |
| Company | Every company organisation number operating at the business. |
| Opening hours | Hours for each day of the week, plus the business's own note on hours. |
| Price list | Every service with category, price in SEK, price label, duration in minutes, add-on flag, and description. |
| Ratings | Average rating, review count, and the 1 to 5 star distribution. |
| Staff | Number of active staff and their job titles, with no names. |
| Booking and offers | Instant booking, cancellation notice, last-minute discount, first free slot, campaigns, and multi-visit bundles. |
| Payments | Pay later with Klarna or Qliro, gift cards, wellness allowance, and prepayment requirement. |

Every record includes `scraped_at` (UTC). Download your dataset from Apify as CSV, JSON, Excel, or XML.

### 💡 Use cases

#### 🧴 Every hair salon in Stockholm with an email address

```json
{ "mode": "search", "categories": ["Frisör"], "locations": ["Stockholm"], "requireEmail": true }
```

#### 💻 Highly rated clinics without their own website

```json
{ "mode": "search", "categories": ["Hudvård", "Laser"], "minRating": "4.7", "minReviews": "50", "website": "none", "maxItems": 500 }
```

#### 📊 Massage businesses accepting the wellness allowance in Göteborg

```json
{ "mode": "search", "categories": ["Massage"], "locations": ["Göteborg"], "acceptsWellnessCard": true }
```

#### ⏰ Nail studios with a free evening slot this week

```json
{ "mode": "search", "categories": ["Naglar"], "locations": ["Malmö"], "timeOfDay": "evening", "availableFrom": "2026-09-28", "availableTo": "2026-10-02" }
```

#### 🔎 Resolve known profiles

```json
{ "mode": "lookup", "placeUrls": ["https://www.bokadirekt.se/places/queeings-frisor-barbershop-136216"] }
```

### ⚙️ How the input is organised

**Maximum results** sits at the very top, since it applies no matter what you're doing. Leave it empty to collect every match. Below it, the form is split into seven numbered sections:

| Section | What it's for |
| --- | --- |
| **1 · What to do** | Search for businesses or look up known profiles. |
| **2 · What and where** | Service categories, other service keywords, locations, or a map point. |
| **3 · Availability and offers** | Free slots by date and time of day, last-minute deals, campaigns, and bundles. |
| **4 · Payments and trust** | Pay later, gift cards, wellness allowance, and trade association membership. |
| **5 · Lead quality** | Minimum rating and reviews, requiring an email, website, or Instagram, or only businesses without a website. |
| **6 · Order** | How results are sorted. |
| **7 · Look up** | Business profile URLs or IDs to resolve directly. |

> **Apify Free plan:** every run is limited to a fixed 10-row sample. Upgrade your Apify plan to run your own settings.

### 🛡️ Limits & responsible use

This Actor reads only public Bokadirekt business profiles. It never signs in and never accesses anything gated behind an account.

It collects business information only. Staff names, reviewer names, and personal identity numbers that Swedish sole traders use as their organisation number are left out on purpose. Business contact details are still covered by the GDPR and by Bokadirekt's terms, so use them for relevant B2B outreach, respect opt-outs, and do not republish the content.

Around 1,000 full business profiles load in under a minute, and the whole marketplace of more than 17,000 businesses in well under half an hour. Searches are paced to stay gentle on the source.

A profile that doesn't resolve in Look up mode writes a row with an `error` field instead of failing the run.

### 📧 Contact

Need a scraper for a different site, or found something wrong with this one? norm.data.scrapers@gmail.com

### Local development

```bash
bun install
bun test
bun run src/main.ts
```

# Changelog

This Actor's version history is a separate document: https://apify.com/normdata/bokadirekt-scraper/changelog.md

# Actor input Schema

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

Caps how many businesses this run writes. Leave empty to collect every match.

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

Search builds a list of businesses. Look up resolves specific known profiles directly.

## `categories` (type: `array`):

One or more service categories. Leave empty, with no keywords, to search every business.

## `keywords` (type: `array`):

Any other service in Swedish, e.g. "Balayage", "Lash lift", "Microneedling". Each keyword is searched on its own and the results are merged.

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

Swedish cities, municipalities, or districts, e.g. "Göteborg", "Södermalm", "Uppsala". Leave empty for all of Sweden. An unknown name stops the run with suggestions instead of silently searching the whole country.

## `nearPoint` (type: `string`):

Search around a map point instead of a named location. Paste the coordinates exactly as Google Maps copies them, e.g. 59.3293, 18.0686 (right-click a spot in Google Maps and click the numbers).

## `availableFrom` (type: `string`):

Only businesses with a free booking slot from this date.

## `availableTo` (type: `string`):

Only businesses with a free booking slot up to this date. Defaults to the same day as Available from.

## `timeOfDay` (type: `string`):

Only businesses with a free slot at this time of day.

## `lastMinuteOnly` (type: `boolean`):

Only businesses currently offering discounted last-minute slots.

## `hasCampaigns` (type: `boolean`):

Only businesses with an active discount campaign.

## `hasBundles` (type: `boolean`):

Only businesses selling punch cards or multi-visit bundles.

## `payLater` (type: `boolean`):

Only businesses that accept pay later.

## `acceptsGiftCard` (type: `boolean`):

Only businesses that accept gift cards.

## `acceptsWellnessCard` (type: `boolean`):

Only businesses that accept payment with the Swedish employer wellness allowance (friskvårdsbidrag).

## `tradeAssociationOnly` (type: `boolean`):

Only businesses that belong to a professional trade association, such as Frisörföretagarna or the Swedish skin therapists' association.

## `minRating` (type: `string`):

Only businesses rated at least this. Most businesses on Bokadirekt score above 4.5, so the useful cut-offs are high.

## `minReviews` (type: `string`):

Only businesses with at least this many reviews, a good sign of an established business.

## `requireEmail` (type: `boolean`):

Only businesses that publish an email address.

## `website` (type: `string`):

Filter on whether the business has its own website. Businesses without one are often the best leads for web and marketing agencies.

## `requireInstagram` (type: `boolean`):

Only businesses that publish an Instagram account.

## `sort` (type: `string`):

Order of results. "Closest" needs a point in Near a point.

## `placeUrls` (type: `array`):

Profile URLs like https://www.bokadirekt.se/places/some-salon-136216, or just the number at the end.

## Actor input object example

```json
{
  "maxItems": 10,
  "mode": "search",
  "categories": [
    "Frisör"
  ],
  "locations": [
    "Stockholm"
  ],
  "timeOfDay": "any",
  "lastMinuteOnly": false,
  "hasCampaigns": false,
  "hasBundles": false,
  "payLater": false,
  "acceptsGiftCard": false,
  "acceptsWellnessCard": false,
  "tradeAssociationOnly": false,
  "minRating": "any",
  "minReviews": "any",
  "requireEmail": false,
  "website": "any",
  "requireInstagram": false
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset row per business matched by search or looked up by profile.

# 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 = {
    "maxItems": 10,
    "mode": "search",
    "categories": [
        "Frisör"
    ],
    "locations": [
        "Stockholm"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/bokadirekt-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 = {
    "maxItems": 10,
    "mode": "search",
    "categories": ["Frisör"],
    "locations": ["Stockholm"],
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/bokadirekt-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 '{
  "maxItems": 10,
  "mode": "search",
  "categories": [
    "Frisör"
  ],
  "locations": [
    "Stockholm"
  ]
}' |
apify call normdata/bokadirekt-scraper --silent --output-dataset

```

## MCP server setup

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