Norwegian Fake Data
A Python CLI for making Norwegian phone numbers, fødselsnummer, license plates, and character records for murder mystery games and props. Runs offline, with Rich terminal output and JSON/CSV exports.
Proudly sponsored by CaseClosed
Proudly sponsored by CaseClosed in Norway and Caseclosed Mysteries internationally, creators of printed murder mystery games.
Get started
You'll need Python 3.11 or newer and uv.
Run commands with uvx, without a permanent installation:
uvx norwegian-fake-data phone
uvx norwegian-fake-data fnr --birthday 1987 5 17
uvx norwegian-fake-data plate --count 5
uvx norwegian-fake-data person --age 42 --vehicle
For a permanent installation, use uv tool install norwegian-fake-data.
To pin a release, use uvx norwegian-fake-data@0.1.0 phone.
Phone numbers
uvx norwegian-fake-data phone --count 10 --unique
uvx norwegian-fake-data phone --international
uvx norwegian-fake-data phone --international --style compact
Numbers come from Nkom's reserved TV/film range, 68050000–68059999.
Choose spaced output (68 05 12 34) or compact output (68051234), with an
optional +47 prefix.
Fødselsnummer
Choose a birthday or an age:
uvx norwegian-fake-data fnr --birthday 1987 5 17
uvx norwegian-fake-data fnr --age 35 --as-of 2026-10-06
uvx norwegian-fake-data fnr --age 35 --exact-age --as-of 2026-10-06
--age 35 picks a random birthday for someone aged 35 on the reference date.
On 2026-10-06, that's between 1990-10-07 and 1991-10-06.
--exact-age instead uses 1991-10-06: their 35th birthday is on that date.
--as-of defaults to today; set it to the date of your story.
Both modes produce fictional identifiers:
| Mode | Result |
|---|---|
prop (default) |
Realistic birth date with a deliberately invalid checksum |
synthetic |
Month increased by 80, following Skatteetaten's test-data convention |
uvx norwegian-fake-data fnr --birthday 1987 5 17 --mode synthetic
Supported birth years are 1854–2039. February 29 birthdays advance in age on February 28 in non-leap years. JSON and CSV include the actual birthday, age, mode, and reference date alongside the number.
License plates
uvx norwegian-fake-data plate --count 5 --unique
uvx norwegian-fake-data plate --prefix QB
uvx norwegian-fake-data plate --prefix QC --compact
Plates use QA, QB, or QC followed by five digits, such as QB 12345.
These prefixes were absent from Statens vegvesen's published plate series when
checked on 2026-10-06; they are not an officially reserved film range.
Character records
uvx norwegian-fake-data person --age 42 --count 6 --unique --vehicle \
--as-of 2024-11-15 --seed 73 --format json > characters.json
Each record contains a Norwegian name, birthday, age, FNR, phone, example.com
email, and optional plate. It accepts the same birthday and mode options as fnr.
Save the records to reuse the same details across letters, contact lists, and
witness statements. Names are drawn from a small hand-curated list and may repeat.
Output options
| Option | What it does |
|---|---|
--count N, -n N |
Generate a batch; default 1 |
--seed N |
Repeat results with the same options and package version |
--unique |
Avoid duplicate identifiers within the batch |
--format rich |
Tables and character cards |
--format plain |
One identifier per line; tab-separated fields for people |
--format json |
Array of records |
--format csv |
Header and one row per record |
Output defaults to Rich in a terminal and plain text when piped. Use a fixed
--as-of with seeded age-based generation. Import identifier columns as text
when opening CSV files in a spreadsheet to keep leading zeros.
uvx norwegian-fake-data phone --count 20 --format csv > phones.csv
uvx norwegian-fake-data --help
uvx norwegian-fake-data fnr --help
Using it from Python
from datetime import date
from norwegian_fake_data import generate_fnrs, generate_people, generate_phones, generate_plates
phones = generate_phones(5, seed=42, unique=True)
plates = generate_plates(5, seed=42, prefix="QA")
records = generate_fnrs(age=35, as_of=date(2026, 10, 6), seed=42)
characters = generate_people(6, age=42, seed=73, vehicle=True, unique=True)
print(records[0].fnr, records[0].birthday)
Data sources
- Nkom's numbering plan: the TV/film phone range.
- Statens vegvesen's plate series: plate format and prefix selection.
- Skatteetaten's test-data documentation: the synthetic month offset.
- Skatteetaten's checksum documentation: checksum calculations. Prop mode changes the final checksum, which fails both the traditional and published 2032 rules.
Development and publishing
From a checkout, run the CLI with uvx --from . norwegian-fake-data and use
these commands for development:
uv sync --locked
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv build
uv run twine check --strict dist/*
CI runs lint, tests, and the package build once on Ubuntu with Python 3.11.
Pushing a version tag runs the checks and publishes the package to PyPI.
Set the version in pyproject.toml, run uv lock, then commit and push before
tagging that commit. For version 0.1.0:
git tag -a v0.1.0 -m "Release 0.1.0"
git push origin v0.1.0
The tag must match the package version. Use a new version and tag for each release.
After publishing, run uvx --refresh norwegian-fake-data --version to get the latest.
Publishing uses PyPI Trusted Publishing
from caseclosed-no/norwegian-fake-data through release.yml.
License
MIT, copyright LVL UP AS.
Metadata
Release files for norwegian-fake-data 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| norwegian_fake_data-0.1.0.tar.gz | 51.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| norwegian_fake_data-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 65.9 kB
Release files / norwegian_fake_data-0.1.0.tar.gz
| Download URL | norwegian_fake_data-0.1.0.tar.gz |
|---|---|
| Size | 51.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dde1f913afa51d1a80ab8b80c33a4edc9b556bb0f232a63a96b8c22fae28918c
|
|
BLAKE2b-256 checksum How to use checksums |
397b40415dbe6803bc0221cb2112ad99f3c8086e2824d05cffd1bc56eeec722f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / norwegian_fake_data-0.1.0-py3-none-any.whl
| Download URL | norwegian_fake_data-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
13d4a475571f15ff3ae6ea711ab64ded6e23e8cf18ba0b0cdb0de6932286e60c
|
|
BLAKE2b-256 checksum How to use checksums |
db285a2a57ebe8916003d63dc5498e0bdf124a7a6f3f1a4f69f5b4c0502ab220
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log