# Norway Companies Scraper (`normdata/norway-companies-scraper`) Actor

Scrape Norway's Brønnøysund company register by name or filter (legal form, NACE, municipality, employees, VAT, dates). Clean firmographics with CEO, board, annual accounts, address and share capital. Batch lookup by org number, sub-units of a parent, and a change feed for CRM sync.

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

## Pricing

from $11.90 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

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

![Norm Data](https://i.ibb.co/rGbhM5Y8/Chat-GPT-Image-Sep-8-2026-02-20-50-PM.png)

## 🇳🇴 Norway Companies Scraper

Scrape the **Norwegian company register** (Brreg / Brønnøysundregistrene, the Brønnøysund
Register Centre) with no API key and no login. Search over a million Norwegian entities by name
or by structured filters, look up a batch of organisation numbers, pull every establishment of a
company, or read the register's change feed. Get clean structured **company data for KYB,
compliance and B2B lead generation**: legal form, NACE industry codes, addresses, employees, VAT
(MVA) and bankruptcy status, the full **board, chair, CEO and auditor**, share capital, and filed
**annual accounts**.

Here is one real row (trimmed), for Equinor ASA:

```json
{
  "org_number": "923609016",
  "name": "EQUINOR ASA",
  "active": true,
  "age_years": 53,
  "org_form": "ASA",
  "org_form_label": "Allmennaksjeselskap",
  "industry_code": "06.100",
  "industry_label": "Utvinning av råolje",
  "sector_label": "Statlig eide aksjeselskaper mv.",
  "employees": 21239,
  "ceo": "Anders Opedal",
  "chair": "Jarle Kjell Roth",
  "website": "www.equinor.com",
  "phone": "51 99 00 00",
  "business_address": "Forusbeen 50",
  "business_city": "STAVANGER",
  "business_municipality": "STAVANGER",
  "founded_date": "1972-09-18",
  "registered_date": "1995-03-12",
  "vat_registered": true,
  "bankrupt": false,
  "under_liquidation": false,
  "part_of_group": true,
  "share_capital": 5976872600,
  "share_capital_currency": "NOK",
  "historical_names": [{ "name": "STATOIL ASA", "from": "2001-05-11", "to": "2018-05-16" }],
  "officers": [
    { "role_code": "DAGL", "role": "Daglig leder", "name": "Anders Opedal", "is_person": true, "birth_date": "1968-05-04", "active": true }
  ],
  "annual_accounts": [
    { "year": "2025", "currency": "USD", "revenue": 67956000000, "operating_result": 5563000000, "annual_result": 5731000000, "total_assets": 103432000000, "total_equity": 39182000000, "total_debt": 64249000000 }
  ],
  "url": "https://virksomhet.brreg.no/nb/oppslag/enheter/923609016",
  "query": null,
  "error": null,
  "scraped_at": "2026-09-08T15:20:57.000Z"
}
```

### What it does

Reads Norway's central register of business entities (Enhetsregisteret and Regnskapsregisteret),
published as open data by the Brønnøysund Register Centre. Four modes:

- **Search companies** by name and any of: municipality, NACE industry code, legal form, postal
  code, employee range, institutional sector, VAT status, founding date range, registration date
  range, bankrupt-only. Filters combine with logical AND.
- **Look up by organisation number**: paste a batch of nine-digit numbers, get the full record
  for each. Works for companies and sub-units. Numbers that do not resolve come back as a row
  with `error: "not found"`, so the output always has one row per input. The KYB / CRM-refresh
  workflow.
- **Sub-units (establishments)**: every establishment (branch, site, department) registered
  under a parent company, each with its own address, employees and industry code. Or a
  standalone sub-unit search.
- **Change feed**: every entity registered or changed on or after a date, newest first. Keep a
  local copy in sync, or watch for new companies, bankruptcies and liquidations.

Two optional enrichments, on by default:

- **Board and CEO** (`includeRoles`): CEO, chair, and the full officer list with role codes,
  role names, birth dates, and an active flag. Company officers such as the auditor carry their
  own organisation number. One extra request per company.
- **Annual accounts** (`includeFinancials`): filed accounts for the years on record, with
  revenue, operating result, annual result, total assets, equity and debt. One extra request
  per company.

Missing source values are returned as `null`, never invented.

### Why this scraper

- **No API key, no login, no captcha.** Public open data, delivered clean and flat.
- **Two modes nobody else on Apify has:** every establishment of a company, and the register's
  change feed for monitoring and CRM sync.
- **Real KYB depth:** board, chair, CEO, auditor, share capital, sector code, group membership,
  historical names and statutory purpose on every record.
- **Multi-year financials:** revenue, results, assets, equity and debt from the filed accounts.
- **Export anywhere:** JSON, CSV or Excel, from the Apify API, CLI or any language.

### How it compares

| Capability | This actor | Other Brreg scrapers on Apify |
|---|:--:|:--:|
| Name search + organisation number lookup | yes | yes |
| Batch list of organisation numbers in one run | yes | some |
| Filters: municipality, NACE, legal form, postal code | yes | yes |
| Filters: employee range, VAT status, sector, date ranges | yes | some |
| Bankrupt-only filter | yes | rare |
| Officers: board, chair, CEO, auditor (full array with birth dates) | yes | names only, or none |
| Filed annual accounts, multi-year | yes | rare |
| **Sub-units: every establishment of a company** | **yes** | **no** |
| **Change feed: entities registered or changed since a date** | **yes** | **no** |
| Free-plan preview | yes | rare |

### Use cases

- **KYB and KYC / compliance.** Verify a Norwegian counterparty by organisation number, capture
  legal form, status, officers and financials for the onboarding file.
- **B2B lead generation.** Build targeted company lists by industry (NACE), municipality, size
  (employee range) or VAT status, with phone, website and address.
- **CRM enrichment.** Feed a list of organisation numbers and refresh every account with current
  registry fields, leadership and accounts.
- **Monitoring.** Run the change feed on a schedule to catch new registrations, name changes,
  bankruptcies and liquidations as the register publishes them.
- **Credit and risk.** Pull revenue, equity, liabilities and multi-year accounts for a portfolio
  of companies.
- **Location mapping.** Use sub-units mode to list every site a company operates from.

### Quickstart

```json
{
  "mode": "search",
  "query": "Equinor",
  "includeRoles": true,
  "includeFinancials": true,
  "maxItems": 10
}
```

Every AS company in Oslo with 20 to 100 employees, registered for VAT:

```json
{
  "mode": "search",
  "municipality": "0301",
  "orgForm": "AS",
  "employeesFrom": 20,
  "employeesTo": 100,
  "vatRegistered": "yes",
  "maxItems": 500
}
```

Refresh a list of companies:

```json
{ "mode": "lookup", "orgNumbers": ["923609016", "974760673"] }
```

Every establishment of a company:

```json
{ "mode": "subunits", "parentOrgNumber": "923609016" }
```

New or changed companies since a date:

```json
{ "mode": "updates", "changedSince": "2026-09-01", "maxItems": 1000 }
```

### Input reference

| Field | Applies to | Description |
|---|---|---|
| `maxItems` | all | Ceiling on rows written. |
| `mode` | all | `search`, `lookup`, `subunits` or `updates`. |
| `query` | search | Full or partial company name. |
| `municipality` | search | Municipality number (e.g. 0301 Oslo). |
| `industryCode` | search | NACE / SN2007 code, prefix match. |
| `orgForm` | search | Legal form code (AS, ASA, ENK, NUF, ...). |
| `postalCode` | search | Four-digit postal code. |
| `employeesFrom` / `employeesTo` | search | Registered employee range. |
| `sectorCode` | search | Institutional sector code. |
| `vatRegistered` | search | `any`, `yes`, `no`. |
| `bankruptOnly` | search | Only companies flagged bankrupt. |
| `foundedFrom` / `foundedTo` | search | Founding date range, YYYY-MM-DD. |
| `registeredFrom` / `registeredTo` | search | Entity-register date range, YYYY-MM-DD. |
| `orgNumbers` | lookup | Nine-digit organisation numbers. Separators are stripped. |
| `parentOrgNumber` | subunits | Return the establishments under this company. |
| `changedSince` | updates | YYYY-MM-DD. |
| `includeRoles` | search, lookup, subunits | Add CEO, chair and officers. |
| `includeFinancials` | search, lookup | Add filed annual accounts. |

### Output reference (selected)

Columns are ordered for reading: identity, classification, size, people, contact, address,
dates, status, then the nested and provenance fields.

| Field | Description |
|---|---|
| `name` | Registered name. |
| `org_number` | Nine-digit organisation number. |
| `active` | False when bankrupt, under liquidation, or under forced liquidation. |
| `org_form` / `org_form_label` | Legal form code and Norwegian label. |
| `industry_code` / `industry_label` (and `_2`, `_3`) | NACE codes and labels. |
| `sector_code` / `sector_label` | Institutional sector. |
| `employees` | Registered employee count. |
| `ceo` / `chair` / `officers` | Board and management (with `includeRoles`). |
| `website` / `phone` / `email` | Contact details where registered. |
| `business_address` ... `business_country` | Business address, broken into parts. |
| `postal_address` ... `postal_city` | Postal address. |
| `founded_date` / `age_years` / `registered_date` | Dates and derived age. |
| `vat_registered` / `vat_registered_date` | VAT (MVA) register status. |
| `bankrupt` / `bankruptcy_date` / `under_liquidation` / `under_forced_liquidation` | Distress flags. |
| `part_of_group` / `parent_org_number` | Group membership. |
| `share_capital` / `share_capital_currency` / `share_capital_shares` | Registered capital. |
| `historical_names` | Previous names with date ranges. |
| `annual_accounts` | Filed accounts per year (with `includeFinancials`). |
| `is_sub_unit` | True for establishment rows. |
| `change_type` / `changed_at` / `update_id` | Change-feed rows only. |
| `query` | In Look up mode, the number you asked for. `null` otherwise. |
| `error` | `null` on a normal row. `"not found"` on a Look up row whose number did not resolve (every other field is then `null`). |
| `url` | Link to the public registry page. |
| `scraped_at` | ISO 8601 timestamp of when the row was collected. |

### Run via API and CLI

```bash
curl -X POST "https://api.apify.com/v2/acts/USERNAME~norway-companies-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode":"search","municipality":"0301","orgForm":"AS","maxItems":200}'
```

```bash
apify call USERNAME/norway-companies-scraper --input '{"mode":"lookup","orgNumbers":["923609016"]}'
```

### Fetch results

```bash
## JSON
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=json"
## CSV
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"
## Paginate large datasets
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&offset=1000&limit=1000"
```

`<DATASET_ID>` is `defaultDatasetId` on the run object.

### Billing and limits

- **Pay per result.** Billed per company row written to the dataset. The current rates are on
  the Actor's Pricing tab.
- **Enrichment is billed separately, and only when it returns data.** With `includeRoles` on, a
  company adds one *detail record* charge when board / CEO data is found; with
  `includeFinancials` on, it adds one *financials record* charge only when the company has filed
  accounts. A company with no officers or no filed accounts is not charged the add-on, and
  sub-unit rows are billed as base rows only.
- **No charge on failure.** A run that produces zero rows fails with a message and is not billed.
- A Look up number that does not resolve still writes one `error: "not found"` row and is billed
  as a base row, so your output count matches your input list.
- **Free Apify plans** run the built-in 10-row sample only. Upgrade to run your own settings.
- A 1,000-company run with both enrichments on finishes in about a minute.

### FAQ and troubleshooting

**Do I need an API key or login?** No. The Norwegian company register is public open data, no
key, no login, no captcha.

**Can I look up a company by organisation number?** Yes, use `mode: "lookup"` with `orgNumbers`.
It accepts one or many, and resolves both companies and sub-units. A number that does not
resolve comes back as a row with `query` set and `error: "not found"`, so you keep one row per
input.

**A run returned 0 rows. Why?** The name or filter combination matched nothing. Loosen filters
(drop `municipality`, `industryCode` or the employee range), or check the spelling. Zero-row runs
are not charged.

**How does billing work?** Three line items on the Pricing tab: the base company row, an optional
*detail record* (board, CEO, officers) and an optional *financials record* (filed annual
accounts). The two add-ons are billed per company and only when that data is actually returned,
so you never pay for an empty column.

**Why are `ceo`, `chair` and `officers` missing?** `includeRoles` was off. Turn it on.

**Why is `annual_accounts` missing or empty?** Either `includeFinancials` was off, or the company
has not filed accounts (common for new, dormant or very small entities). Missing values are
`null`, never invented.

**How current is the data?** It reflects the register at run time. New registrations, status
changes and freshly filed accounts appear as soon as the register publishes them.

**Why are names and labels in Norwegian?** The register holds them as filed. It does not hold
English company names.

**Is this an official Brønnøysund tool?** No. Independent, not affiliated with the Brønnøysund
Register Centre. It reads only data the register publishes as open data.

### Local development

```bash
bun install
bun test              # offline: input parsing and normalisation against synthetic fixtures
bun run src/main.ts   # reads storage/key_value_stores/default/INPUT.json
```

# Actor input Schema

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

Caps how many rows this run writes to the dataset. Starts at 10 for a quick sample; raise it for a full run.

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

Search filters the register. Look up takes exact organisation numbers. Sub-units returns the establishments of a company. Change feed returns entities registered or changed since a date.

## `query` (type: `string`):

Full or partial company name. Leave empty to search the whole register with the filters below.

## `municipality` (type: `string`):

Norwegian municipality number, e.g. 0301 for Oslo, 1103 for Stavanger.

## `industryCode` (type: `string`):

NACE / SN2007 code, e.g. 62.010 for computer programming. Prefix matches work (62 covers all of IT services).

## `orgForm` (type: `string`):

Organisation form code, e.g. AS (private limited), ASA (public limited), ENK (sole proprietorship), NUF (foreign branch).

## `postalCode` (type: `string`):

Four-digit Norwegian postal code.

## `employeesFrom` (type: `integer`):

Minimum registered employee count.

## `employeesTo` (type: `integer`):

Maximum registered employee count.

## `sectorCode` (type: `string`):

Institutional sector code, e.g. 2100 for private non-financial companies.

## `vatRegistered` (type: `string`):

Filter by whether the company is in the VAT register.

## `bankruptOnly` (type: `boolean`):

Return only companies currently flagged as bankrupt.

## `foundedFrom` (type: `string`):

Earliest founding date, YYYY-MM-DD.

## `foundedTo` (type: `string`):

Latest founding date, YYYY-MM-DD.

## `registeredFrom` (type: `string`):

Earliest registration date in the entity register, YYYY-MM-DD.

## `registeredTo` (type: `string`):

Latest registration date in the entity register, YYYY-MM-DD.

## `orgNumbers` (type: `array`):

Nine-digit Norwegian organisation numbers. Spaces and other separators are stripped.

## `parentOrgNumber` (type: `string`):

Return every establishment (sub-unit) registered under this company.

## `changedSince` (type: `string`):

YYYY-MM-DD. Returns every entity registered or changed on or after this date, newest first.

## `includeRoles` (type: `boolean`):

Add the CEO, chair and full officer list (with roles and birth dates) to each company. Billed as a separate 'Detail record' event, and only for companies where role data is found. Turn off to skip it.

## `includeFinancials` (type: `boolean`):

Add the filed annual accounts (revenue, operating result, annual result, total assets, equity, debt) for the years on record. Billed as a separate 'Financials record' event, and only for companies that have filed accounts. Turn off to skip it.

## Actor input object example

```json
{
  "maxItems": 10,
  "mode": "search",
  "query": "Equinor",
  "vatRegistered": "any",
  "bankruptOnly": false,
  "includeRoles": true,
  "includeFinancials": true
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset row per company (or sub-unit, or change-feed entry).

# 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 = {
    "maxItems": 10,
    "mode": "search",
    "query": "Equinor",
    "vatRegistered": "any",
    "includeRoles": true,
    "includeFinancials": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/norway-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 = {
    "maxItems": 10,
    "mode": "search",
    "query": "Equinor",
    "vatRegistered": "any",
    "includeRoles": True,
    "includeFinancials": True,
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/norway-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 '{
  "maxItems": 10,
  "mode": "search",
  "query": "Equinor",
  "vatRegistered": "any",
  "includeRoles": true,
  "includeFinancials": true
}' |
apify call normdata/norway-companies-scraper --silent --output-dataset

```

## MCP server setup

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