# Æ, ø and å: character sets and URL encoding

> Send æøå correctly URL-encoded, read UTF-8 responses without broken characters, open CSV in Excel with the right letters, and understand the oe/aa/ae folding in autocomplete.
>
> https://danadresse.dk/en/guides/aeoeaa-tegnsaet · verified 2026-11-02
Danish addresses are full of æ, ø and å. The API uses UTF-8 all the way: in the URL, in JSON and in CSV. Problems appear when one link in the chain uses another character set, usually Windows-1252 (also called Latin-1 or ANSI). The result is either empty responses or text like `RÃ¥dhuspladsen`.

## Recognise the problem

| You see | It should be | Cause |
|---|---|---|
| `Ã¦`, `Ã¸`, `Ã¥` | æ, ø, å | UTF-8 read as Windows-1252 |
| `Ã†`, `Ã˜`, `Ã…` | Æ, Ø, Å | The same with capitals |
| `�` or `?` | æ, ø or å | Windows-1252 read as UTF-8, or the character lost in a conversion |
| `R%E5dhuspladsen` in the URL | `R%C3%A5dhuspladsen` | The text was URL-encoded as Latin-1 |
| `å` in JSON | å | Not a problem. The JSON parser turns it into å |

## Send æøå in the URL

In a URL, æ, ø and å must be sent as UTF-8 bytes, percent-encoded:

| Character | URL-encoded |
|---|---|
| æ / Æ | `%C3%A6` / `%C3%86` |
| ø / Ø | `%C3%B8` / `%C3%98` |
| å / Å | `%C3%A5` / `%C3%85` |
| space | `%20` (or `+` in the query string) |

Never build the URL by concatenating text. Let your library encode the parameters. With curl, `-G` and `--data-urlencode` do it for you:

```bash id=curl-urlencode run=live expect="Rådhuspladsen"
curl -s -G "https://api.danadresse.dk/autocomplete" \
  --data-urlencode "q=Rådhuspladsen 1" \
  --data-urlencode "per_side=3" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"
```

In Python, `requests` encodes everything you pass in `params`:

```python id=python-params run=live expect="%C3%A5"
import os
import requests

r = requests.get(
    "https://api.danadresse.dk/autocomplete",
    params={"q": "Rådhuspladsen 1", "per_side": 1},
    headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]},
    timeout=10,
)
r.raise_for_status()
print(r.url)                              # ...?q=R%C3%A5dhuspladsen+1&per_side=1
print(r.json()[0]["forslagstekst"])       # r.json() always reads UTF-8
```

In PHP, use `http_build_query`, which encodes UTF-8 strings correctly. Do not use `utf8_decode` or `mb_convert_encoding` to Latin-1 before the call:

```php id=php-build-query run=live expect="Rådhuspladsen"
<?php
$query = http_build_query(["q" => "Rådhuspladsen 1", "per_side" => 3]);
$ctx = stream_context_create(["http" => [
    "header" => "X-Api-Key: " . getenv("DANADRESSE_API_KEY"),
    "timeout" => 10,
]]);
$body = file_get_contents("https://api.danadresse.dk/autocomplete?$query", false, $ctx);
foreach (json_decode($body, true) as $suggestion) {
    echo $suggestion["forslagstekst"], "\n";
}
```

In JavaScript, use `URL` and `searchParams.set()`, as in [Your first API call](/en/guides/kom-i-gang).

If your text comes from an old system, a file or a database in Windows-1252, convert it to UTF-8 before you send it. In Python: `text = raw_bytes.decode("cp1252")`. On the command line: `iconv -f WINDOWS-1252 -t UTF-8 in.csv > out.csv`.

## Read the response as UTF-8

JSON responses have `Content-Type: application/json` without a `charset` parameter. JSON is always UTF-8, and most clients know that: `r.json()` in Python, `res.json()` in JavaScript and `json_decode()` in PHP give the right characters.

Problems come when a client guesses the character set from the header:

- **Windows PowerShell 5.1** (`Invoke-RestMethod`, `Invoke-WebRequest`) reads a response without `charset` as Latin-1. Use PowerShell 7, or read the bytes and decode them yourself:

```powershell id=powershell-utf8 run=no
$headers = @{ "X-Api-Key" = $env:DANADRESSE_API_KEY }
$res = Invoke-WebRequest -Uri "https://api.danadresse.dk/postnumre/2900" -Headers $headers -UseBasicParsing
$json = [System.Text.Encoding]::UTF8.GetString($res.RawContentStream.ToArray()) | ConvertFrom-Json
$json.navn
```

- **Older HTTP libraries** in, for example, Java, .NET or VBA use the system's default character set when turning bytes into text. Specify UTF-8 explicitly.
- **The database** must be able to store the characters too. In MySQL and MariaDB the column and the connection must be `utf8mb4`.

## CSV in Excel

`format=csv` gives UTF-8 without a BOM (byte order mark). If you double-click the file in Excel on Windows, Excel guesses Windows-1252 and shows `RÃ¥dhuspladsen`. There are three fixes:

1. **Import instead of opening.** In Excel: *Data → From Text/CSV*, choose the file, and set *File Origin* to *65001: Unicode (UTF-8)*.
2. **Power Query.** Set the character set directly:

```m id=power-query-csv run=no
let
    Kilde = Web.Contents(
        "https://api.danadresse.dk/adresser",
        [Query = [postnr = "4200", per_side = "100", format = "csv"],
         Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]),
    Csv = Csv.Document(Kilde, [Delimiter = ",", Encoding = 65001, QuoteStyle = QuoteStyle.Csv]),
    Tabel = Table.PromoteHeaders(Csv, [PromoteAllScalars = true])
in
    Tabel
```

3. **Save the file with a BOM.** If you fetch the CSV with a script, write it with a BOM in front. Excel then opens it correctly on double-click:

```python id=csv-with-bom run=syntax
import os

import requests

r = requests.get(
    "https://api.danadresse.dk/adresser",
    params={"postnr": "4200", "per_side": 1000, "format": "csv"},
    headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]},
    timeout=30,
)
r.raise_for_status()
with open("adresser.csv", "w", encoding="utf-8-sig", newline="") as f:  # utf-8-sig = UTF-8 with BOM
    f.write(r.content.decode("utf-8"))
print("Saved adresser.csv")
```

Excel with Danish regional settings expects a semicolon as separator. The API's CSV uses commas, so pick comma in the import dialog, or use Power Query as above. See also [Excel and Power Query](/en/guides/excel-power-query).

## oe, aa and ae in autocomplete

Users often type without Danish characters: `raadhuspladsen`, `kobenhavn`, `Soendergade`. `/autocomplete` therefore tries variants of what the user typed:

- `aa` → å, `oe` → ø, `ae` → æ (also with a capital first letter)
- an `o` at the start of a word → ø, so `oster` finds `Øster`
- on top of that a typo tolerance that can fix one or two wrong letters in longer words

```python id=folding-demo run=live expect="Rådhuspladsen"
import os
import requests

r = requests.get(
    "https://api.danadresse.dk/autocomplete",
    params={"q": "raadhuspladsen 1", "per_side": 3},
    headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]},
    timeout=10,
)
r.raise_for_status()
for suggestion in r.json():
    print(suggestion["forslagstekst"])
```

The folding lives in `/autocomplete`. The filters on `/adresser` and `/adgangsadresser` (`vejnavn=`, `husnr=`, `postnr=`) do not do the same folding. Write the names with æ, ø and å. If your data lacks æøå, run it through `/autocomplete` or `/datavask/adresser` first. The datavask parser reads spellings such as `Aabenraa`, `Åbenrå` and `Kobenhavn` and matches them to the official name. See [No results?](/en/guides/ingen-resultater)

## Next steps

- [No results?](/en/guides/ingen-resultater)
- [Formats: JSON, CSV, GeoJSON and NDJSON](/en/guides/formater-json-csv-geojson)
- [Excel and Power Query](/en/guides/excel-power-query)
