# SHAB Swiss New Company Registrations Scraper (`scrapersdelight/shab-new-companies-scraper`) Actor

Scrape every newly registered Swiss company from the SHAB/FOSC commercial gazette (rubric HR01): name, CHE UID, full street address, canton, legal form, share capital, business purpose, cantonal register office and the named founders and officers. Filter by canton, legal form, capital or keyword.

- **URL**: https://apify.com/scrapersdelight/shab-new-companies-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 per company returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## 🇨🇭 SHAB Swiss New Company Registrations — UID, address, capital, founders

Every company registered in Switzerland, the day it is registered. This Actor reads rubric
**HR01 "Neueintragung" / "Nouvelle inscription"** of the **Swiss Official Gazette of Commerce
(SHAB / FOSC / FUSC)** — the statutory gazette every cantonal commercial register must publish in —
and turns it into one clean row per new company: **name, CHE UID, full street address, canton,
legal form, share capital, the complete statutory business purpose, the cantonal register office,
and the named founders and officers.**

No login, no API key, no CAPTCHA. **3,937 new Swiss registrations were gazetted in the last 30
days** (measured day by day against the live API on 2026-09-05: 21 gazette days, largest single day
244\), and the archive holds **404,662** registrations back to January 2018 (2017 returns 0).

### What does this Actor do?

- 🏢 **`companyName`** + **`uid`** (`CHE-123.456.789`) + `uidOrganisationId` + `code13` — the
  register keys you can join to Zefix, the VAT register and every Swiss B2B dataset
- 📍 **`street`, `houseNumber`, `zipCode`, `town`, `addressFull`, `canton`, `seat`** — the real
  domicile, not a PO box guess
- 🏷️ **`legalForm`** (the register's own 4-digit code) + **`legalFormLabel`** in English, German,
  French or Italian — GmbH/Sàrl, AG/SA, sole proprietorship, cooperative, foundation, branch…
- 💰 **`shareCapitalChf`, `paidUpCapitalChf`, `capitalFullyPaid`** — how well funded the company is
  on day one
- 🎯 **`purpose`** — the full statutory business-purpose clause, often 1,000–2,500 characters. This
  is what lets you carve a vertical out of the whole Swiss economy
- 👤 **`registeredPersons[]`** — the named founders, managing officers and shareholders with
  **role, signature authority, town of residence and place of origin or nationality**, plus
  **`primaryPerson`** and the raw **`registeredPersonsText`** block
- 🏛️ **`registrationOffice`, `journalNumber`, `journalDate`, `publicationNumber`, `legalBasis`** —
  the full audit trail back to the cantonal register entry
- 🔍 **`auditOptOut`, `auditorName`, `parentEntityName`** — governance signals for finance buyers
- 🔗 **`publicationUrl`** (the SHAB notice) and **`zefixUrl`** (the company's register record)

### Example input

```json
{
  "lookbackDays": 7,
  "cantons": ["ZH", "ZG"],
  "purposeKeywords": ["Software", "Informatik", "IT-Dienstleistungen"],
  "requireCapital": true,
  "minShareCapitalChf": 50000,
  "maxItems": 200
}
```

Every software or IT company registered in Zurich and Zug in the last week with at least
CHF 50,000 of capital. Rows dropped by those filters are **never billed**.

### Who is this for?

Swiss and DACH agencies and SDR teams building a weekly new-business call list · Treuhand,
fiduciaire and accounting firms prospecting companies that have just incorporated and have not yet
picked an accountant · banks, insurers, leasing and merchant-services vendors on a
freshly-funded-company trigger · business-software and SaaS vendors selling to day-one companies ·
KYB, credit and compliance teams needing a UID-keyed feed of new Swiss entities · market
researchers tracking company formation by canton and sector.

### Field coverage — measured, not promised

Every number below is from **one uncapped run of this exact build**: run `ufX9BKIeCjrDN8209`,
**1,890 registrations** across the 10 gazette days 2026-08-24 → 2026-09-04, on the shipped defaults
— which do apply one filter, `excludeBranches`, and dropped 57 of the window's 1,947 publications
(1,890 unique `publicationId`, 1,890 unique `uid`, 649 s, 1,890 billed = 1,890 delivered).

| Field | Fill | Note |
|---|---|---|
| `companyName`, `uid`, `uidOrganisationId`, `code13`, `legalForm`, `isBranch`, `seat`, `canton`, `cantons` | **100%** | the core register row |
| `street`, `zipCode`, `town`, `addressFull`, `hasStreetAddress`, `country` | **100%** | `houseNumber` **99.79%** |
| `purpose`, `purposeLength` | **100%** | the statutory purpose clause |
| `journalNumber`, `journalDate`, `registrationOffice`, `isRegistration`, `auditOptOut` | **100%** | |
| `publicationDate`, `creationDate`, `updateDate`, `publicationNumber`, `publicationLanguage`, `title`, `legalBasis`, `publicationUrl`, `zefixUrl` | **100%** | `legalBasis` is plain text — the register serves it as an HTML fragment and we strip the markup |
| `publicationText` | **100%** | the complete published notice |
| `registeredPersonCount` | **100%** | |
| `legalFormLabel` | **99.95%** | the raw code is always present; we leave the label `null` for a code we have not seen in a live publication rather than inventing one. The single miss was code `0117` (a public-law institution, Kantonsspital Winterthur) |
| `registeredPersonsText`, `registeredPersonsParseMethod` | **99.95%** | 1,889 of 1,890 — see below |
| `registeredPersons[]`, `primaryPerson` | **99.79%** | |
| `shareCapitalChf`, `paidUpCapitalChf`, `capitalFullyPaid` | **59.84%** | absent **by law** on sole proprietorships (654 of the 1,890 rows), not missing data — it moves with the day's mix of legal forms |
| `auditorName`, `auditorUid` | **2.06%** | most new companies opt out of an audit |
| `addressLine1` (the c/o line, often the Treuhand that incorporated the company) | **18.36%** | itself a lead signal |
| `addressLine2` | **0.32%** · `postOfficeBox` **0.05%** · `additionalSeat` **0%** | register fields that exist in the schema and are almost never used. We emit them so the rare row that has one is not silently dropped |
| `parentEntityName`, `parentEntityUid`, `parentEntityCountry` | **0% on a default run** | these are the *branch* fields — the parent company a `Zweigniederlassung` belongs to. Branches are excluded by default, so they are empty unless you set `excludeBranches: false`. Measured on 400 recent publications that included 14 branches: **12 of the 14 branch rows carried all three**, 0 of the 386 non-branch rows |

**Named persons, per person** (3,007 people across the 1,890 companies, **1.59 per company**):
`fullName` 100% · `role` 99.87% · `surname` 96.57% · `givenName` 94.71% · `residence` 93.22% ·
`signatureAuthority` 88.99% · `originOrNationality` 86.90%.

**Person block located, by publication language** (same run): German **1,311/1,311 = 100%** ·
French **502/503 = 99.8%** · Italian **76/76 = 100%**.

#### What a row actually contains

A default run delivers **53 columns**. Two more — `xmlUrl` and `pdfUrl` — are **off by default and
are not emitted at all** unless you switch them on, so you never get an always-empty column in your
CSV; turn either on and it appears in its normal place between `publicationUrl` and `zefixUrl`
(verified on run `XXooqygyMp8J5s9Yn`: 55 columns, both populated on 40/40 rows). `publicationUrl`
behaves the same way. Everything else on the list above is emitted on every row, `null` where the
register genuinely published no value.

### Honest limits — read this before you buy

- **The register does not publish founders as structured data.** We checked the live XSD
  (`HR01-export.xsd` 1.26, 111 element declarations): there is **no person element**. Named
  founders and officers exist only inside the free-text notice, in German, French or Italian, so
  `registeredPersons[]` is a **text parser**, not a schema read. It located the person block on
  **1,889 of 1,890 rows (99.95%)** in the 1,890-row run above — 1,311/1,311 German, 502/503 French,
  76/76 Italian — but a wording the register has not used in front of us can still defeat it, and
  did on exactly one French notice. That is exactly why **`registeredPersonsText` (the raw block)
  and `publicationText` (the whole notice) are always emitted alongside** — you can always see and
  re-parse the source text yourself.
- **Branch registrations legitimately have no founders.** A `Zweigniederlassung` / `succursale` is
  a new office of an existing company, so it names no people and registers no capital — it names a
  parent instead (`parentEntityName` / `parentEntityUid` / `parentEntityCountry`). Branches were
  **14 of 400** consecutive publications we sampled (3.5%) and are **excluded by default**
  (`excludeBranches`).
- **Roles are captured as the register wrote them**, including the register's own occasional
  gender slips, and only the first role phrase in a record is lifted into `role` — the full
  wording is always in the person's `raw` field.
- **Share capital is missing on ~40% of rows by design.** Sole proprietorships register no capital
  at all — they were **654 of the 1,890 rows (34.6%)** in the run above, and the capital fields came
  back on 59.84% of rows. The share moves with the day's mix of legal forms. Use `requireCapital`
  if you only want incorporated entities.
- **Company contact details are not in the register.** SHAB publishes the domicile address, not a
  phone number, email or website. This is a company + founder + address feed; enrich elsewhere.
- **A small number of rows are not new businesses at all.** Code `0118` is a registered
  non-commercial power of attorney, and codes such as `0117` cover public-law institutions
  (1 of the 1,890 rows above). Rubric HR01 is "new register entry", which is slightly wider than
  "new company". Use the **Legal forms** whitelist to keep only the forms you want — the 1,890-row
  run broke down as `0107` GmbH/Sàrl 782 · `0101` sole proprietorship 654 · `0106` AG/SA 349 ·
  `0103` general partnership 46 · `0109` association 40 · `0110` foundation 8 · `0108` cooperative 7 ·
  `0104` limited partnership 3 · `0117` 1.
- **The gazette runs on business days.** Weekends and Swiss public holidays return 0 rows. That is
  the register, not a failure — the run exits clean and tells you so.
- **An empty run always tells you which of those it was.** A 0-row run never guesses: if your
  keyword, cantons or language scope was the cause, the status message says how many registrations
  the gazette *did* publish in that window (one extra unscoped count call, made only on the empty
  path) so you can tell "Switzerland published nothing" apart from "nothing matched my scope".
  A weekend, a future date SHAB has not loaded yet, a client-side filter, a wrong-rubric
  publication ID and a name that matched nothing each get their own distinct sentence.

### Why this Actor is correct where a naive one is not

The SHAB API has a **hard 10,000-row offset window** (`page × size` must stay under 10,000; we
measured `size=100 / page=100` returning HTTP 400) and, worse, its publication-date sort is
**non-deterministic across requests** because ~200 rows share each date.

We measured what that does to an offset-paging scraper on a **closed, static month** (June 2026),
crawled contiguously: it declared 5,299 rows, fetched 5,299 rows — and got only **4,949 unique**.
**6.61% duplicates, and therefore 6.61% of the month silently missed.** A green health test would
never show it.

This Actor instead issues **exactly one request per publication day** with
`publicationDate.start == publicationDate.end`, page 0, size 1000. Over that same June:
**30 day-calls, 5,299 declared, 5,299 unique, 0 duplicates, 100.00% coverage.** Every list call
asserts `content.length === total` and the run **fails loudly** rather than delivering a partial
day. We re-measured every one of the last 120 days against the live API on 2026-09-05: 83 gazette
days, and the **largest single day was 295 rows (2026-06-19)** — ~3.4× under the page size. If a day
ever overflowed, it is split by canton — never by offset.

### Reliability

Measured on the 1,890-row run above (`ufX9BKIeCjrDN8209`), through the Apify **datacenter** proxy at
the default concurrency of 10: **2,015 requests sent, 38 retried, 0 gave up** — 98.1% succeeded
first try and **100% succeeded after at most one retry, with 0 hard failures**, across 30 day-calls
and 1,985 register-record fetches in 649 s. Not one 403, 429 or CAPTCHA: shab.ch runs no anti-bot
control on these endpoints, so no browser and no residential proxy is needed.

### Pricing

**$0.003 per company returned.** Pay per event, no monthly fee, and **no actor-start charge** —
four of the five other Swiss-register Actors on the Store bolt $0.005–$0.10 onto every run.

- Rows removed by your filters are **never** charged.
- The same publication is **never** delivered or charged twice in a run.
- `maxItems` is applied **before** charging.
- **One row per person** (`personsAsSeparateRows`) still bills **once per company**, never per
  person.
- List-only mode (`includeDetail: false`) bills a separate, much cheaper **$0.0005** event, because
  those rows carry no UID, address, capital or founders.

For reference: the cheapest comparable full-register-record Actor on the Store is $0.0035/company,
and the direct new-company-registration analog for another country is $0.009/row plus a $0.02 start
fee.

### FAQ

**Is this the same as Zefix?**
No. Zefix is the current-state company register; SHAB is the **gazette**, the dated stream of
register *events*. This Actor reads only the "new registration" event, which is what makes it a
new-business feed rather than a directory lookup.

**Can I see companies before they are officially published?**
Yes — that is the point of **"Include tomorrow's gazette"** (on by default), which reaches the
window 7 days forward instead of stopping at today. SHAB loads a publication into the API days
before its publication date: on all **1,890 of 1,890** rows of the run above, `publicationDate` was
**2 days after `creationDate` (1,139 rows) or 4 days after it (751 rows)** — never the same day. The
forward queue is a business-day queue, though: read on a Saturday (2026-09-05, 22:00 UTC) the
window 2026-09-06…2026-09-20 held 0 publications, and the Actor simply widened backwards and
returned the last 14 days of real registrations instead of an empty dataset.

**How do I build a niche list, e.g. new dental practices?**
Use **`keyword`** for a server-side full-text search over the whole notice (re-measured
2026-09-05: `Zahnarzt` 72 hits, `Softwareentwicklung` 1,254, `Treuhand` 6,698 across the archive),
and/or
**`purposeKeywords`** to filter on the statutory purpose after the record is fetched. Combine with
`cantons` and a date window. **Widen the window for a niche this narrow:** 72 `Zahnarzt` hits across
404,662 archived registrations is roughly one every three weeks, so on the default one-day window
that search legitimately returns nothing most days. It says so precisely — *"the gazette published
244 new registration(s) in 2026-09-04 … 2026-09-04, but none of them matched your keyword
'Zahnarzt'"* (run `Khe1Nj4EIg5ed13TW`) — rather than blaming the gazette calendar. Try
`lookbackDays: 90`.

**How do I run this weekly and only get new companies?**
Turn on **"Skip companies seen in earlier runs"**. The Actor remembers every publication it has
**delivered** in a named key-value store that survives between runs, so a schedule only ever
returns — and only ever bills — genuinely new registrations. (It remembers only what it actually
delivered: a run stopped by `maxItems` will not skip the companies it never returned.)

**Can I get one row per founder?**
Yes — **"One row per person"**. Each row carries the full company columns plus that person's name,
role, signature authority, residence and origin. You are billed once per company.

**How far back does it go?**
2018-01-01. Yearly volumes, re-measured against the live API on 2026-09-05: 2018 = 14,310 ·
2019 = 44,616 · 2020 = 46,842 · 2025 = 55,654. 2017 returns 0. A full historical backfill is
404,662 registrations.

**Can I look up one specific company?**
Yes — paste a **CHE UID**, a company name, a SHAB publication ID or a shab.ch URL. Re-checked
2026-09-05 on 15 UIDs drawn at random from the 1,890-row run: **15 of 15** resolved to exactly one
publication — the right one — across all 404,662 records. A **broad** name, though, resolves
through one full-text call that reads the newest **1,000** matches (`Treuhand` matched 6,704 on
2026-09-07, run `8TFK3BmsUDJ6tixhO`) —
when that limit bites, the run's status message says so and tells you to narrow with a date window
or cantons. It is never silently truncated.

**What about the other gazette rubrics?**
Out of scope on purpose. HR02 (mutations, 1,648,694 publications) and HR03 (deletions, 248,284 —
both re-counted live on 2026-09-05) are
different products with different buyers. This Actor does one site and one function: new
registrations.

**Do the German, French and Italian regions all work?**
Yes. The register publishes in the language of the canton; all three parse. Archive split
(re-counted 2026-09-05): German 272,438 · French 112,595 · Italian 19,629. The 1,890-row run above
was 1,311 German / 503 French / 76 Italian.

**Will it break if a run has no results?**
No. A day with no gazette, or a filter that matches nothing, exits **cleanly** with an explanation
in the status message. The Actor only fails loudly when the data would be **wrong** — for example
when the API declares more publications for a day than it returns.

### Data source, legality and fair use

Data comes from the public API of **www.shab.ch**, the Swiss Official Gazette of Commerce published
by the Federal Office for the Register of Commerce. Publication is **statutory**: HRegV Art. 9 and
Art. 35 require these entries to be public, and the API returns that legal basis on every record
(`legalBasis`). No login, no API key, no access control and no anti-bot measure is bypassed by this
Actor — it reads the same public JSON and XML endpoints the site's own front end reads.

`https://www.shab.ch/robots.txt` is, in full:

```
User-agent: *
Disallow: /
```

**Personal data — read this.** These records name individual people: founders, managing officers,
their role, their signature authority, their town of residence and their place of origin or
nationality. They are statutorily public, but they remain personal data under the Swiss **FADP**
and, for officers resident in the EU, the **GDPR**. **You are the controller for any onward
processing** — that includes any outreach you do with this data, and any obligation to inform the
people in it. If you do not want personal data at all, switch **"Extract founders and officers"**
off and the Actor returns company-only rows.

You are responsible for complying with SHAB's terms and with the data-protection law of your
jurisdiction and theirs. Rate limits, robots directives and volume are your call to make; this
Actor gives you the controls (`requestConcurrency`, `maxItems`, `maxDaysToCrawl`) to be a good
citizen.

# Actor input Schema

## `lookbackDays` (type: `integer`):

How many publication days back from today to crawl, when you have not set explicit dates below. 1 = today only. The Actor issues exactly ONE request per publication day (never offset paging, see the README for why that matters), so 30 days = 30 list requests.

## `dateFrom` (type: `string`):

YYYY-MM-DD. Overrides the lookback window. Day-granular and verified server-side. The archive starts 2018-01-01 (2017 returns 0 rows).

## `dateTo` (type: `string`):

YYYY-MM-DD. Overrides the lookback window.

## `includeFuturePublications` (type: `boolean`):

SHAB loads a publication into the API up to ~2 days BEFORE its official publication date. With this on, the default window reaches 7 days forward, so you see registrations before they are formally gazetted. Measured 2026-09-03: the window 2026-09-04 to 2026-09-10 already returned 244 rows created 2026-09-02. That head start is the buyer's real edge. Turn it off for a strict historical export.

## `cantons` (type: `array`):

Server-side filter, verified additive (ZH 73,011 + VD 39,458 = 112,469 together). Counts in brackets are that canton's total HR01 registrations since 2018, measured live 2026-09-04. Leave empty for all of Switzerland.

## `keyword` (type: `string`):

Searched server-side across the entire publication text: company name, business purpose, address and the named officers. This is the lever that turns the gazette into a niche lead list. Measured hit counts across the whole archive: Zahnarzt 72, Softwareentwicklung 1,254, Treuhand 6,698, postcode 8001 gives 2,789, an exact CHE UID gives exactly 1.

## `publicationLanguage` (type: `string`):

The language the cantonal register published in, a good proxy for the language region. Server-side. Measured archive split: German 272,438, French 112,595, Italian 19,629.

## `uids` (type: `array`):

Swiss UIDs in the form CHE-123.456.789. Verified to resolve to exactly one publication on 12 of 12 spot checks across all 404,662 records.

## `companyNames` (type: `array`):

Exact or partial company names, resolved through the same server-side full-text search.

## `publicationIds` (type: `array`):

The publication UUID from a shab.ch detail URL. Fetched directly. Anything that is not an HR01 new registration is skipped with a warning rather than silently returned.

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

Paste shab.ch publication links or raw API URLs. The publication UUID is read out of each one. A URL carrying no UUID is skipped with a warning.

## `legalForms` (type: `array`):

Keep only these legal forms. Empty = all. The raw 4-digit register code is always emitted in the legalForm field regardless, and legalFormLabel is null for any code we have not seen in a live publication rather than guessed at (measured 99.5% labelled over 400 consecutive registrations).

## `excludeBranches` (type: `boolean`):

On by default. A branch (Zweigniederlassung / succursale) is a new office of a company that already exists, so it carries no founders and no share capital and is a weak lead. Measured 3.6% of registrations, and all 5 records in our 250-doc sample where no person could be parsed were branches.

## `minShareCapitalChf` (type: `integer`):

Keep only companies whose registered nominal capital is at least this. Capital is present on 62.8% of registrations. It is absent BY LAW on sole proprietorships, not missing data, so any minimum implicitly drops them.

## `maxShareCapitalChf` (type: `integer`):

Keep only companies at or below this nominal capital. Useful for targeting the CHF 20,000 GmbH floor rather than large incorporations.

## `requireCapital` (type: `boolean`):

Drops sole proprietorships and other forms that register no capital.

## `requirePaidUpFull` (type: `boolean`):

Keeps only companies whose paid-in capital equals the nominal capital, a solvency signal for finance and leasing buyers.

## `zipCodes` (type: `array`):

Exact Swiss postcodes of the registered office, e.g. 8001. Empty = anywhere.

## `townContains` (type: `string`):

Substring match against the registered town and the registered seat, case-insensitive.

## `requireStreetAddress` (type: `boolean`):

Drops the rare registration filed with no domicile address. Measured 100% street, 100% postcode and 99.2% house number on a 250-record sample, so this removes very little.

## `purposeKeywords` (type: `array`):

Matched case-insensitively against the statutory business purpose, the full register text and the company name. This is what turns the feed into a vertical: Zahnarzt / cabinet dentaire, Bauunternehmen, Restaurant, Immobilien, Software. Every Swiss company must file a purpose, and the field is present on 97.2% of records.

## `purposeKeywordsMode` (type: `string`):

ANY keeps a company matching at least one keyword (a vertical). ALL keeps only companies matching every keyword (a precise niche).

## `excludeKeywords` (type: `array`):

Drop any company whose purpose, register text or name contains one of these. Applied after the include filters.

## `requireRegisteredPersons` (type: `boolean`):

Keeps only rows where at least one named person was parsed out of the register text. Measured on 250 records: 98.0% overall and 100.0% of non-branch registrations. See the README honest-limits section: the register does not publish persons as structured XML.

## `registrationOfficeContains` (type: `string`):

Substring match against the filing office name, e.g. Zurich or Geneve. Mostly redundant with the canton filter, but exposed for exact office-level exports.

## `includeDetail` (type: `boolean`):

ON (default): one extra request per company fetches the register XML, giving UID, address, legal form, share capital, business purpose and the named founders. OFF: list metadata only (headline, date, canton, register office) with NO UID, address, capital or persons. List-only rows are billed at a separate, much cheaper event.

## `extractRegisteredPersons` (type: `boolean`):

Parse the named persons out of the register text into a structured array. Turn this OFF for a company-only export containing no personal data at all.

## `personsAsSeparateRows` (type: `boolean`):

Emit one dataset row per named founder or officer, each carrying the full company columns, which is the shape a CRM import wants. You are still billed ONCE PER COMPANY, never per person.

## `includeFullPublicationText` (type: `boolean`):

The complete published notice in German, French or Italian. Present on 100% of records and the honest fallback wherever person parsing is imperfect.

## `includePurpose` (type: `boolean`):

The full statutory purpose clause, often 1,000 to 2,500 characters.

## `purposeMaxChars` (type: `integer`):

0 keeps the whole clause. Set e.g. 300 if you are exporting to Google Sheets, where multi-thousand-character cells are painful.

## `legalFormLabelLanguage` (type: `string`):

Language of the human-readable legalFormLabel. The raw 4-digit code stays in legalForm.

## `includeTitleTranslations` (type: `boolean`):

SHAB publishes each headline in German, French, Italian and English. English is always emitted; this adds the other three.

## `includePublicationUrl` (type: `boolean`):

A direct link to the published notice on shab.ch. A Zefix company link is always included.

## `includeXmlUrl` (type: `boolean`):

The API URL of the underlying register XML, so you can audit any row back to the source bytes.

## `includePdfUrl` (type: `boolean`):

The officially signed PDF of the notice. Not every publication has one.

## `includeRawXml` (type: `boolean`):

Attaches the complete source XML to every row. An escape hatch for buyers who want fields we do not surface; it makes rows several kilobytes larger.

## `fieldsToInclude` (type: `array`):

Whitelist of output field names, e.g. companyName, uid, addressFull, primaryPerson. Empty keeps every field. A whitelist that matches nothing is ignored rather than emptying your rows.

## `flattenOutput` (type: `boolean`):

Flattens nested objects and arrays into dot-notation columns (registeredPersons.0.fullName and so on) so a CSV or Google Sheets export is readable.

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

Hard cap on billed companies. Set 0 for no cap, bounded then only by your date window and the run timeout.

## `maxDaysToCrawl` (type: `integer`):

Stop after this many publication days, whatever the date window says. 0 means no limit. A safety rail for large historical backfills.

## `dedupeBy` (type: `string`):

The same publication is NEVER delivered or billed twice; that guard is always on. This chooses whether a second, company-level pass also collapses two publications sharing one CHE UID (rare in HR01, but possible across a wide window).

## `dedupeAgainstPreviousRuns` (type: `boolean`):

Remembers every publication ID in a NAMED key-value store that survives between runs, so a daily or weekly schedule only ever returns, and only ever bills, genuinely new registrations.

## `onlyNewSinceLastRun` (type: `boolean`):

Begins the date window at the newest publication date any previous run delivered, instead of the lookback window. Uses the same named store.

## `namedStateStoreKey` (type: `string`):

Optional. Which named key-value store holds the run-to-run memory. Defaults to shab-new-companies-state. Give separate schedules separate names so they do not share memory.

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

Newest publication day first, or oldest first, which is better for a chronological backfill.

## `requestConcurrency` (type: `integer`):

Parallel register-XML fetches. Measured success through the Apify datacenter proxy: 5 gave 100% (15/15), 10 gave 100% (30/30), 20 gave 95% (57/60, and all 3 losses were proxy-side socket resets, never a block from shab.ch). 10 is the tested sweet spot.

## `maxRequestRetries` (type: `integer`):

Across 554 recon requests, 98.0% succeeded first try and 100% succeeded after at most one retry. Every loss was an Apify-proxy socket reset: no CAPTCHA, no 403, no rate limit.

## `requestTimeoutSecs` (type: `integer`):

How long a single request may take before it is retried.

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

Apify datacenter proxy is the default and is all this Actor needs: measured 200 OK on datacenter, on residential Switzerland and on residential US, all returning identical data. Residential was 5x slower for no benefit. Pin a country only if your own policy requires it.

## `webhookUrl` (type: `string`):

Optional. POSTed a JSON summary at the end of the run: company count, the run and dataset IDs, and up to 50 sample companies. Pair it with the memory store for a genuine new-registration alert.

## `slackWebhookUrl` (type: `string`):

Optional. Posts a formatted digest of the newest registrations to a Slack incoming webhook.

## `notifyOnlyNew` (type: `boolean`):

Restricts the webhook and Slack alerts to publications not seen by a previous run. Uses the same named memory store.

## Actor input object example

```json
{
  "lookbackDays": 1,
  "dateFrom": "2026-08-01",
  "dateTo": "2026-08-31",
  "includeFuturePublications": true,
  "cantons": [],
  "keyword": "Treuhand",
  "publicationLanguage": "any",
  "uids": [
    "CHE-103.703.601"
  ],
  "companyNames": [],
  "publicationIds": [],
  "startUrls": [],
  "legalForms": [],
  "excludeBranches": true,
  "requireCapital": false,
  "requirePaidUpFull": false,
  "zipCodes": [],
  "townContains": "",
  "requireStreetAddress": false,
  "purposeKeywords": [
    "Zahnarzt",
    "cabinet dentaire"
  ],
  "purposeKeywordsMode": "any",
  "excludeKeywords": [],
  "requireRegisteredPersons": false,
  "registrationOfficeContains": "",
  "includeDetail": true,
  "extractRegisteredPersons": true,
  "personsAsSeparateRows": false,
  "includeFullPublicationText": true,
  "includePurpose": true,
  "purposeMaxChars": 0,
  "legalFormLabelLanguage": "en",
  "includeTitleTranslations": false,
  "includePublicationUrl": true,
  "includeXmlUrl": false,
  "includePdfUrl": false,
  "includeRawXml": false,
  "fieldsToInclude": [],
  "flattenOutput": false,
  "maxItems": 100,
  "maxDaysToCrawl": 0,
  "dedupeBy": "publicationId",
  "dedupeAgainstPreviousRuns": false,
  "onlyNewSinceLastRun": false,
  "namedStateStoreKey": "",
  "sortOrder": "desc",
  "requestConcurrency": 10,
  "maxRequestRetries": 3,
  "requestTimeoutSecs": 60,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "webhookUrl": "",
  "slackWebhookUrl": "",
  "notifyOnlyNew": false
}
```

# Actor output Schema

## `companies` (type: `string`):

Company name, CHE UID, full street address, canton, legal form, share capital, statutory business purpose, cantonal register office, the named founders and officers, and links to the SHAB notice and the Zefix company record.

# 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 = {
    "lookbackDays": 1,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/shab-new-companies-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 = {
    "lookbackDays": 1,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/shab-new-companies-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 '{
  "lookbackDays": 1,
  "maxItems": 100
}' |
apify call scrapersdelight/shab-new-companies-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/shab-new-companies-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/3fZI4Ma2QidQkNBFF/builds/FjCZbjswSn4Wd7opf/openapi.json
