Skip to contents

tidybrreg provides tidy access to Norway’s Central Coordinating Register for Legal Entities (Enhetsregisteret), maintained by the Brønnøysund Register Centre at data.brreg.no. The register contains approximately 1 million active entities — companies, partnerships, sole proprietorships, associations, and government bodies.

The package is a thin, typed client: fifteen functions that each wrap one register endpoint and return a tibble with English column names. Persistence, synchronisation and panel construction live in the companion package tidybrregpanel.

Installation

# From r-universe (pre-built binaries)
install.packages("tidybrreg",
  repos = c("https://sondreskarsten.r-universe.dev",
            "https://cloud.r-project.org"))

# Or from GitHub
pak::pak("sondreskarsten/tidybrreg")

Look up a single entity

Every Norwegian legal entity has a unique 9-digit organization number (organisasjonsnummer). Look up Equinor ASA:

library(tidybrreg)

brreg_entity("923609016")
#> # A tibble: 1 × 63
#>   org_nr    name        legal_form founding_date employees nace_1
#>   <chr>     <chr>       <chr>      <date>            <int> <chr>
#> 1 923609016 EQUINOR ASA ASA        1972-09-18        21408 06.100

The result is a tibble with English column names mapped from the Norwegian API via the package’s field_dict. Only the fields the register emitted for that entity are present: a sole proprietorship carries no employees or founding_date, a foreign branch no municipality_code. Test for a column with %in% names() rather than assuming it. Two columns are always present: registry (which registry answered) and deleted.

A deleted entity is returned, not hidden. Both of the register’s signals (HTTP 410, and HTTP 200 with respons_klasse = "SlettetEnhet") yield deleted = TRUE, a parsed deletion_date, the remaining observed fields, and a tidybrreg_warning_deleted.

Translate codes to labels

By default, functions return raw codes (ASA, 06.100). Two ways to get labels:

# Option 1: inline via type = "label"
brreg_entity("923609016", type = "label")

# Option 2: pipe to brreg_label() for more control
brreg_entity("923609016") |>
  brreg_label(code = c("legal_form", "nace_1"))
#> legal_form      = "Public limited company"
#> legal_form_code = "ASA"  (original code preserved)
#> nace_1          = "Extraction of crude petroleum"
#> nace_1_code     = "06.100"

# Norwegian labels
brreg_label(c("AS", "ENK"), dic = "legal_form", lang = "no")

The code = argument keeps the original code in a _code suffixed column alongside the label — following the eurostat package’s pattern. Legal-form and role labels are bundled; NACE and sector labels come from the SSB KLASS API on first use and are cached for the session. Set options(tidybrreg.offline = TRUE) to stay on the bundled English dictionaries; see ?get_brreg_dic.

Search for entities

Query by name, legal form, geography, industry, employee count, or any combination:

# Large private companies in Oslo
brreg_search(
  legal_form = "AS",
  municipality_code = "0301",
  min_employees = 500,
  max_results = 10
)

Search results are paginated automatically up to max_results. The register’s search window is 10,000 results: when a query matches more than that and you ask for more than the window, the call aborts with a tidybrreg_error_result_window instead of returning a partial population. When fewer rows are returned than matched, the result carries attr(x, "complete") == FALSE and attr(x, "total_matches") and a tidybrreg_warning_truncated is signalled. For larger extractions, use brreg_download().

Sub-entities (establishments)

Use registry = "underenheter" to search sub-entities — branch offices, plants, and establishments linked to a parent entity:

brreg_search(name = "Equinor", registry = "underenheter", max_results = 5)
brreg_underenheter("923609016")

Retrieve roles, groups and signing authority

Board members, officers, and auditors for any entity:

roles <- brreg_roles("923609016")
roles
#> # A tibble: 25 × 17
#>   org_nr    role_group        role              first_name last_name birth_date
#>   <chr>     <chr>             <chr>             <chr>      <chr>     <date>
#> 1 923609016 Board of Directors Chair of the Board Jon Erik   Reinhardsen 1960-07-14
#> 2 923609016 Board of Directors Board member      ...

# Roles Equinor holds in other entities
brreg_roles_legal("923609016")

# The corporate group tree
brreg_konsern("923609016")

# Who may sign for the entity, and procuration holders
brreg_signatur("923609016")
brreg_prokura("923609016")

These per-entity endpoints share one status contract (see ?brreg_roles): HTTP 404 returns the typed zero-row tibble with attribute http_status = 404L and no warning (the ordinary case for a company that is in no group), HTTP 410 warns about deletion, and any other failure is a tidybrreg_error_http.

Follow changes

The change data capture feeds report what changed since an instant:

brreg_updates(since = "2026-03-01T00:00:00Z", size = 1000, max_pages = 10)
brreg_update_fields(since = Sys.Date() - 1, size = 500)
brreg_updates(type = "roller", since = Sys.Date() - 1)

since is sent as a UTC instant and timestamps come back as UTC POSIXct. The result carries complete, pages_fetched and cursor attributes; pass cursor + 1 to resume.

Bulk download the full register

Three registries available:

# Main entities: ~196 MB JSON
entities <- brreg_download(type = "enheter")

# Sub-entities: ~75 MB JSON
sub_entities <- brreg_download(type = "underenheter")

# All roles for all entities: ~131 MB JSON
all_roles <- brreg_download(type = "roller")

# Only the file
path <- brreg_download(type_output = "path")

Downloads are cached in tools::R_user_dir("tidybrreg", "cache"). Use refresh = TRUE to force re-download, or refresh = "auto" to re-download only when the server’s validators (ETag, Last-Modified) differ from the cached copy’s.

Conditions

Every error and warning the package raises has a class you can catch or silence selectively; see ?tidybrreg_conditions.

tryCatch(
  brreg_search(municipality_code = "4601", max_results = 20000),
  tidybrreg_error_result_window = function(e) e$total_matches
)
suppressWarnings(brreg_konsern("923609016"), classes = "tidybrreg_warning_deleted")

Function → API endpoint mapping

Function API endpoint Returns
brreg_entity(org_nr) /enheter/{orgnr} 1-row tibble
brreg_entity(org_nr, registry = "underenheter") /underenheter/{orgnr} 1-row tibble
brreg_search(...) /enheter?... N-row tibble
brreg_search(..., registry = "underenheter") /underenheter?... N-row tibble
brreg_underenheter(org_nr), brreg_children(org_nr) /underenheter?overordnetEnhet=, /enheter?overordnetEnhet= N-row tibble
brreg_roles(org_nr) /enheter/{orgnr}/roller N-row tibble
brreg_roles_legal(org_nr) /roller/enheter/{orgnr}/juridiskeroller N-row tibble
brreg_konsern(org_nr) /konsernstruktur/{orgnr} N-row tibble
brreg_signatur(org_nr), brreg_prokura(org_nr) fullmakt/enheter/{orgnr}/signatur, .../prokura N-row tibble
brreg_download("enheter") /enheter/lastned Full register tibble
brreg_download("underenheter") /underenheter/lastned Full sub-entity tibble
brreg_download("roller") /roller/totalbestand Full roles tibble
brreg_updates(type = "enheter"), brreg_update_fields() /oppdateringer/enheter Change events tibble
brreg_updates(type = "roller") /oppdateringer/roller Change events tibble
get_brreg_dic("nace") SSB KLASS classifications/6/codesAt Dictionary tibble

Next steps

  • vignette("business-data") — Norwegian legal forms, NACE codes, and data quirks
  • The tidybrregpanel package — snapshots, synchronisation, panels, flows, networks
  • The tidybrregmcp package — the same fifteen functions as Model Context Protocol tools