Norway Company Contacts Scraper — Brreg Enhetsregisteret avatar

Norway Company Contacts Scraper — Brreg Enhetsregisteret

Pricing

$3.00 / 1,000 per unit returneds

Go to Apify Store
Norway Company Contacts Scraper — Brreg Enhetsregisteret

Norway Company Contacts Scraper — Brreg Enhetsregisteret

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.

Pricing

$3.00 / 1,000 per unit returneds

Rating

0.0

(0)

Developer

Scrapers Delight

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

🇳🇴 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:

FieldMain 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 all38.1%32.3%

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

SegmentAny contact
Sole traders (ENK)79.2%
VAT-registered units59.8%
Oslo (0301), all forms55.0%
Limited companies (AS)48.9%
Restaurants & food service (NACE 56)35.4%
Construction (NACE 43)25.4%
Registered since 2025-01-0111.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

FieldNotes
organisationNumber9-digit Norwegian organisation number. The join key for everything.
nameRegistered name
unitTypeenhet (main unit) or underenhet (sub-unit)
parentOrganisationNumberSub-units only — the parent's organisation number
legalFormCode / legalForme.g. AS / Aksjeselskap
previousNamesEvery former registered name, as a list

Contact — the product

FieldNotes
emailepostadresse as registered
phonetelefon as registered, spacing preserved (51 99 00 00)
mobilemobil, kept separate from phone
websitehjemmeside, as registered (often without a scheme)
hasEmail / hasPhone / hasAnyContactBooleans, so you can filter and count without null checks. hasPhone covers both phone and mobile.

Location

FieldNotes
businessStreet, businessStreetLines, businessPostalCode, businessCity, businessMunicipality, businessMunicipalityNumber, businessCountry, businessCountryCodeThe 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

FieldNotes
naceCode1..3 / naceDescription1..3Up to three SN2007 codes with the register's own Norwegian text
auxiliaryIndustryCodehjelpeenhetskode, where present
sectorCode / sectorStatistics Norway institutional sector. Main units only.
employeesRegistered headcount. Read the next row before using it.
employeesRegisteredBoolean, present on 100% of rows. See Honest limits.
employeesRegisteredDateWhen 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:

{
"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

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

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

{
"unitTypes": ["enheter"],
"kommunenummer": ["4601"],
"registrertIMvaregisteret": "true",
"fraAntallAnsatte": 5,
"tilAntallAnsatte": 50,
"maxItems": 5000
}
{
"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

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

Newly registered limited companies

{
"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.

RowsCost
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, which also carries the Brreg name. They do not overlap:

This actorBankruptcy Notices Scraper
Surfacedata.brreg.no/enhetsregisteret — the register's REST APIw2.brreg.no/kunngjoring — the statutory gazette
A row isone registered unitone published bankruptcy notice
Corpus1,174,639 units + 864,237 sub-units~14,000–15,000 notices a year
Contactsthe company's own registered e-mail, phone, mobilethe appointed trustee's name and e-mail
Unique to itNACE, addresses, headcount, capital, VATcourt, 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.