# StarOfService Scraper | Pros | Coverage | Leads (`ahmed_jasarevic/starofservice-scraper`) Actor

Scrape StarOfService professional profiles, coverage areas and catalog data for service business lead generation and home services market research. Covers ~1,010 trades across France with contact details in structured rows.

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

## Pricing

from $4.90 / 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

## StarOfService Scraper — French Service-Pro Leads And Trade × City Coverage Counts

Extract pro profiles from [starofservice.com](https://www.starofservice.com), the French professional-services directory — **~1,010 trades** (plumbers, electricians, roofers…) with ratings, review counts and locations — for **service business lead generation**, plus one coverage row per trade × city combination so you can size a local market before scraping it. Runs as plain HTTP against the site's own internal JSON:API (CheerioCrawler, no browser, ~256 MB RAM), because StarOfService's CloudFront WAF returns HTTP 403 to datacenter IPs.

### Main Use Cases: Service Business Lead Generation, Contractor Leads And Local Market Analysis

- **Service business lead generation for French trades** — pro rows (name, trade, city, ZIP, rating, review count) as contractor leads, plumber leads or cleaning business leads (`nettoyage`), any French city.
- **Home services market research** — trade × city coverage counts (`proCount`, `proCountCapped`) size a local market before you spend budget.
- **Find plumbers in Paris — and every other trade, city by city** — start from the ~1,010-trade catalog and city resolver, then enumerate profiles per pair.
- **Business directory data scraping** — profile, coverage and catalog rows in one dataset, three views (Pros, Trade × city coverage, Catalog).
- **Local service leads on a schedule** — weekly runs refresh a lead list and catch new pros, ratings and premium profiles.

### How The StarOfService Scraper Works

StarOfService is a Next.js site behind a CloudFront WAF returning HTTP 403 to datacenter IPs — including Apify's proxy ranges — so a headless browser fails too. The Actor skips the website and talks to the internal "zeus" JSON:API its own pages call: host and token come from the server-rendered `__NEXT_DATA__` blob, then paginated JSON flows through Crawlee (CheerioCrawler, no DOM parsing, ~256 MB). Modes: `profiles`, `coverage`, `trades`, `cities`, `profilesByUrl`. Rows are pushed in batches of 50 with `pushed N row(s) … combination d/t` logs. Coverage is France-only (`Accept-Country: fr`).

### Input Parameters For Modes, Trades, Cities And Run Caps

**Modes:** `profiles` (default) — pros per trade × city pair, each pair fetched three times (default, `sort=nb_reviews`, `sort=-nb_reviews`) for ~23 unique pros, plus one coverage row. `coverage` — counts only, 1 request per pair. `trades` — full catalog; **run first** for valid slugs. `cities` — names → UUIDs, slugs, postcodes, coordinates. `profilesByUrl` — profiles from `startUrls`.

| Field | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `mode` | string (select) | No | `profiles` | `profiles`, `coverage`, `trades`, `cities`, `profilesByUrl`. |
| `startUrls` | array | No | *(empty)* | `profilesByUrl` mode; `/inv/professionnel/…` and `/professionnel/…` accepted. |
| `trades` | array of string | No | *(empty)* | Slugs like `plomberie`, `electricite`. Empty → `defaultTrades`. |
| `cities` | array of string | No | `["Paris"]` | Names or slugs (`Paris`, `Aix-en-Provence`), resolved via `/cities`. |
| `defaultTrades` | array of string | No | 10 common trades | Fallback when `trades` is empty — 10 slugs from the `/services` catalog. |
| `maxPairs` | integer | No | `0` | Backstop on trade × city pairs; `0` = auto (enough to reach `maxProfiles`). |
| `maxProfiles` | integer | No | `500` | Target profile rows; sort variants continue until reached. Free accounts: 10. |
| `maxTrades` | integer | No | `1010` | Max trade catalog rows (`trades` mode). |
| `maxCities` | integer | No | `200` | Max city rows **per searched name** (`cities` mode). |
| `includeDetails` | boolean | No | `false` | Extra request per pro: bio, registration date, gallery. |
| `apiToken` | string | No | *(empty)* | Override zeus token; empty = built-in, auto-refreshed from the SSR blob. |
| `country` | string | No | `fr` | `Accept-Country` header (`fr` = French marketplace). |
| `maxRequestsPerCrawl` | integer | No | `1000` | Hard cap on HTTP requests. |
| `maxConcurrency` | integer | No | `8` | Parallel requests (1–10). |
| `proxy` | object | No | `{ "useApifyProxy": false }` | Apify Proxy picker, off by default; applies to every Crawlee call if on. |

### Output Fields: Pros, Coverage And Catalog Views

Every row carries `type` — `profile`, `coverage`, `trade` or `city` — selecting its shape. Fields are strings unless annotated; unavailable values are `null`. Output tabs: **Pros**, **Trade × city coverage**, **Catalog**.

**`profile` rows (Pros view)**

| Field | Description |
| --- | --- |
| `proUuid` / `name` | Profile UUID (zeus `/pro_profiles` id); pro or company name. |
| `url` / `landingPageUrl` | Public profile URL; trade × city landing page. |
| `tradeUuid` / `tradeSlug` / `tradeName` | Trade UUID, slug (e.g. `plomberie`) and display name. |
| `cityUuid` / `citySlug` / `city` / `cityId` (integer) | City UUID (zeus API), slug, name; legacy numeric city id from profile URLs. |
| `zipCode` / `department` | Postcode and department name. |
| `latitude` / `longitude` (number) | Address coordinates (city rows: city centre). |
| `rating` (number) / `reviewCount` (integer) | Average rating 0–5; published review count. |
| `description` / `presentation` / `workDescription` | Profile, presentation and work description texts. |
| `bio` / `phone` | Bio (only with `includeDetails`); phone usually `null` (hidden until quote request). |
| `startingYear` / `employees` / `premium` | Year founded, employee count (int), paid premium flag. |
| `createdAt` / `registeredAt` | Creation and registration timestamps (ISO 8601); `registeredAt` only with `includeDetails`. |
| `photo` / `logo` / `hasAvatar` (boolean) | Primary photo and logo URLs; custom-avatar flag. |
| `photos` / `services` (array) | All photo URLs; service names — often empty (API returns ids). |

**`coverage` rows (Trade × city coverage view)**

| Field | Description |
| --- | --- |
| `tradeSlug` / `tradeName` / `cityName` | Trade and city counted. |
| `proCount` (integer) / `proCountCapped` (boolean) | Pros for the pair — a **lower bound** (max 10 per pair); `true` = full 10-profile page, at least 10. |
| `listingUrl` | Public `/dir/<region>/<department>/<city>/<trade>` page. |

**`trade` rows (Catalog view)**

| Field | Description |
| --- | --- |
| `tradeUuid` / `tradeSlug` / `tradeName` | Trade UUID, slug and display name. |
| `availableOnLandings` (boolean) | Bookable via request-a-quote landing pages. |

**`city` rows (Catalog view)**

| Field | Description |
| --- | --- |
| `cityUuid` / `citySlug` / `cityName` / `zipCode` | City UUID, slug, name and postcode. |
| `fullCityName` / `fullName` | Site labels, e.g. `75008 — Paris`, `69001 — Lyon`. |
| `latitude` / `longitude` (number) | City-centre coordinates (population is not exposed). |

### Example Input: Build A Plumber Lead List For Paris

Run `{"mode": "trades"}` first for valid trade slugs, then:

```json
{
  "mode": "profiles",
  "trades": ["plomberie", "electricite", "menuiserie"],
  "cities": ["Paris", "Lyon", "Marseille"],
  "maxProfiles": 200,
  "includeDetails": true
}
```

### Example Output: Profile And Coverage Rows

An abbreviated `profile` row (real field names; unavailable fields return `null` — `phone` usually is):

```json
{
  "type": "profile",
  "proUuid": "562163b3-e344-b858-d4c7-a87c86a53a3e",
  "name": "Duchateau & fils",
  "url": "https://www.starofservice.com/professionnel/plomberie/paris/173009619/duchateau-fils",
  "tradeSlug": "plomberie",
  "tradeName": "plomberie",
  "city": "Paris",
  "zipCode": "75008",
  "latitude": 48.8739,
  "longitude": 2.3126,
  "rating": 5,
  "reviewCount": 10,
  "phone": null,
  "premium": false,
  "services": ["Dépannage plomberie"]
}
```

The matching `coverage` row (`trades`/`cities` modes emit the `trade` and `city` catalog rows above):

```json
{
  "type": "coverage",
  "tradeSlug": "plomberie",
  "tradeName": "plomberie",
  "cityName": "Paris",
  "proCount": 10,
  "proCountCapped": true,
  "listingUrl": "https://www.starofservice.com/dir/ile-de-france/paris/paris/plomberie"
}
```

### Scrape StarOfService Profiles: Batched Writes And Three Sort Variants

- **Batched writes** — 50 rows per push, with `pushed N row(s) … combination d/t` logs keeping runs traceable.
- **Three sort variants per pair** — each `pro_profiles` request caps at 10 pros with no pagination, so pairs are requested in default, `sort=nb_reviews` and `sort=-nb_reviews` order — **~23 unique pros per pair**.
- **Two products in one run** — profile lead rows *and* one coverage row per pair.
- **Bounded** — `maxRequestsPerCrawl` (1000), `maxConcurrency` (1–10), `maxProfiles` / `maxPairs`; free accounts: 10 profiles.

### StarOfService API Access — No Public API Required

`www.starofservice.com` sits behind a **CloudFront WAF returning HTTP 403** to datacenter IPs (Apify proxy ranges included) — a headless browser fails the same way — and there is **no public StarOfService developer API**: API Evangelist and apis.io both maintain a StarOfService profile stating so. The Actor reads the API coordinates from the site's own pages:

1. Next.js pages embed a `__NEXT_DATA__` blob whose `pageProps.apiData` holds the host and token: `{ "pageProps": { "apiData": { "zeusHost": "https://zeus.starofservice.com", "token": "…" } } }`
2. The site's JS bundles reference that API as **`SOS-NOID`**.

A [JSON:API](https://jsonapi.org/) service on `https://zeus.starofservice.com` requiring these headers:

| Header | Value |
| --- | --- |
| `Authorization` | `SOS-NOID <token>` |
| `X-App-Identifier` | `SOS.WebInternal/1.0` |
| `Accept-Country` | `fr` |
| `Accept` / `Content-Type` | `application/vnd.api+json` |

| Endpoint | Purpose |
| --- | --- |
| `GET /services?filter[available_on_landings]=true` | Trade catalog (~1,010 trades, 100/page) |
| `GET /cities?filter[name]=…&sort=-population` | City lookup + region/department relations |
| `GET /regions/{id}`, `GET /departments/{id}` | Slugs for public `/dir/…` URLs |
| `GET /pro_profiles?filter[service.id]=…&filter[city.id]=…` | Profiles for a trade + city (10/page max) |
| `GET /pro_profiles/{uuid}` | Single profile (bio, registration date, gallery) |

**Token handling.** The built-in token comes from the site's data blob; when StarOfService rotates it, the Actor re-reads a fresh one or logs a clear error. Paste your own into `apiToken` anytime.

### Size The Local Market First: Trade × City Coverage Counts

`coverage` mode answers "how many pros serve this trade in this city?" with **1 request per pair** — no profile rows. Rows carry `proCount`, `proCountCapped` and the public `listingUrl`. Two rules: `proCount` is a **lower bound** (no exact totals exist), and `proCountCapped: true` means `10+`, not `10`. Compare coverage across cities for a go/no-go read before spending a `profiles` run or ad budget — local coverage data, not a market-size figure.

### Directory Scraping The French Services Marketplace: ~1,010 Trades And Artisans In France

- **`trades` mode** — ~1,010 real slugs from `/services` (100/page) with `tradeUuid`, `tradeSlug`, `tradeName`, `availableOnLandings`. Run first; feed slugs back into `trades`.
- **`cities` mode** — plain names (`Paris`, `Aix-en-Provence`) → UUIDs, slugs, postcodes, coordinates; up to `maxCities` (200) rows per name. `population` isn't exposed — coordinates come instead.
- **`profilesByUrl` mode** — paste profile URLs into `startUrls` (both variants).
- **France-only by design** — `Accept-Country: fr`: plumbers in Paris, electricians in Lyon, cleaners in Bordeaux, enumerated the same way for every trade.

### Service Marketplace Data: Ratings, Reviews And The Phone-Number Limitation

Beyond `rating`, `reviewCount`, location and company facts (full tables above), `bio` and `registeredAt` arrive with `includeDetails`. Limitations:

- **Phone numbers are usually `null`** — StarOfService hides contact details until a quote request, so the API returns `phone_number: null` for most profiles. That's the site's behaviour, not a scraping failure: plan lead capture around profile URLs, not cold lists.
- **Max 10 pros per request**, no reliable pagination or totals; the three sort variants (~23 per pair) mitigate this, and `proCount` stays a lower bound.
- **Review *text* is not extracted** — only `rating` and `reviewCount`; text is gated behind the profile page.
- **City `population` is not exposed**; coordinates are returned instead.
- **The internal API is unofficial** and could change without notice.

### Run starofservice-scraper From The Apify API, Console Or Schedule

- **Apify Console** — set inputs, press *Run*; rows appear under the three views, with `pushed N row(s)` in the log tab.
- **Apify API** — start actor `LKqjH7YCD1On7Rs0T` via `POST https://api.apify.com/v2/acts/LKqjH7YCD1On7Rs0T/runs` (or `run-sync-get-dataset-items`), then read `GET https://api.apify.com/v2/datasets/<datasetId>/dataset/items`.
- **Schedule** — save the input as a task and schedule it (cron, UTC).

### Integrations & Automation

Native Apify integrations only. **Apify API**: start runs, fetch dataset items. **Webhooks**: `ACTOR.SUCCEEDED` → POST rows to Slack, Google Sheets, Airtable or your CRM. **Zapier / Make**: native Apify modules. **Schedules**: a realistic pattern is a **weekly coverage run** (cron `0 6 * * 1`, Mondays 06:00 UTC) per trade list, plus a monthly `profiles` refresh — keeping your trade × city baseline current.

### Related Actors

- [local-service-leads-scraper](https://apify.com/mahogany_songbird/local-service-leads-scraper) — local service businesses by trade and city (Google Maps): phone, website, rating — the US complement to France-only data.
- [home-service-business-lead-scraper](https://apify.com/digitalnomadph/home-service-business-lead-scraper) — home service leads from Houzz, Yellow Pages and BuildZoom.
- [thumbtack-scraper](https://apify.com/jungle_synthesizer/thumbtack-scraper) — Thumbtack pro listings: ratings, reviews, hire counts, pricing (US).
- [angi-scraper](https://apify.com/igolaizola/angi-scraper) — Angi contractor profiles, 150+ categories, with phones and reviews.
- [homeguide-scraper](https://apify.com/ahmed_jasarevic/homeguide-scraper) — HomeGuide contractor leads by ZIP and trade: rating, reviews, hire count, Top Pro badges.

### StarOfService Scraper FAQ: API, Coverage, Contact Data And Alternatives

#### Does StarOfService have a public API?

No — API Evangelist and apis.io both maintain StarOfService profiles stating so. This Actor uses the internal JSON:API the frontend itself calls (`zeus.starofservice.com`, `SOS-NOID` auth, host and token from the `__NEXT_DATA__` blob).

#### Can you scrape StarOfService?

Yes — but not by rendering the site: the WAF 403s datacenter IPs, browsers included. The Actor queries the internal API the site itself calls: paginated, filterable JSON, no DOM parsing.

#### How many plumbers are there in Paris?

`coverage` mode with `trades: ["plomberie"]`, `cities: ["Paris"]` returns `proCount`, `proCountCapped` and `listingUrl`. `proCount` is a lower bound; `proCountCapped: true` means the 10-profile page was full (at least 10). Works for any trade, any French city.

#### How do I get leads for a cleaning business?

`trades: ["nettoyage"]` plus your cities in `profiles` mode → one row per cleaning company: name, profile URL, city, ZIP, rating, reviews. Coverage mode first shows which cities list most.

#### Where can I get a list of local service businesses with contact details?

Name, trade, city, ZIP, coordinates, rating, review count, description, size, founding year — but StarOfService hides contact details until a quote request, so most `phone` values are `null`. Treat profile URLs as the path.

#### What are the alternatives to this actor — Thumbtack, Angi or something else?

US options (see Related Actors): thumbtack-scraper, angi-scraper, local-service-leads-scraper, home-service-business-lead-scraper, homeguide-scraper. None cover France and this actor covers only the French marketplace — pick by geography.

### SEO Keywords

starofservice scraper, scrape starofservice, starofservice api, starofservice alternative, starofservice.com, service business lead generation, local lead generation, contractor leads, plumber leads, cleaning business leads, home service business leads, local service leads, lead scraping, directory scraping, business directory data scraping, service marketplace data, home services market size, home services market research, thumbtack alternative, angi vs thumbtack, local market analysis, find plumbers in paris, artisans in france, service provider directory scraping

### For AI Agents & LLM Apps

**Purpose:** Extract French service-pro profiles and trade × city coverage counts from StarOfService's internal JSON:API — a lead-generation and market-sizing source where no public API exists.

**Minimal working input:**

```json
{ "mode": "trades" }
```

**Variant — cheapest billed run (1 request per pair):**

```json
{ "mode": "coverage", "trades": ["plomberie"], "cities": ["Paris"], "maxPairs": 1 }
```

**Output fields (40, one `type` per row):**

- profile: proUuid, name, url, landingPageUrl, tradeUuid, tradeSlug, tradeName, cityUuid, citySlug, city, cityId, zipCode, department, latitude, longitude, rating, reviewCount, description, presentation, workDescription, bio, phone, startingYear, employees, premium, createdAt, registeredAt, hasAvatar, photo, logo, photos, services
- coverage: tradeSlug, tradeName, cityName, proCount, proCountCapped, listingUrl
- trade: tradeUuid, tradeSlug, tradeName, availableOnLandings
- city: cityUuid, citySlug, cityName, zipCode, fullCityName, fullName, latitude, longitude

**Behaviors an agent should know:**

- `mode` defaults to `profiles`; empty `trades` falls back to `defaultTrades` (10 slugs); `cities` defaults to `["Paris"]`. Run `mode=trades` first for valid slugs.
- `profiles` fetches each pair in three sort orders (~23 unique pros) **and** emits one `coverage` row per pair; `coverage` emits counts only, 1 request per pair. `proCount` is a lower bound; `proCountCapped: true` means "≥10, likely more" — never an exact total.
- `maxProfiles` (default 500) is a target, not a page limit; `maxPairs: 0` auto-computes pairs; `maxRequestsPerCrawl` (1000) caps requests; free accounts are capped at 10 profiles.
- `includeDetails` defaults to `false` — `bio` and `registeredAt` are absent unless enabled (+1 request per profile). `phone` is usually `null` by platform design, not an extraction failure.
- The API token auto-refreshes from the SSR blob; `apiToken` overrides it. An enabled proxy applies to every Crawlee request; `maxConcurrency` must be 1–10 (default 8).

**Billing:** pay-per-event — `result` $0.005 per result, `Actor Start` $0.00005 per run start.

### Legal & Compliance Disclaimer

- This Actor is an independent third-party tool and is not affiliated with, endorsed by, sponsored by, or connected to StarOfService or starofservice.com.
- It accesses only publicly available data: public profile and directory pages and the unauthenticated JSON:API endpoints those pages call — no login, no account creation, no auth bypass. The API token is read from the site's own publicly served pages.
- StarOfService's terms restrict commercial reuse of its directory. You are responsible for compliance with those terms and applicable data-protection law — for France/EU data, that includes the GDPR.
- Output rows may occasionally contain a phone number. Contact data must not be used for unsolicited commercial outreach in violation of applicable law (including GDPR and ePrivacy direct-marketing rules).
- The internal API is unofficial and may change without notice. Rate-limit your runs, respect `robots.txt`, and use the data for legitimate market research and lead generation.

# Actor input Schema

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

What to scrape:

- `profiles` — enumerate pro profiles for each trade+city combination (the main mode).
- `coverage` — cheap mode: only the number of pros per trade+city combination (1 request per combination, no profile rows).
- `trades` — list all trade/service categories with their slugs (1010 for the FR marketplace).
- `cities` — list/search city records (uuid, name, zip code, slug).
- `profilesByUrl` — fetch full detail for pro profile URLs supplied in `startUrls`.

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

Used by `profilesByUrl` mode. Starofservice pro profile URLs, e.g. `https://www.starofservice.com/inv/professionnel/plomberie/paris/173009619/duchateau-fils`. Both the `/inv/professionnel/...` and `/professionnel/...` variants are supported.

## `trades` (type: `array`):

Trade slugs from the Starofservice `/services` catalog, e.g. `plomberie`, `electricite`, `menuiserie`, `serrurerie`, `peinture`. Run `mode=trades` to list all ~1010 slugs. Combined with `cities` to build trade+city queries. Leave empty to use `defaultTrades`.

## `cities` (type: `array`):

City names or slugs to resolve, e.g. `Paris`, `Lyon`, `Marseille`, `Aix-en-Provence`, `Bordeaux`. Each is resolved to a Starofservice city record (UUID + region/department slugs) via the `/cities` endpoint.

## `defaultTrades` (type: `array`):

Trade slugs used when the `trades` input is left empty. These are real slugs from StarofService's `/services` catalog — run `trades` mode to list all ~1010.

## `maxPairs` (type: `integer`):

Backstop on the number of trade × city combinations to process. 0 = automatic: enough combinations to reach `maxProfiles` (about 10 profiles per combination, plus sort variants).

## `maxProfiles` (type: `integer`):

Target number of pro profiles to push to the dataset — the Actor keeps fetching combinations (and both sort variants of each, up to ~23 unique profiles per combination) until it is reached. Free accounts are capped at 10.

## `maxTrades` (type: `integer`):

Maximum number of trade categories to list (`trades` mode).

## `maxCities` (type: `integer`):

Maximum number of city records to list (`cities` mode).

## `includeDetails` (type: `boolean`):

Fetch one extra request per pro to add description, phone number, photo gallery and offered services. Slower but much richer.

## `apiToken` (type: `string`):

Optional override for the zeus API token. Leave empty to use the built-in token; the Actor also tries to auto-refresh it from the site's Next.js data blob when the built-in one stops working.

## `country` (type: `string`):

Value sent in the `Accept-Country` header (the site uses `fr` for the French marketplace).

## `maxRequestsPerCrawl` (type: `integer`):

Hard cap on total HTTP requests made by this run.

## `maxConcurrency` (type: `integer`):

How many zeus API requests to run in parallel (1-10).

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

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "mode": "profiles",
  "startUrls": [],
  "trades": [],
  "cities": [
    "Paris"
  ],
  "defaultTrades": [
    "plomberie",
    "electricite",
    "menuiserie",
    "serrurerie",
    "peinture",
    "jardinage",
    "nettoyage",
    "charpenterie-et-menuiserie",
    "chaudiere-et-chauffage-central",
    "installation-et-remplacement-de-toiture"
  ],
  "maxPairs": 0,
  "maxProfiles": 500,
  "maxTrades": 1010,
  "maxCities": 200,
  "includeDetails": false,
  "country": "fr",
  "maxRequestsPerCrawl": 1000,
  "maxConcurrency": 8,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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": "profiles",
    "startUrls": [],
    "trades": [],
    "cities": [
        "Paris"
    ],
    "defaultTrades": [
        "plomberie",
        "electricite",
        "menuiserie",
        "serrurerie",
        "peinture",
        "jardinage",
        "nettoyage",
        "charpenterie-et-menuiserie",
        "chaudiere-et-chauffage-central",
        "installation-et-remplacement-de-toiture"
    ],
    "apiToken": "",
    "country": "fr",
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/starofservice-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": "profiles",
    "startUrls": [],
    "trades": [],
    "cities": ["Paris"],
    "defaultTrades": [
        "plomberie",
        "electricite",
        "menuiserie",
        "serrurerie",
        "peinture",
        "jardinage",
        "nettoyage",
        "charpenterie-et-menuiserie",
        "chaudiere-et-chauffage-central",
        "installation-et-remplacement-de-toiture",
    ],
    "apiToken": "",
    "country": "fr",
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/starofservice-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": "profiles",
  "startUrls": [],
  "trades": [],
  "cities": [
    "Paris"
  ],
  "defaultTrades": [
    "plomberie",
    "electricite",
    "menuiserie",
    "serrurerie",
    "peinture",
    "jardinage",
    "nettoyage",
    "charpenterie-et-menuiserie",
    "chaudiere-et-chauffage-central",
    "installation-et-remplacement-de-toiture"
  ],
  "apiToken": "",
  "country": "fr",
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/starofservice-scraper --silent --output-dataset

```

## MCP server setup

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