Danish Public Tenders (TED): Udbud Alerts by CPV & Keyword
Pricing
from $3.00 / 1,000 tender notices
Danish Public Tenders (TED): Udbud Alerts by CPV & Keyword
Danish public tenders (udbud) from the official EU TED API: buyer, CPV, value, deadline, link. CPV/keyword filters and daily only-new alerts.
Pricing
from $3.00 / 1,000 tender notices
Rating
0.0
(0)
Developer
Nordic Open Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Get Danish public tenders (offentlige udbud) as clean, ready-to-use data: title, buyer, CPV codes, estimated value, bid deadline and a link to the notice. The data comes from TED, the EU's official procurement journal. Add Sweden, Norway, Finland or Iceland if you bid across the Nordics.
Daily tender alerts that cost nothing on quiet days. Switch on Only new since last run and schedule the Actor. Each notice is delivered once, ready for Slack, email, Google Sheets or your CRM. A run with nothing new is free.
What it does
- Searches all TED notices from Danish buyers (kommuner, regioner, styrelser, forsyninger, boligselskaber …), with optional other Nordic countries.
- Filters by CPV code (e.g.
72IT,45construction), keywords in any language (software,rengøring,rådgivning), notice type and publication date. - Only open for bids: drop tenders whose deadline has passed. Minimum value drops small or unpriced tenders.
- Contract awards: who won, with the winner's company number and the awarded value (notice type "Contract awards").
- Buyer CVR number, NUTS region, number of lots, framework agreement flag (rammeaftale) and direct links to the tender documents and bid submission page.
- Only new since last run: remembers what you already received, per saved search (
monitorId). - Every lot of a notice: title, CPV, value and deadline per lot (nested
lotsarray), or one row per lot for spreadsheets. - Nordic presets (Denmark, Scandinavia, all Nordic) with values converted to DKK and EUR using the ECB reference rates.
- English where it exists: an English CPV category for every notice, plus the buyer's own English title and summary when they published one. Nothing is machine-translated.
- Changes and cancellations are flagged: each notice has a
status(published, changed, cancelled, awarded, noAward). In alert mode, corrections, cancellations and awards for tenders you already received are markedupdatesSeenNotice: true. - Titles and buyer names in Danish, English, Swedish, Norwegian or Finnish.
- Fast and cheap: one official API, no scraping, no login and no proxies. A 20-notice run takes a few seconds.
Who it's for
- Bid managers and sales teams who want a morning list of new Danish tenders in their category.
- Consultants and tender-writing agencies who run one saved search per client.
- Market analysts who size public demand by CPV, buyer or value.
- AI agents and automations that need a small, flat record per tender.
How to use it
- Click Try for free. The default (Denmark, keyword "software", calls for tender from the last 7 days, 20 notices) runs in seconds.
- Set your CPV codes and/or keywords.
- For alerts, turn on Only new since last run, give the search a Monitor ID, and add a Schedule (e.g. every weekday at 07:00).
- Export as JSON, CSV or Excel, or connect to Google Sheets, Slack, Make, Zapier or n8n.
Example inputs
Daily IT tender alert, Denmark only, open tenders only:
{ "cpvCodes": ["72", "48"], "onlyOpenForBids": true, "onlyNew": true, "monitorId": "it-dk", "publishedWithinDays": 3, "maxItems": 200 }
Construction tenders in Denmark and Norway in September 2026, in Danish:
{ "countries": ["DNK", "NOR"], "cpvCodes": ["45"], "dateFrom": "2026-09-01", "dateTo": "2026-09-30", "preferredLanguage": "dan", "maxItems": 500 }
Who won Danish IT contracts in the last 30 days:
{ "cpvCodes": ["72"], "noticeTypes": ["result"], "publishedWithinDays": 30 }
Recipes: daily alerts in 5 minutes
- Save a task. Open the Actor, enter one of the inputs below and click Save as a new task. Name it e.g. "IT tenders DK".
- Schedule it. In Apify Console go to Schedules → Create new, set e.g.
0 7 * * 1-5(weekdays 07:00, Europe/Copenhagen) and add your task. - Get notified.
- Email: on the task, open Integrations and add the email integration (or a Zapier/Make "Actor run succeeded" trigger). Have it send the dataset link or items.
- Slack, Teams or your system: under Integrations → Webhooks, add a webhook for
ACTOR.RUN.SUCCEEDEDpointing to your endpoint (Slack incoming webhook via Make/Zapier/n8n, or your API). Fetch the items fromhttps://api.apify.com/v2/datasets/{{resource.defaultDatasetId}}/items?view=overview. - Know when something breaks: add a second notification for
ACTOR.RUN.FAILED/TIMED_OUT.
- Quiet days cost nothing: a run with no new notices isn't charged.
Example inputs per industry
IT and software (Denmark, open tenders only):
{ "cpvCodes": ["72", "48"], "onlyOpenForBids": true, "onlyNew": true, "monitorId": "it", "publishedWithinDays": 3 }
Construction across Scandinavia, values in DKK, over 5 million:
{ "countryPreset": "scandinavia", "cpvCodes": ["45"], "minValue": 5000000, "onlyNew": true, "monitorId": "construction", "publishedWithinDays": 3 }
Cleaning and facility services (Danish and English keywords):
{ "cpvCodes": ["909"], "keywords": ["rengøring", "cleaning", "facility"], "onlyNew": true, "monitorId": "cleaning", "publishedWithinDays": 3 }
Consulting, management and engineering advice (one row per lot):
{ "cpvCodes": ["79400000", "71300000"], "keywords": ["rådgivning", "konsulent"], "outputMode": "lots", "onlyNew": true, "monitorId": "consulting", "publishedWithinDays": 3 }
Note: minValue is compared in the notice's own currency.
Output
One row per notice, newest first. Example:
{"id": "711403-2026","title": "Danmark – Aflæsning af målere – LEVERING AF FORBRUGSMÅLERE OG -REGNSKABER SAMT HÅNDTERING AF FORBRUGSKLAGER (2026)","buyer": "Boligselskabet Sjælland","buyerCountry": "DNK","cpv": ["65500000", "38421100", "72314000"],"mainCpv": "65500000","value": 25000000,"currency": "DKK","deadline": "2026-11-25","deadlineType": "tender","daysToDeadline": 41,"publicationDate": "2026-10-15","noticeType": "cn-standard","noticeGroup": "competition","contractNature": "services","procedureType": "open","buyerCvr": "42008419","placeOfPerformance": ["DK021", "DK022"],"lotCount": 1,"isFrameworkAgreement": false,"documentsUrl": "https://permalink.mercell.com/292506803.aspx","submissionUrl": "https://permalink.mercell.com/292506803.aspx","winners": [],"awardedValue": null,"description": "Dette udbud vedrører levering og installation af forbrugsmålere …","url": "https://ted.europa.eu/en/notice/-/detail/711403-2026","pdfUrl": "https://ted.europa.eu/en/notice/711403-2026/pdf","source": "TED"}
Contract award example (noticeTypes: ["result"]):
{ "id": "710026-2026", "buyer": "FORSYNING HELSINGØR SPILDEVAND A/S", "buyerCvr": "32654266", "isFrameworkAgreement": true,"winners": [{ "name": "Init Denmark A/S", "identifier": "19256707" }], "awardedValue": 4590000, "awardedCurrency": "DKK" }
Views: Tenders (date, title, buyer, value, deadline, documents, link), Contract awards (buyer, CVR, winners, awarded value) and All details (every field).
Pricing
Pay per event. Platform usage is included.
| Event | Price | When |
|---|---|---|
Actor start (actor-start) | $0.002 | Once per run that returns at least one notice |
Tender notice (tender-notice) | $0.003 | Per notice returned ($3 per 1,000) |
Runs that fail or return no notices cost nothing, so a daily alert with nothing new is free. Examples: a 20-notice test costs $0.062. A daily alert with about 5 new notices a day costs about $0.50 a month. A 1,000-notice export costs about $3. Use Max notices (or the run's maximum cost) to cap spending.
FAQ
Does it include all Danish tenders? It includes everything Danish buyers publish on TED: all EU tenders above the thresholds, plus voluntary below-threshold publications. Tenders published only on udbud.dk (below the EU thresholds) are not included yet. See Limitations.
How does "only new" work? The IDs of notices you received are stored in a key-value store named dk-tenders-state in your own Apify account. The record is keyed by your Monitor ID plus a fingerprint of your search filters: countries, CPV codes, keywords (case and order don't matter), notice types, minimum value and open-only. Changing the date range, max notices, language, row format or description setting keeps your history, so a rolling "last 3 days" schedule works. Changing a filter starts a fresh list, so you get the full matching set once. The first run returns everything that matches and saves the baseline. Notices that correct, cancel or award a tender you already received are delivered again as their own notices, with updatesSeenNotice: true.
Why zero results? Your filters are narrow or, in "only new" mode, nothing new was published. You're not charged for that. TED publishes on working days (Tue–Sat).
Can I search in Danish? Yes. Keywords match the full notice text in any language. Combine e.g. ["rengøring", "cleaning"].
Limitations
- TED only (v1). udbud.dk's below-threshold notices are not included. udbud.dk allows reuse with attribution, but only through its official API, which needs a registered system-provider account. Support is planned.
- The value is TED's total value or, if that's missing, the sum of the lot estimates. It's in the notice's own currency, and many notices publish no value.
- Currency conversion uses the latest ECB rate, not the rate on the publication date.
- English titles and summaries exist only when the buyer wrote them in English. Most Danish notices are Danish-only, apart from the English CPV category.
- The deadline is the earliest lot deadline for submitting a tender. For restricted and negotiated procedures it's the deadline to request participation instead (
deadlineType). - At most 1,000 notices per run and a 366-day date range.
- No contact persons, e-mails or phone numbers are returned. Contract winners are the company names and identifiers published on TED. A winner can occasionally be a sole trader trading under a personal name.
- Winner identifiers are paired with names only when TED's lists line up one-to-one. Otherwise the identifier is left empty rather than guessed.
- Not every award notice names a winner (e.g. cancelled lots or no tenders received).
Technical
Input reference
| Field | Default | Notes |
|---|---|---|
countryPreset | denmark | denmark, scandinavia (DK/SE/NO), nordic (+FI, IS), custom |
countries | ["DNK"] | Custom list (countryPreset = custom): DNK, SWE, NOR, FIN, ISL (2-letter codes accepted) |
keywords | – | Any keyword matches (TED full-text FT~) |
cpvCodes | – | 2–8 digits, padded to 8; check digit -5 stripped; matched as TED does with classification-cpv IN (…) |
noticeTypes | ["competition"] | competition (cn-), result (can-), planning (pin-*); [] = all |
publishedWithinDays / dateFrom / dateTo | last 7 days | Max 366 days |
onlyOpenForBids | false | Requires deadline ≥ run date |
onlyNew / monitorId | false / default | State in named KV store dk-tenders-state, key STATE_<monitorId>_<12-hex search hash> = {ids (last 20,000), procedures→ids}. A v1 SEEN_<monitorId> list is migrated automatically |
preferredLanguage | eng | eng, dan, swe, nor, fin |
minValue | – | Drops notices with lower or missing value (falls back to awardedValue), notice currency |
includeDescription | true | Description and English summary truncated to 2,000 chars |
outputMode | notices | lots = one dataset row per lot (still billed per notice) |
convertCurrency | true | Adds valueDkk, valueEur, awardedValueDkk, fxRateDate |
maxItems | 50 | 1–1,000 |
OUTPUT record
OUTPUT in the run's default key-value store holds status (OK, PARTIAL, NO_DATA, CHARGE_LIMIT_REACHED, ERROR), message, charged, the TED query, matched, returned, skippedSeen, skippedClosed, skippedValue, filters and attribution. A failed run (e.g. invalid input) still writes status: "ERROR", the message and charged: false.
Currency conversion
valueDkk and valueEur use the latest daily ECB euro foreign exchange reference rates (https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml), converted via EUR and rounded to 2 decimals. fxRateDate is the rate date, and OUTPUT fx lists the rates used. The ECB publishes these for information only. They're not a transaction rate, and estimated values are often set months before publication. If the ECB can't be reached, the conversion fields are null and OUTPUT has a warning; the run still succeeds.
Status and changes
status comes from eForms fields: changed when change-notice-version-identifier is set (corrigendum), cancelled when the change reason is cancel/cancel-intent, noAward when every lot result is clos-nw, awarded for other can-* notices, otherwise published. changeOf identifies the changed notice: usually its TED publication number, sometimes its eForms notice ID + version (UUID-01). Matching to notices you already have therefore also uses procedureId. In only-new mode, relatedSeenIds lists earlier notices you received from the same procedure (procedureId) or the notice it changes. isExpired compares the deadline with the run date.
Lots
Per-lot values, deadlines and CPV codes are mapped only when TED returns exactly one entry per lot. Otherwise those lot fields are null rather than guessed (the notice-level value and deadline are still filled).
Billing events
actor-start (once per run with at least one notice) and tender-notice (per notice). Notices are saved first and charged after. If your maximum cost per run is reached, the run returns what it could pay for (status PARTIAL), and only those notices are marked as seen.
Data source and licence
Data: TED API v3 (api.ted.europa.eu), Publications Office of the European Union. Source: TED – Tenders Electronic Daily (https://ted.europa.eu), © European Union. Reused under Commission Decision 2011/833/EU on the reuse of Commission documents. This Actor processes the data and is not endorsed by the Publications Office of the EU. Every run's OUTPUT carries this attribution.