# Norway Company Contacts Scraper — Brreg Enhetsregisteret (`scrapersdelight/brreg-enhetsregisteret-contacts-scraper`) Actor

Bulk Norwegian company contacts from Brreg's Enhetsregisteret open API: registered e-mail, phone, mobile and website, plus NACE codes, addresses, headcount, VAT and bankruptcy flags. Main units AND the 864,237 sub-unit locations. Filters by municipality, industry, legal form and size. $0.003/row.

- **URL**: https://apify.com/scrapersdelight/brreg-enhetsregisteret-contacts-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

$3.00 / 1,000 per unit 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?

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

## 🇳🇴 Norway Company Contacts Scraper — Brreg Enhetsregisteret

**The e-mail address, phone number, mobile number and website that Norwegian companies registered with the state — for all 1,174,639 registered units and all 864,237 of their operating locations, filtered by municipality, industry, legal form, size and registration date.**

This reads *Enhetsregisteret*, the Norwegian national entity register, through Brønnøysundregistrene's own open REST API at `data.brreg.no`. No login, no API key, no scraping of a website — this is the register's published machine interface, under an open-government licence that permits commercial reuse.

***

### 🤔 What does this actor do?

You describe a segment — *plumbers in Oslo*, *VAT-registered limited companies with 5–50 staff*, *everything registered in Bergen since January* — and it returns one clean row per registered unit, with whatever contact details that unit filed with the register.

- 📧 **Registered e-mail address** (`epostadresse`)
- ☎️ **Registered phone and mobile** (`telefon`, `mobil`) — kept as two separate fields, because a mobile reaches a sole trader and a switchboard does not
- 🌐 **Website** (`hjemmeside`)
- 🆔 **Organisation number** — the 9-digit key that joins to every other Norwegian dataset
- 🏢 **Legal form**, previous names, share capital, last filed annual accounts
- 🏭 **Up to three NACE industry codes**, each with the register's own Norwegian description
- 📍 **Business address and postal address**, split into street, post code, city, municipality and municipality number
- 👥 **Registered headcount**, with an explicit flag for whether a headcount was registered at all
- ⚖️ **Risk flags** — VAT registered, in the Foretaksregisteret, bankrupt (with date), under liquidation, under compulsory dissolution, part of a group
- 🏬 **Sub-units (`underenheter`)** — the individual shops, branches and depots, each carrying its **parent organisation number** and its **own** contact details and location
- 🧾 **Provenance on every row** — the exact partition and query that produced it, plus the NLOD licence, attribution and statutory basis

***

### 📊 How many rows actually have a contact? (the number most listings won't give you)

This is the honest centre of this actor, so it goes near the top rather than buried in a footnote. **The register stores contact fields. It does not populate them for every unit.** Measured 2026-09-19 with a stratified random sample — 6,400 rows per endpoint, drawn from a random page inside each of 32 registration-year strata and weighted by stratum size, so it is a register-wide estimate and not a page-one sample:

| Field | Main units (`enheter`) | Sub-units (`underenheter`) |
|---|---|---|
| **E-mail** (`epostadresse`) | **25.9%** | **22.8%** |
| **Mobile** (`mobil`) | **25.7%** | **18.4%** |
| **Phone** (`telefon`) | **15.3%** | **15.7%** |
| Website (`hjemmeside`) | 9.1% | 8.5% |
| **Any phone** (phone *or* mobile) | **34.5%** | **29.3%** |
| **Any contact at all** | **38.1%** | **32.3%** |

Fill varies enormously by segment, and the variation is more useful than the average. Measured on 2,000-row samples:

| Segment | Any contact |
|---|---|
| Sole traders (`ENK`) | **79.2%** |
| VAT-registered units | **59.8%** |
| Oslo (0301), all forms | 55.0% |
| Limited companies (`AS`) | 48.9% |
| Restaurants & food service (NACE 56) | 35.4% |
| Construction (NACE 43) | 25.4% |
| **Registered since 2025-01-01** | **11.2%** |

**Read the last row before you build a "new companies" campaign.** Newly registered companies are the classic prospecting list and they are the emptiest: a company registers first and files its contact details later, if ever. If you want reachable leads, filter on `registrertIMvaregisteret: "true"` or on sole traders, not on a recent registration date.

And if you only want the rows that are worth anything: **`onlyWithContact` drops the rest and you are not charged for them.**

***

### 🎯 What this does that the other Brreg actors don't

#### 1. It handles the register's 10,000-row wall for you

Enhetsregisteret refuses to page more than 10,000 rows deep into any one query. It says so itself:

```
HTTP 400  {"valideringsfeil":[{"feilmelding":"size * (page+1) kan ikke overstige 10_000"}]}
```

Oslo alone holds **208,868** main units. Every other Brreg actor either stops at 10,000 or, at best, tells you in its README to split the run by municipality and date yourself and merge the files afterwards.

This one does it. When a segment is bigger than the wall, it splits the query into registration-date slices that each fit under it, sweeps every slice, and checks the result. The date axis is used because it is the only one that always works: the registration date is present on **100%** of rows in both endpoints, the range ends are inclusive and the split is exact (2024 = 70,544 rows; January–June = 34,817; July–December = 35,727; the halves sum to the whole, with no off-by-one and no double count), and the busiest single day in the register holds 211 rows — three orders of magnitude under the cap, so the split always terminates.

#### 2. It counts what it got against what the register says exists

Every partition is compared against the endpoint's **own `totalElements`**, counted in **unique organisation numbers** — never in rows fetched, because those two numbers come apart the moment an ordering is unstable. Duplicate hits are counted and reported even though the measured duplicate rate on this API is zero. If a sweep comes up short, the run **fails** rather than handing you a partial register that reports success. Coverage per partition, the duplicate-hit count and any lost pages are all in `RUN_SUMMARY`.

A short parse is indistinguishable from a small register unless somebody checks. This checks.

#### 3. Sub-units — 864,237 operating locations

Most Brreg actors return only `enheter`: the legal entity, at its registered business address. A chain of 40 shops is one row at head office. The `underenheter` endpoint holds the **other 864,237 records** — the actual shops, branches, sites and depots, each with its own physical location, its own headcount, its own NACE code and, **22.8% of the time, its own e-mail address**. Every sub-unit row carries `parentOrganisationNumber` so you can roll it back up.

If you sell to locations rather than to legal entities, this is the half of the register you have been missing.

#### 4. You are told when your industry code doesn't exist

This is the one genuinely silent trap on this API, and it will bite you on another actor. `naeringskode` accepts **any** string. An unknown code returns **HTTP 200 with zero hits** — byte-for-byte the same answer as a real, empty segment.

Norway uses SN2007, whose five-digit codes are **not** the EU's. `43.220` is plumbing in the EU numbering; in Norway it does not exist, and the register returns a perfectly successful, completely empty result for it. The Norwegian codes are `43.221`, `43.222` and `43.223`.

Every code you supply is probed against the live register before the sweep starts. An unknown one is reported by name; if all of them are unknown, the run stops and tells you, instead of costing you nothing and teaching you nothing.

#### 5. Charge-on-delivery, with a contact filter

`onlyWithContact` and `requireEmail` are applied after the rows are read — the register offers no server-side filter for contact presence — and **you are charged only for rows that survive**. The run summary reports exactly how many units were examined against how many were delivered, so the ratio is never a mystery.

***

### 📦 What you get — every field

#### Identity

| Field | Notes |
|---|---|
| `organisationNumber` | 9-digit Norwegian organisation number. The join key for everything. |
| `name` | Registered name |
| `unitType` | `enhet` (main unit) or `underenhet` (sub-unit) |
| `parentOrganisationNumber` | Sub-units only — the parent's organisation number |
| `legalFormCode` / `legalForm` | e.g. `AS` / `Aksjeselskap` |
| `previousNames` | Every former registered name, as a list |

#### Contact — the product

| Field | Notes |
|---|---|
| `email` | `epostadresse` as registered |
| `phone` | `telefon` as registered, spacing preserved (`51 99 00 00`) |
| `mobile` | `mobil`, kept separate from `phone` |
| `website` | `hjemmeside`, as registered (often without a scheme) |
| `hasEmail` / `hasPhone` / `hasAnyContact` | Booleans, so you can filter and count without null checks. `hasPhone` covers both `phone` and `mobile`. |

#### Location

| Field | Notes |
|---|---|
| `businessStreet`, `businessStreetLines`, `businessPostalCode`, `businessCity`, `businessMunicipality`, `businessMunicipalityNumber`, `businessCountry`, `businessCountryCode` | The **operating** address. For a main unit this is `forretningsadresse`; for a sub-unit it is `beliggenhetsadresse`. Both land under one `business*` prefix so a mixed dataset joins on one column. This is also what the register's `kommunenummer` filter matches (measured 193/200 and 198/200 respectively — the handful that miss have only a postal address). |
| `postalStreet`, `postalPostalCode`, `postalCity`, `postalMunicipality`, `postalMunicipalityNumber`, … | `postadresse`, often a PO box |

#### Industry & size

| Field | Notes |
|---|---|
| `naceCode1..3` / `naceDescription1..3` | Up to three SN2007 codes with the register's own Norwegian text |
| `auxiliaryIndustryCode` | `hjelpeenhetskode`, where present |
| `sectorCode` / `sector` | Statistics Norway institutional sector. Main units only. |
| `employees` | Registered headcount. **Read the next row before using it.** |
| `employeesRegistered` | Boolean, present on 100% of rows. See *Honest limits*. |
| `employeesRegisteredDate` | When the headcount was last registered |

#### Status, risk & corporate detail *(main units only — the sub-unit endpoint does not serve these, and they are cut rather than shipped as a column of nulls)*

`vatRegistered`, `vatRegisteredDate`, `voluntaryVatDescriptions`, `registeredInBusinessRegister`, `businessRegisterDate`, `registeredInFoundationRegister`, `registeredInVoluntaryRegister`, `bankrupt`, `bankruptcyDate`, `underLiquidation`, `liquidationDate`, `underCompulsoryDissolution`, `partOfGroup`, `shareCapital`, `shareCapitalCurrency`, `shareCapitalType`, `numberOfShares`, `lastAnnualAccountsYear`, `auditorOptedOutDate`, `articlesDate`, `statedPurpose`, `activity`, `languageForm`, and the foreign-unit block (`homeCountryLegalForm`, `homeCountryRegistrationNumber`, `homeCountryRegisterName`, `governingLawCountry`).

*Sub-units instead carry `startDate` (`oppstartsdato`) and `ownershipChangeDate` (`datoEierskifte`), which main units do not have.*

#### Dates & provenance

`registeredDate`, `foundedDate`, `sourceUrl`, `registerUrl`, `scrapedAt`, plus:

- **`partition`** — `unitType`, `kommunenummer`, `naeringskode`, `registeredFrom`, `registeredTo`, `expectedTotal` and the literal `query` that produced this row. Merge three runs into one warehouse table and every row still knows where it came from.
- **`source`** — provider, API, NLOD licence and link, the exact attribution string the licence prescribes, a statement that field names were translated, and the statutory basis quoted verbatim.

***

### 📄 A real row

Not an illustration — this is an actual row, from the captured bytes the offline test suite runs against:

```json
{
  "organisationNumber": "811167452",
  "name": "AS DEN NATIONALE SCENE",
  "unitType": "enhet",
  "legalFormCode": "AS",
  "legalForm": "Aksjeselskap",
  "email": "dns@dns.no",
  "phone": "55 54 97 00",
  "mobile": null,
  "website": "www.dns.no",
  "hasEmail": true,
  "hasPhone": true,
  "hasAnyContact": true,
  "businessStreet": "Engen 1",
  "businessPostalCode": "5011",
  "businessCity": "BERGEN",
  "businessMunicipality": "BERGEN",
  "businessMunicipalityNumber": "4601",
  "postalStreet": "Postboks 78   Sentrum",
  "postalPostalCode": "5803",
  "naceCode1": "90.202",
  "naceDescription1": "Utøvende kunstnerisk virksomhet og underholdningsvirksomhet innenfor scenekunst",
  "sectorCode": "6100",
  "sector": "Statsforvaltningen",
  "employees": 184,
  "employeesRegistered": true,
  "registeredDate": "1995-03-12",
  "foundedDate": "1962-06-29",
  "vatRegistered": true,
  "bankrupt": false,
  "underLiquidation": false,
  "shareCapital": 102000,
  "shareCapitalCurrency": "NOK",
  "lastAnnualAccountsYear": "2025",
  "registerUrl": "https://virksomhet.brreg.no/nb/oppslag/enheter/811167452",
  "partition": {
    "unitType": "enheter",
    "kommunenummer": "0301",
    "naeringskode": "43.22",
    "expectedTotal": 676,
    "query": "kommunenummer=0301&naeringskode=43.22"
  },
  "source": {
    "provider": "Brønnøysundregistrene (Brreg) — Enhetsregisteret",
    "licence": "NLOD 2.0 — Norsk lisens for offentlige data",
    "attribution": "Inneholder data under Norsk lisens for offentlige data (NLOD) tilgjengeliggjort av Brønnøysundregistrene."
  }
}
```

***

### ⚙️ How to run it

#### Plumbers in Oslo with a contact detail

```json
{
  "kommunenummer": ["0301"],
  "naeringskode": ["43.22"],
  "onlyWithContact": true,
  "maxItems": 1000
}
```

#### Every VAT-registered company in Bergen with 5–50 staff

```json
{
  "unitTypes": ["enheter"],
  "kommunenummer": ["4601"],
  "registrertIMvaregisteret": "true",
  "fraAntallAnsatte": 5,
  "tilAntallAnsatte": 50,
  "maxItems": 5000
}
```

#### Every restaurant *location* in the country, not just the legal entities

```json
{
  "unitTypes": ["underenheter"],
  "naeringskode": ["56"],
  "requireEmail": true,
  "maxItems": 0
}
```

`maxItems: 0` means no cap. The segment is far bigger than the 10,000-row wall, so the actor splits it into registration-date slices automatically and asserts that each one came back whole.

#### Enrich a list you already have

```json
{
  "organisasjonsnummer": ["923609016", "811167452"],
  "unitTypes": ["enheter"]
}
```

#### Newly registered limited companies

```json
{
  "organisasjonsform": ["AS"],
  "fraRegistreringsdatoEnhetsregisteret": "2026-08-01",
  "maxItems": 2000
}
```

Expect a low contact fill here — **11.2%** for units registered since the start of 2025. That is the register, not the actor.

***

### 💰 Pricing

**$0.003 per unit delivered.** No subscription, no start fee, no charge for a run that returns nothing.

You are charged for rows **delivered to your dataset**. Units removed by your filters, dropped by `onlyWithContact`, or cut off by your `maxItems` cap are read but never billed.

| Rows | Cost |
|---|---|
| 100 (the default) | $0.30 |
| 1,000 | $3.00 |
| 10,000 | $30.00 |
| 100,000 | $300.00 |

`maxItems` is a budget as much as a limit — set it and you cannot be surprised.

***

### ⚖️ Source, licence and legality

**This is open government data, published by the state for reuse, and this actor uses the publication channel the state built for exactly this.**

- **Source:** `https://data.brreg.no/enhetsregisteret/api` — Brønnøysundregistrene's documented open REST API. No login, no API key, no registration. Brreg's own page says so: *"Det er ikke nødvendig å registrere seg for å ta datasettet i bruk."*
- **`robots.txt`:** `https://data.brreg.no/robots.txt` is **empty** — the host publishes no crawl restrictions at all.
- **Statutory basis:** Enhetsregisterloven § 22, *Innsyn – utlevering av opplysninger*: *"Enhver har rett til å få tilgang til opplysninger og dokumenter registrert i Enhetsregisteret. Dette gjelder ikke fødselsnummer og d-nummer."* — everyone has the right of access; national identity numbers are the exception. This actor never requests them.
- **Licence:** **NLOD 2.0** — Norsk lisens for offentlige data. The licence grants the right to *"kopiere, bruke og tilgjengeliggjøre informasjon"* — copy, use and make available — including commercially, **provided you attribute the contributor**.
- **Attribution, which the licence requires and this actor performs:** NLOD § 5 prescribes the wording, a link to the licence and to the source, and a statement when the data has been modified. All four are written onto **every row** in the `source` object, not merely mentioned here, so they survive an export into your warehouse:

  > *Inneholder data under Norsk lisens for offentlige data (NLOD) tilgjengeliggjort av Brønnøysundregistrene.*
  >
  > Licence: https://data.norge.no/nlod/no/2.0 · Source: `data.brreg.no/enhetsregisteret/api` · Modified by the licensee: field names translated to English and addresses flattened; values unchanged.

  **If you redistribute this data, that attribution travels with it — it is a licence condition, not a courtesy.**

**What this actor deliberately does not collect.** The register also exposes a `/roller` endpoint with the names and **dates of birth** of directors, chairs and general managers. It is reachable and it would be easy to add. It is not included: those are natural persons, the payload carries personal data that a business-contact product has no need for, and § 22's own exception marks the register's sensitivity on this axis. This is a **company** contact product. If you need officer data, that is a decision for you to take deliberately, with your own GDPR basis — not one to inherit by default from a lead-list tool.

**Not affiliated with, endorsed by, or connected to Brønnøysundregistrene.** The register is not responsible for anything done with this data, and NLOD § 7 disclaims warranties on data quality — which is worth remembering given the fill rates above.

***

### 🧭 How this differs from our Norway bankruptcy actor

We publish **[Norway Bankruptcy Notices Scraper — Brreg Konkurs Gazette](https://apify.com/scrapersdelight/brreg-bankruptcy-notices-scraper)**, which also carries the Brreg name. They do not overlap:

| | This actor | Bankruptcy Notices Scraper |
|---|---|---|
| **Surface** | `data.brreg.no/enhetsregisteret` — the register's REST API | `w2.brreg.no/kunngjoring` — the statutory gazette |
| **A row is** | one registered unit | one published bankruptcy notice |
| **Corpus** | 1,174,639 units + 864,237 sub-units | ~14,000–15,000 notices a year |
| **Contacts** | the **company's own** registered e-mail, phone, mobile | the appointed **trustee's** name and e-mail |
| **Unique to it** | NACE, addresses, headcount, capital, VAT | court, case number, claim deadline, fristdag, creditors' meeting |

Different host, different corpus, different row. They share exactly one column — the organisation number — which joins them cleanly if you want both.

***

### 🚧 Honest limits

- **The contact fields are sparse, and the table at the top is the real number.** 38.1% of main units publish any contact at all; 25.9% publish an e-mail. A register that *stores* a field is not a register that *populates* it. Use `onlyWithContact` and pay only for the rest.
- **`employees` is null far more often than a company has no staff, and null does not mean zero.** The register never serialises a zero — `"antallAnsatte":0` appears **0 times** in a 5,000-row raw sample while `"antallAnsatte":` appears 890 — and it omits the field both for a unit that registered zero and for one that never registered a count. Its own filter lumps the two together: `fraAntallAnsatte=0&tilAntallAnsatte=0` returns 996,848 and `fraAntallAnsatte=1` returns 177,791, which sum to exactly the 1,174,639 register total. So this actor does **not** convert an absent value to 0 — `Number(null)` is `0` and a fabricated zero reads as "dead company". Use the pair: `employeesRegistered: true` with `employees: null` means a registered headcount of zero; `employeesRegistered: false` means nobody ever filed one.
- **`navn` (name search) is case-sensitive in an undocumented way.** `Equinor` returns 179 hits and `equinor` returns 240 against the same register. That is the register's behaviour, not a bug here. Treat name search as a lookup convenience; use the structured filters for a bulk pull.
- **The sub-unit endpoint does not accept every filter.** `konkurs`, `underAvvikling` and `institusjonellSektorkode` are rejected there with HTTP 400. When you sweep both unit types with one of those set, it is applied to main units only and the run warns you and records it in `RUN_SUMMARY` — sub-unit rows in that dataset are not filtered by it.
- **The 10,000-row wall is handled, not abolished.** With `maxItems` at or under 10,000 a huge segment is read straight through to your budget and the partition is marked `limitedByDeepPagingCap` in the summary. Set `maxItems` above 10,000 or to 0 and the automatic date split kicks in and the coverage assertion applies. This is deliberate: splitting costs hundreds of sizing probes, and spending them for rows you capped away would be your money.
- **Industry filtering matches a prefix across all three NACE fields.** `naeringskode=62` returns 33,947 units, including some whose *first* code is something else but whose second or third is in 62. That is usually what you want from an industry filter; it is not an exact match on `naceCode1`.
- **Contact details are as good as the day the unit filed them.** The register does not verify or refresh them. A 2003 e-mail address is still in there.
- **No proxy by default, on purpose.** The API is open with no anti-bot. The same request measured 1.0s direct, 2.0s through a datacenter proxy and 3.0s through residential — identical HTTP 200 bodies. A proxy would cost you two to three times the wall-clock you are billed for and buy nothing. `proxyConfiguration` is there if your own network needs it.
- **Brreg also publishes a complete 210 MB gzipped dump** of the register at `/enheter/lastned`. If you genuinely want all 1.17 million rows and no filtering, that file is free and this actor is the wrong tool. This actor is for *segments* — filtered, deduplicated, coverage-checked, and charged per row.

***

### ❓ FAQ

**Is this legal?**
Yes, and it is not a grey area. Enhetsregisterloven § 22 makes the register public to everyone, Brreg publishes it through an open API that requires no registration, and NLOD 2.0 explicitly permits commercial reuse with attribution. The attribution the licence requires is written onto every row.

**Do I need a Brreg API key?**
No. There is no key and no registration. Brreg's own open-data page states it.

**How fresh is it?**
It is read live from the register at run time. `scrapedAt` on every row records the moment.

**Why do so many rows have no e-mail?**
Because the companies never filed one. Registering a contact is not mandatory. The measured rates are at the top of this page; `onlyWithContact` filters them out and you are not charged for them.

**What is the difference between `enheter` and `underenheter`?**
An `enhet` is the legal entity — the company. An `underenhet` is a place where it does business: a shop, a branch, a site. A chain with 40 shops is 1 `enhet` and 40 `underenheter`, and each sub-unit can have its own address, headcount and contact details. Sub-units carry `parentOrganisationNumber`, so you can always roll them up.

**Can I get more than 10,000 rows from one segment?**
Yes. Set `maxItems` above 10,000 or to 0 and the actor splits the query into registration-date slices under the register's cap, sweeps every slice and asserts that each came back whole.

**How do I know the result is complete?**
`RUN_SUMMARY` in the run's key-value store holds per-partition coverage: the register's own total before and after the sweep, unique organisation numbers read, duplicate hits, short pages and lost pages. If a completed sweep falls short of the register's own count, the run fails rather than reporting success over a partial corpus.

**My industry code returned nothing. Is the actor broken?**
Almost certainly the code does not exist in Norway's SN2007. The EU's five-digit codes are not Norway's — `43.220` is plumbing in the EU and does not exist here (use `43.221`). Every code you pass is probed against the live register first and an unknown one is named in the log and in `RUN_SUMMARY`.

**Can I get the directors and owners?**
Not from this actor, deliberately — see the licence section. Those are natural persons with dates of birth attached, and a company-contact product should not ship personal data by default.

**Does it include bankrupt companies?**
Yes, with `bankrupt`, `bankruptcyDate`, `underLiquidation` and `underCompulsoryDissolution` flags — around 3,250 units are flagged bankrupt at any time. Set `konkurs: "false"` to exclude them, or `"true"` to target only them. Main units only.

**Will it charge me for rows I filtered out?**
No. Billing is per row delivered to your dataset. Rows that fail a filter, fail the contact filter, or fall outside `maxItems` are never charged. If your Apify charge cap stops a run, the actor says so explicitly in the log rather than letting you think the register ran out.

**How do I find a municipality number?**
`0301` Oslo, `4601` Bergen, `5001` Trondheim, `1103` Stavanger, `3301` Drammen, `4204` Kristiansand. Note that Norway renumbered its municipalities in the 2020 reform, so a pre-2020 code is rejected at input time with a clear message instead of quietly returning nothing.

**Can I run this on a schedule?**
Yes. Combine `fraRegistreringsdatoEnhetsregisteret` with a daily or weekly Apify schedule to pull only newly registered units — but see the contact-fill caveat above before building a campaign on them.

***

*Independent tool. Not affiliated with or endorsed by Brønnøysundregistrene. Data from Enhetsregisteret under NLOD 2.0.*

# Actor input Schema

## `unitTypes` (type: `array`):

Which of the register's two endpoints to read. 'enheter' = main units, the 1.17 million registered companies, associations and sole traders. 'underenheter' = sub-units, the 864,000 individual operating locations (a branch, a shop, a depot), each linked to its parent by parentOrganisationNumber. Sub-units are where a chain's per-site contact details live. With both selected the row budget is split evenly between them, so a capped run returns a mix rather than only main units.

## `kommunenummer` (type: `array`):

Four-digit Norwegian municipality numbers, e.g. 0301 Oslo, 4601 Bergen, 5001 Trondheim, 1103 Stavanger. Several are swept as one partition each, so the run stays under the register's 10,000-row-per-query paging cap. The register matches a main unit on its business address (forretningsadresse) and a sub-unit on its physical location (beliggenhetsadresse) — the operating address in both cases, not the postal one. Leave empty for the whole country. Note that Norway renumbered its municipalities in the 2020 reform; a pre-2020 code is rejected at input time rather than silently returning nothing.

## `naeringskode` (type: `array`):

Norwegian SN2007 industry codes, matched as a PREFIX across a unit's first, second and third industry code. '43' means all of specialised construction, '43.22' means plumbing, heating and ventilation as a group, '43.221' means plumbing alone. Several codes are combined with OR. Careful: Norway's five-digit codes are NOT the EU's — 43.220 does not exist here and the register answers an unknown code with a perfectly successful, completely empty result, so every code you give is probed against the live register first and an unknown one is reported by name instead of silently contributing nothing.

## `organisasjonsform` (type: `array`):

Norwegian legal form codes, combined with OR. AS = aksjeselskap (limited company, 432,623 of them), ENK = enkeltpersonforetak (sole trader, 463,108), ASA = public limited, ANS / DA = partnerships, NUF = Norwegian branch of a foreign company, BEDR = sub-unit of a business, FLI = association, STI = foundation. Leave empty for all 44 forms.

## `onlyWithContact` (type: `boolean`):

Drop every unit that has registered no e-mail address, no phone and no mobile number — and charge you for nothing that was dropped. The register holds a contact for roughly 38% of main units and 32% of sub-units, so this is the difference between a list you can work and a list you have to clean. The register offers no server-side filter for it, so the rows are read and then discarded on our side; the run summary reports exactly how many were examined against how many were delivered.

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

Stricter than the setting above: keep only units with a registered e-mail address, ignoring phone-only ones. About 26% of main units qualify. Same deal — you are charged only for what is delivered.

## `registrertIMvaregisteret` (type: `string`):

Limit to units that are ('true') or are not ('false') in the VAT register. VAT registration is the closest thing the register has to a proof of real trading activity: 410,012 of the 1.17 million main units are registered, and their contact fill rate is far higher than the register average.

## `konkurs` (type: `string`):

Limit to units flagged bankrupt ('true', about 3,250 at any time) or exclude them ('false'). Main units only — the sub-unit endpoint rejects this filter, so sub-unit rows are never filtered by it and the run summary says so when you combine the two.

## `underAvvikling` (type: `string`):

Limit to units under voluntary liquidation, or exclude them. Main units only, like the bankruptcy filter.

## `fraRegistreringsdatoEnhetsregisteret` (type: `string`):

Earliest registration date in Enhetsregisteret. Newly registered companies are the classic prospecting list — they need an accountant, insurance, banking and software — but note they are also the thinnest on contact details: units registered since 2025-01-01 carry a contact only about 11% of the time, against 38% register-wide. Both ends of the range are inclusive.

## `tilRegistreringsdatoEnhetsregisteret` (type: `string`):

Latest registration date in Enhetsregisteret. Inclusive. This is also the axis the actor splits on internally when a single query would exceed the register's paging cap.

## `fraAntallAnsatte` (type: `integer`):

Smallest registered headcount. Beware what zero means here: the register omits the employee field entirely both for a unit that registered zero and for one that never registered a count at all, and its own filter lumps the two together (996,848 units sit in the 0-0 bucket, exactly the register total minus the 177,791 with one or more). Set this to 1 to get only units that have actually reported staff.

## `tilAntallAnsatte` (type: `integer`):

Largest registered headcount. Combine with the minimum to target a size band — 5 to 50 employees is 64,205 main units.

## `institusjonellSektorkode` (type: `string`):

Statistics Norway institutional sector code, e.g. 2100 for private non-financial limited companies (426,413 units) or 7000 for non-profit organisations. Main units only — the sub-unit endpoint rejects it.

## `navn` (type: `string`):

Free-text name search run by the register itself. Be aware it is case-sensitive in a way that is not documented: 'Equinor' returns 179 hits and 'equinor' returns 240 against the same register. Treat it as a convenience lookup, not as a reliable filter for a bulk pull.

## `organisasjonsnummer` (type: `array`):

Look up specific nine-digit Norwegian organisation numbers instead of sweeping. Useful for enriching a list you already have with the register's contact details.

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

Hard cap on delivered rows, and on what you are charged — you pay per row delivered, so a cap is a budget. Split evenly across the unit types you selected. Set to 0 for no cap. One thing to know: the register refuses to page more than 10,000 rows deep into any single query, so while this stays at or under 10,000 the actor reads a big municipality straight through; raise it past 10,000 (or set 0) and the actor automatically splits the query into registration-date slices that each fit under the cap, and asserts that every slice came back whole.

## `pageSize` (type: `integer`):

Advanced. The register serves up to 10,000 rows in one response, but big bodies truncate under HTTP 200: ten parallel 1,000-row requests produced a torn response, while 500 at the shipped concurrency produced none over repeated trials. 500 is the measured-safe default and there is little reason to change it. Every page is checked against its own declared size, so a torn body is retried rather than mistaken for the end of the data.

## `concurrency` (type: `integer`):

Advanced. How many register pages to read at once. 6 is the measured safe ceiling at the default page size; higher values start tearing response bodies rather than going faster.

## `maxPartitions` (type: `integer`):

Advanced. Safety guard on how many separate register queries one run may plan. Municipalities multiply by industry codes, so 40 municipalities and 10 codes is already 400 partitions before a single row is read. Raise it for a whole-register sweep, which needs roughly one date slice per 10,000 rows.

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

Advanced. Per-request timeout. The register answers a 500-row page in about a second directly and two to three seconds through a proxy.

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

Optional, and off by default on purpose. data.brreg.no is open government data with no anti-bot of any kind: the same request measured 1.0s direct, 2.0s through the Apify datacenter proxy and 3.0s through residential, all returning byte-identical HTTP 200. A proxy here buys nothing and costs you two to three times the wall-clock you are billed for. Turn it on only if your own network needs it.

## Actor input object example

```json
{
  "unitTypes": [
    "enheter",
    "underenheter"
  ],
  "kommunenummer": [
    "0301"
  ],
  "onlyWithContact": false,
  "requireEmail": false,
  "registrertIMvaregisteret": "any",
  "konkurs": "any",
  "underAvvikling": "any",
  "maxItems": 25,
  "pageSize": 500,
  "concurrency": 6,
  "maxPartitions": 400,
  "requestTimeoutSecs": 90,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `units` (type: `string`):

Organisation number, name, unit type, registered e-mail / phone / mobile / website, business and postal address, up to three NACE industry codes, legal form, sector, headcount, share capital, VAT and bankruptcy flags, registration dates, parent organisation for sub-units, and NLOD provenance.

## `runSummary` (type: `string`):

Per-partition coverage against the register's own totals, unique organisation numbers read, duplicate-hit count, pages lost, and the measured fill rate of e-mail / phone / mobile on this run's rows.

# 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 = {
    "kommunenummer": [
        "0301"
    ],
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/brreg-enhetsregisteret-contacts-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 = {
    "kommunenummer": ["0301"],
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/brreg-enhetsregisteret-contacts-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 '{
  "kommunenummer": [
    "0301"
  ],
  "maxItems": 25
}' |
apify call scrapersdelight/brreg-enhetsregisteret-contacts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/brreg-enhetsregisteret-contacts-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/leSm3IPjB0qDbuQCM/builds/HDcjGAE3SWVdyKC6x/openapi.json
