npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

getaddress-dk-api

v1.2.0

Published

TypeScript client for getaddress.dk, the DAWA-compatible Danish address API: autocomplete, adresser, adgangsadresser, reverse geocoding, vejnavne, postnumre, datavask, companies (CVR) and usage. DAWA's paths, parameters, field names and ids.

Readme

getaddress-dk-api

TypeScript client for getaddress.dk, the DAWA-compatible Danish address API — every address in Denmark, from the Danish Address Register (DAR). DAWA's paths, parameters, field names and ids. No dependencies; Node 18+ and every modern browser. Types included.

npm install getaddress-dk-api

Usage

On your server, with your API key:

import Client from 'getaddress-dk-api';

const api = new Client('your-api-key');

// Suggestions as text only: free.
const autocompleteResult = await api.adresserAutocomplete('Amagerbrogade 217A', { kun_tekst: true });

if (autocompleteResult.isSuccess) {
    const picked = autocompleteResult.toSuccess()[0];   // the one the user chose

    // The address picked: one look-up.
    const getResult = await api.adresse(picked.adresse, { struktur: 'mini' });

    if (getResult.isSuccess) {
        const adresse = getResult.toSuccess();
        console.log(adresse.vejnavn, adresse.husnr, adresse.etage, adresse['dør'], adresse.postnr, adresse.postnrnavn);
    }
} else {
    const failed = autocompleteResult.toFailed();
    console.log(failed.status, failed.message);
}

CommonJS works too: const { Client } = require('getaddress-dk-api');

Records keep DAWA's Danish field names — vejnavn, husnr, etage, dør, postnr, postnrnavn, kommunekode, x, y and the rest — so read dør as adresse['dør']. Ids are DAR's UUIDs, the same ids DAWA gave, so ids you have stored still work.

Suggestions are free; each address picked is one look-up. Pass kun_tekst: true to autocomplete, adresserAutocomplete or adgangsadresserAutocomplete and each suggestion carries only its text and the record's id and href, free (rate limited); fetch the one picked with adresse(id) or adgangsadresse(id). Without it the answer is DAWA's own, records included, and one that suggests addresses is a look-up.

In the browser

The API refuses an API key sent from a web page. In the browser, use a domain token (made in your console for your site's domain). Pass it where the key would go; the client sends it in the path, https://api.getaddress.dk/t/{dtoken_…}/autocomplete?q=…, as DAWA widgets do.

For a ready-made address field, use a widget instead of this client: ours, getaddress-dk-autocomplete, or DAWA's open-source dawa-autocomplete2 with baseUrl set to https://api.getaddress.dk/t/{your-domain-token}. Both are supported; see JavaScript Autocomplete.

import Client from 'getaddress-dk-api';

const api = new Client('dtoken_your-domain-token');

input.addEventListener('input', async () => {
    // Free: text-only suggestions.
    const result = await api.autocomplete(input.value, { caretpos: input.selectionStart, kun_tekst: true });
    if (!result.isSuccess) return;

    for (const suggestion of result.toSuccess()) {
        // suggestion.type is 'vejnavn', 'adgangsadresse' or 'adresse'
        show(suggestion.forslagstekst, suggestion.tekst, suggestion.caretpos);
    }
});

// When an address is picked: one look-up.
async function picked(suggestion) {
    const result = await api.adresse(suggestion.data, { struktur: 'mini' });
    if (result.isSuccess) fill(result.toSuccess());
}

Autocomplete

autocomplete is DAWA's combined /autocomplete, the one the dawa-autocomplete2 widget calls: street names first, then access addresses, then addresses, moving on as the text narrows. Branch on type.

With kun_tekst: true (ours, not DAWA's) the answer is free: an address or access address carries only { id, href } in data, and the one picked is fetched with adresse(s.data) or adgangsadresse(s.data) for one look-up. The types follow the option, so s.data.vejnavn is a compile error on a text-only answer.

const result = await api.autocomplete('Amagerbrogade 217A', { type: 'adresse', postnr: 2300, fuzzy: true, kun_tekst: true });

for (const s of result.toSuccess()) {
    if (s.type === 'adresse') console.log(s.tekst, s.data.id);   // fetch the one picked: api.adresse(s.data)
    if (s.type === 'vejnavn') console.log(s.data.navn);
}

Without kun_tekst the answer is DAWA's own, data the address in DAWA's mini structure, and an answer that suggests addresses costs one look-up; street names are always free.

One kind of thing only:

await api.adresserAutocomplete('Amagerbrogade 217A, kl.', { postnr: 2300, kun_tekst: true }); // [{ tekst, adresse: { id, href } }] free
await api.adresserAutocomplete('Amagerbrogade 217A, kl.', { postnr: 2300 });   // [{ tekst, adresse }]   1 look-up if not empty
await api.adgangsadresserAutocomplete('Amagerbrogade 217A', { kun_tekst: true }); // [{ tekst, adgangsadresse: { id, href } }] free
await api.vejnavneAutocomplete('Amag');                                          // [{ tekst, vejnavn }]   free
await api.postnumreAutocomplete('23');                                           // [{ tekst, postnummer }] free

Adresser and adgangsadresser

An adresse is a full address, with floor (etage) and door (dør); an adgangsadresse (access address) is the street, house number and postcode it sits behind. Each fetch is one look-up; an id that is not found costs nothing.

const nestet = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b');                    // struktur=nestet (default)
const mini = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b', { struktur: 'mini' });
const flad = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b', { struktur: 'flad', srid: 25832 });
const feature = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b', { format: 'geojson' });

const adgang = await api.adgangsadresse('099f3e28-4fb8-4c61-86a1-edff5df52409', { struktur: 'mini' });

The return type follows struktur and format: AdresseMini, AdresseFlad, AdresseNestet, or a GeoJSON Feature. Mini and flad are typed field by field; nestet types the main fields and leaves the nested registers loose.

Search a page at a time — one look-up per record returned, per_side at most 100. Several values of one parameter go as an array (sent DAWA's way, joined with |); etage: '' or 'dør': '' means "has none".

const page = await api.adresser({ postnr: 2300, vejnavn: 'Amagerbrogade', husnr: '217A', struktur: 'mini' });
const text = await api.adresser({ q: 'Amagerbrogade 217A, kl. 5, 2300 København S' });
const next = await api.adresser({ kommunekode: '0101', side: 2, per_side: 10, struktur: 'mini' });

const adgange = await api.adgangsadresser({ vejnavn: 'Amagerbrogade', postnr: [2300, 2100] });

Reverse geocoding

The access address nearest a point. One look-up; nothing within reach is a 404 that costs nothing.

const nearest = await api.reverse(12.6137425, 55.6490036);                                 // longitude, latitude
const utm = await api.reverse(556488.89, 6323087.65, { srid: 25832, struktur: 'mini' });   // easting, northing

Datavask (address cleaning)

An address written any way — misspelt, abbreviated — matched against DAR. One look-up when an address is returned; free otherwise.

const washed = await api.datavaskAdresser('Amagerbrogde 217A, kl. 5, 2300 Kbh S');
const { kategori, resultater } = washed.toSuccess();      // kategori 'A' exact, 'B' safe to use, 'C' uncertain
if (kategori !== 'C') {
    const adresse = resultater[0].adresse;                 // { id: '3bba05d4-…', vejnavn: 'Amagerbrogade', … }
}

datavaskAdgangsadresser does the same for access addresses (each result's adgangsadresse). Up to 10 results, best first; vaskeresultat.afstand and forskelle count the edits.

Vejnavne and postnumre

Street names and postcodes. Free, and rate limited.

const streets = await api.vejnavne({ postnr: 2300 });           // every street in 2300, with postcodes and kommuner
const street = await api.vejnavn('Amagerbrogade');

const postnumre = await api.postnumre({ kommunekode: '0101' });
const postnummer = await api.postnummer(2300);                  // { nr: '2300', navn: 'København S', bbox, … }

Companies (CVR)

Active Danish companies from CVR (Det Centrale Virksomhedsregister), by name or CVR number. Suggestions are free and rate limited; a company's record is one look-up (a bad check digit or an unknown company costs nothing).

const found = await api.companies('eksempel bag', { top: 5 });       // legal names first, then binavne
const company = await api.company(found.toSuccess().suggestions[0]); // or api.company('12345674')
const { name, other_names, company_form, industry, address, reklamebeskyttet } = company.toSuccess();
// address.source 'dar': the DAR address CVR points at, with x and y; 'cvr': as CVR registered it

A company with reklamebeskyttet: true has asked not to be contacted for direct marketing: you must not use it for that. Data: Det Centrale Virksomhedsregister (CVR), CC BY 4.0.

Failures

Errors the API reports and network failures are results, never thrown. status is the HTTP status (0 when no response arrived), message says what went wrong, and a 429 carries retryAfterSeconds. There are two kinds of error body, and code names either:

  • DAWA's errors, exactly as DAWA sent them, in dawaError ({ type, title, details }): QueryParameterFormatError (400), ResourcePathFormatError (404, a malformed id or postcode) and ResourceNotFoundError (404).
  • Our refusals, as problem details in problem: unauthorized (401), forbidden (403), domain-token-scope (403), domain-token-rate-limit (429), and rate or daily limits (429 with Retry-After).
const result = await api.adresse(id);

if (!result.isSuccess) {
    const failed = result.toFailed();

    if (failed.isNotFound) { /* no such address — costs nothing */ }
    else if (failed.isInvalid) console.log(failed.dawaError.details);   // [['id', 'String does not match pattern …']]
    else if (failed.isRateLimited) await wait(failed.retryAfterSeconds ?? 60);
    else if (failed.isUnauthorized) { /* key missing or unknown, or an API key sent from a browser */ }
    else console.log(failed.code, failed.message);
}

Usage reports

Pass your admin key as the second argument:

const api = new Client('your-api-key', 'your-admin-key');

const today = await api.usage();
const oneDay = await api.usage(1, 9, 2026);
const range = await api.usageRange(new Date('2026-09-01'), new Date('2026-09-14'));

Coming from DAWA

The same paths, parameters, fields and ids as DAWA (api.dataforsyningen.dk), which closes on 1 October 2026:

  1. Change the host to https://api.getaddress.dk.
  2. Add your key: api-key= on the query string from a server, or a domain token in the path (https://api.getaddress.dk/t/{dtoken_…}) for browser code such as dawa-autocomplete2.

Records, field names, ids and error bodies are unchanged, so code that reads DAWA's answers reads ours. A search now pages (per_side at most 100). See Differences from DAWA.

Options

new Client('your-api-key', 'your-admin-key', {
    baseUrl: 'https://api.getaddress.dk', // the API origin
    timeoutMs: 30000,                     // 0 for no timeout
    fetch: customFetch                    // defaults to the global fetch
});

Development

npm install
npm test

GETADDRESS_DK_KEY=your-api-key npm test also runs a live smoke test (one look-up); set GETADDRESS_DK_BASE_URL to point it at another host.

Licence

MIT © getAddress()

The MIT licence covers the code only. Address data is from the Danish Address Register (DAR), © Klimadatastyrelsen, licensed CC BY 4.0: credit it where you show it. See the data sources page.