# Swiss Business Directory Scraper — local.ch (`jungle_synthesizer/local-ch-swiss-business-directory-scraper`) Actor

Swiss business directory data: company names, addresses, phone numbers, emails, ratings, and opening hours for the Swiss SMB market. Filter by industry vertical. Structured JSON output ready for lead lists or CRM import.

- **URL**: https://apify.com/jungle\_synthesizer/local-ch-swiss-business-directory-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 record scrapeds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Swiss Business Directory Scraper — local.ch

Scrape business listings from [local.ch](https://www.local.ch), the Swiss national business directory. Returns company name, address, canton, phone, mobile, email, website, opening hours, ratings, and more for the full Swiss SMB market — filterable by 18 industry verticals.

***

### Swiss Business Directory Scraper Features

- Extracts complete company records — name, street, postal code, city, canton, coordinates
- Returns landline, mobile, fax, email, and website in the same record, when the business lists them
- Filters by 18 industry verticals (restaurants, garages, health specialists, retail, and more)
- Captures ratings, review counts, spoken languages, accepted payment methods, and booking availability
- Formats opening hours per weekday, ready to parse without touching raw HTML
- Covers the entire Swiss directory — every canton, every listed business, not a single-city sample

***

### Who Uses Swiss Business Directory Data?

- **Outbound sales teams** — build canton-level prospect lists with phone and email already attached
- **Fintech and insurance underwriters** — enrich KYB checks with a business's registered address and contact details
- **Agencies** — assemble trade-specific lead lists (plumbers in Zürich, restaurants in Geneva) without hand-copying from a map
- **Market researchers** — measure SMB density and category mix by canton, or track which verticals cluster where
- **CRM and data teams** — feed structured Swiss business records straight into an existing pipeline, no cleanup pass required

***

### How Swiss Business Directory Scraper Works

1. Pick one or more business verticals (or leave it blank for the whole directory).
2. The scraper walks the complete published listing for each selected vertical and pulls every business record it finds.
3. Each record is normalized into a consistent JSON shape — same field names whether the source page had three phone numbers or none.
4. Results land in your dataset as they're collected, so a run you stop early still keeps what it already gathered.

***

### Input

```json
{
  "maxItems": 500,
  "categories": ["garage", "restaurants"]
}
```

| Field         | Type    | Default | Description                                                                                   |
|---------------|---------|---------|-------------------------------------------------------------------------------------------------|
| `maxItems`    | integer | 10      | Maximum records to scrape. Set to `0` for an unlimited run across the full selected corpus.     |
| `categories`  | array   | (all)   | Business verticals to include. Leave empty to crawl every vertical — the entire directory.      |
| `resumeCursor`| string  | —       | Cursor from a previous run's Output, used to continue a stopped crawl. See below.               |

Leaving `categories` empty and `maxItems` at `0` crawls the full Swiss directory — millions of businesses across every canton. Expect a long run.

***

### Swiss Business Directory Scraper Output Fields

```json
{
  "entry_id": "Q_Z8HPLKuC9PEw9R5hNc9g",
  "name": "Sutterlüti AG",
  "category": "Sanitär",
  "categories_all": ["Sanitär", "Heizungen"],
  "street": "Feldeggstrasse 61",
  "postal_code": "8008",
  "city": "Zürich",
  "canton": "ZH",
  "latitude": 47.360905,
  "longitude": 8.55343,
  "phone": "044 384 91 00",
  "mobile": null,
  "fax": null,
  "email": "info@sutterluetiag.ch",
  "website": "http://www.sutterluetiag.ch",
  "opening_hours": "Mon 07:30-12:00,13:00-16:30; Tue 07:30-12:00,13:00-16:30",
  "languages": ["Deutsch", "Englisch"],
  "payment_methods": ["Barzahlung", "TWINT"],
  "has_booking": true,
  "rating_avg": 5,
  "rating_count": 4,
  "description": "Seit 1925 Ihr Partner für Haustechnik im Kanton Zürich",
  "listing_url": "https://www.local.ch/de/d/zuerich/8008/sanitaer/sutterlueti-ag-Q_Z8HPLKuC9PEw9R5hNc9g",
  "locale": "de",
  "source_query_category": "garage",
  "scraped_at": "2026-09-01T22:14:44.370Z"
}
```

| Field                    | Type    | Description                                                                 |
|---------------------------|---------|-------------------------------------------------------------------------------|
| `entry_id`                | string  | local.ch's canonical business id                                              |
| `name`                    | string  | Business trade name                                                           |
| `category`                | string  | Primary category                                                              |
| `categories_all`          | array   | Every category the business is tagged under                                   |
| `street`                  | string  | Street and house number                                                       |
| `postal_code`              | string  | Swiss postal code                                                             |
| `city`                    | string  | City / locality                                                               |
| `canton`                  | string  | Canton code (ZH, GE, VD, etc.)                                                |
| `latitude` / `longitude`  | number  | Coordinates                                                                    |
| `phone` / `mobile` / `fax` | string | Contact numbers, when listed                                                  |
| `email`                   | string  | Contact email                                                                 |
| `website`                 | string  | Business website                                                              |
| `opening_hours`           | string  | Weekday opening hours, formatted (e.g. `"Mon 07:30-12:00,13:00-16:30"`)       |
| `languages`               | array   | Spoken/service languages, when the business lists them                        |
| `payment_methods`         | array   | Accepted payment methods, when listed                                         |
| `has_booking`             | boolean | Whether the business offers online booking                                    |
| `rating_avg` / `rating_count` | number/integer | Rating and review count                                                |
| `description`             | string  | Short business tagline                                                       |
| `listing_url`              | string  | Canonical local.ch page for the business                                      |
| `locale`                  | string  | Always `"de"`                                                                |
| `source_query_category`   | string  | The vertical this record was discovered under                                 |
| `scraped_at`               | string  | Timestamp the record was delivered                                            |

***

### Resuming a large crawl

Every run emits a `resumeCursor` in its Output. If a large crawl stops before it finishes — because it hit `maxItems`, your spend cap (`maxTotalChargeUsd`), or was aborted — start a new run with **the same input** plus that `resumeCursor` to continue from where it left off. The crawl resumes from the queued work the previous run didn't reach.

- You are **not re-charged** for records the earlier run already delivered.
- Resume within your account's run-retention window — on the free tier, roughly your 10 most recent runs. Once the source run is pruned, its `resumeCursor` is no longer valid.
- `resumeCursor` is opaque — supply it unmodified.

***

### FAQ

#### How do I scrape local.ch business listings?

Give Swiss Business Directory Scraper a `maxItems` value and, optionally, a list of verticals. It returns structured records — one per business — with contact details, address, ratings, and hours already parsed out.

#### What data can I get from local.ch?

Name, full address with canton, phone, mobile, email, website, opening hours, languages, payment methods, rating, and category — 26 fields per business, covering the whole Swiss directory rather than one city or trade.

#### Can I filter by industry or business type?

Yes. The `categories` input restricts a run to any combination of 18 verticals — restaurants, garages, health specialists, retail, and more. Leave it empty to pull everything.

#### Do I need an account or API key for local.ch?

No. Swiss Business Directory Scraper needs no local.ch account, login, or API key — just an Apify run.

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

Pricing is per record collected, so a 50-business test run and a full-directory crawl scale the same way per unit. Check the actor's pricing tab for current rates.

***

### Need More Features?

Need custom fields, filters, or a different target site? [File an issue](https://console.apify.com/actors/issues) or get in touch.

### Why Use Swiss Business Directory Scraper?

- **Complete coverage** — every canton, every listed vertical, not a single-city sample you have to stitch together yourself.
- **Contact-ready output** — phone, mobile, email, and website in one record, so a lead list doesn't need a second enrichment pass.
- **Consistent schema** — 26 fields, same names on every record, whether the source business listed three phone numbers or none.

# Actor input Schema

## `sp_intended_usage` (type: `string`):

What will this data feed? E.g. lead lists, KYB checks, price tracking.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

We'll personally help with your use case. No spam.

## `resumeCursor` (type: `string`):

Leave empty for a fresh crawl. To CONTINUE a previous run where it stopped — without paying again for records you already received — paste the `resumeCursor` value from that run's Output (the run's OUTPUT key). Resume promptly: the previous run's data expires with your account's retention window (free tier: your ~10 most recent runs).

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

Maximum number of business records to scrape. Set to 0 for an unlimited crawl of the full selected corpus (millions of records — expect a long run; use resumeCursor to continue across runs).

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

Restrict the crawl to specific local.ch business verticals. Leave empty to crawl every vertical (the full directory).

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "maxItems": 10
}
```

# 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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/local-ch-swiss-business-directory-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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/local-ch-swiss-business-directory-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 '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "maxItems": 10
}' |
apify call jungle_synthesizer/local-ch-swiss-business-directory-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jungle_synthesizer/local-ch-swiss-business-directory-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/5V1SwYabAj88XrTfk/builds/Le8mxaYZVuZPeMVCi/openapi.json
