Denmark Restaurant Inspections: Smiley Food Safety avatar

Denmark Restaurant Inspections: Smiley Food Safety

Pricing

$2.00 / 1,000 food business units

Go to Apify Store
Denmark Restaurant Inspections: Smiley Food Safety

Denmark Restaurant Inspections: Smiley Food Safety

Danish restaurant and food business inspection results from the Fødevarestyrelsen Smiley food safety scheme: up to four inspections per business, result labels, CVR, P-number, address and industry. Filter by postal code or result, or get only changed units. No API key needed.

Pricing

$2.00 / 1,000 food business units

Rating

0.0

(0)

Developer

Mikkel Jeppesen Juhl

Mikkel Jeppesen Juhl

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Get Danish restaurant and food safety inspection results as clean JSON. The actor reads the open Smiley file that Fødevarestyrelsen publishes on findsmiley.dk. It returns one row per food business unit with its latest four inspections, ISO dates, English result labels, CVR and P-number, address, industry and the advertising protection flag.

The file covers about 59,000 restaurants, shops, bakeries, canteens, wholesalers and transport firms. You can filter it by postal code, city, industry, business type, CVR number, latest result and inspection date. You can also run the actor on a schedule and get only the units that changed since the last run, such as a new inspection or a new sour smiley.

Use cases

  • Export Danish restaurant inspection results by postal code or city.
  • Monitor new sour smileys and new inspections on a schedule with change detection.
  • Look up every food business of a company by CVR number.
  • Build food safety datasets for research, insurance, delivery platforms or local news.

What you get

FieldMeaning
smileyIdFødevarestyrelsen's id for the unit, also the findsmiley.dk page number
cvrDanish CVR number of the owner, 8 digits. Missing for about 2% of units
pNumberProduction unit number (P-nummer). Missing for about 3% of units
name, address, postalCode, cityUnit name and address as registered with Fødevarestyrelsen
businessTyperetail (detail, sells to consumers) or wholesale (engros)
smileyIndustryIndustry group on findsmiley.dk, in Danish, for example "Dagligvareforretninger"
fvstIndustryCode, fvstIndustryFødevarestyrelsen's finer industry code and name
latestResultResult of the latest inspection, 1 to 4, or null with no inspection yet
latestResultLabelThe result in English, see the table below
latestSmileyhappy, straight or sour for retail units, null for wholesale
latestInspectionDateDate of the latest inspection, YYYY-MM-DD
worstRecentResultHighest result among the published inspections
inspectionCountHow many inspections the file holds for the unit, 0 to 4
inspectionsUp to four inspections, newest first, each with date, result and resultLabel
advertisingProtectedtrue when the unit is flagged with reklamebeskyttelse. Always present
findSmileyUrlThe unit's page on findsmiley.dk with the full inspection reports
changeTypeIn change mode: new, changed or removed. Null otherwise
changedPartsIn change mode: inspections, details and or advertisingProtection
previousLatestResult, previousLatestInspectionDateIn change mode: the values in the previous snapshot

Result codes

CodeDanishEnglishRetail smiley
1Ingen anmærkningerNo remarksHappy
2IndskærpelseWarningStraight mouth
3Påbud, forbud eller tvangsbøderOrder, ban or daily finesStraight mouth
4Bødeforlæg, politianmeldelse, karantæne, autorisation eller registrering fratagetFine, police report, quarantine, or approval or registration withdrawnSour

A null result means the unit has not been inspected yet, or sits in the lowest risk group and is rarely inspected. Fødevarestyrelsen publishes a result before appeals end and before a fine is final, so a 4 is not a final verdict. Findsmiley.dk can also withdraw a report, and the unit's inspections then move up a slot.

Input

{
"postalCodes": ["1000-2999", "8000"],
"cities": ["Aarhus C"],
"smileyIndustries": ["Restauranter, kantiner, takeaway, værtshuse m.fl."],
"businessTypes": ["retail"],
"cvrNumbers": ["35954716"],
"latestResults": ["2", "3", "4"],
"inspectedSince": "2026-01-01",
"excludeAdvertisingProtected": false,
"onlyChangedSinceLastRun": false,
"snapshotName": "default",
"includeRemoved": true,
"maxItems": 1000,
"sourceFormat": "xlsx"
}
  • Every filter is optional. Filters combine with AND. Values inside one filter combine with OR.
  • postalCodes takes single codes or ranges such as 1000-2999.
  • latestResults takes 1, 2, 3, 4 and none.
  • cvrNumbers returns every unit the company owns. A supermarket chain owns over 1,000 units.
  • sourceFormat picks the 7 MB Excel file or the 60 MB XML file. They hold the same data.

Change detection

Turn on onlyChangedSinceLastRun and schedule the actor, for example daily. The first run saves a snapshot of the whole file in a named key-value store (dk-smiley-snapshots) and outputs nothing. Each later run compares the file with the snapshot and outputs only:

  • new units that were not in the last snapshot,
  • changed units with a new inspection, a withdrawn inspection, new details or a changed advertising flag,
  • removed units that left the file. Removed rows are free.

Use one snapshotName per schedule. Your filters apply to the output, and the snapshot always covers the whole file, so you can change filters between runs. Fødevarestyrelsen rebuilds the file more than once a day.

Advertising protection (reklamebeskyttelse)

About 40% of the units carry advertisingProtected: true. The flag mirrors the CVR register's reklamebeskyttelse. A company sets it in CVR to say it does not want direct marketing. Under section 19 of the Danish CVR Act, a private company must not use CVR data about a protected unit for direct marketing, and anyone who passes on its contact data must mark it as protected. That is why the flag is in every row.

If you buy this data, you must not use it to direct-market units with advertisingProtected: true. That covers mail, phone calls, visits and any other sales approach built on this data. Separate rules apply to everyone: the Danish Marketing Practices Act section 10 bans unsolicited email and SMS marketing without prior consent, and the GDPR applies when a unit is a sole proprietorship named after a person. Set excludeAdvertisingProtected to drop protected units from the output. This is not legal advice. You are responsible for how you use the data.

Source, terms and no endorsement

Source: Fødevarestyrelsen (the Danish Veterinary and Food Administration), Smiley data from findsmiley.dk, downloaded from https://pub.fvst.dk/publikationer/Smileydata.xlsx or .xml on each run. Fødevarestyrelsen publishes the data under the Danish terms for reuse of public data, with four extra conditions: name Fødevarestyrelsen as the source, do not use its logo, any smiley shown for a single business must match its current smiley, and follow the design rules for the smiley symbols. If you show smiley symbols to others, show the current result and link to findSmileyUrl.

The actor renames the fields to English, converts dates to ISO format, adds result labels and computes latestSmiley, worstRecentResult and inspectionCount. Fødevarestyrelsen does not endorse or support this actor. The official results are the ones on findsmiley.dk.

Limits of the source

  • Only the latest four inspections per unit are published, and nothing from before 24 January 2012.
  • The file has no inspection report text. Read the reports on findsmiley.dk.
  • Units appear by production site. Chains appear once per shop and department.
  • The file has no email or phone data.

Run it locally

No Apify account is needed. You need uv.

cd apps/apify-dk-smiley-inspections
uv sync
./run_local.sh input.example.json
uv run python test/coverage.py storage/datasets/default
uv run python -m test.test_filters

Set SMILEY_SOURCE_FILE=/path/Smileydata.xml to read a saved file in place of the download. Run stats land in storage/key_value_stores/default/RUN_STATS.

Pricing

Pay per event: 0.002 USD per unit row (2 USD per 1,000). Removed rows in change mode are free. No start fee. A daily change run on all of Denmark returns about 150 rows on a weekday, since Fødevarestyrelsen inspects about 150 units a day.