EU TED Tenders — Public Procurement Notice Scraper avatar

EU TED Tenders — Public Procurement Notice Scraper

Pricing

from $4.00 / 1,000 results

Go to Apify Store
EU TED Tenders — Public Procurement Notice Scraper

EU TED Tenders — Public Procurement Notice Scraper

Fetches structured public procurement notices from the official EU TED (Tenders Electronic Daily) API. Filter by country, CPV code, date, value, and notice type. Free, unauthenticated API; clean JSON output ready for CRM/dashboard ingestion.

Pricing

from $4.00 / 1,000 results

Rating

5.0

(1)

Developer

Berkan Kaplan

Berkan Kaplan

Maintained by Community

Actor stats

0

Bookmarked

42

Total users

12

Monthly active users

15 hours ago

Last modified

Share

EU Public Tenders — TED 📄

foXLabs procurement series: World Bank · IADB · Ukraine Prozorro · UK Contracts Finder · US federal awards · India

🎉 Turn TED into clean, structured EU public-tender data — no login, no API key, one row per notice, with the buyer, title, value, CPV code, deadline and country. Built for suppliers, bid/proposal teams and public-procurement market intelligence.

🔍 What is the EU Public Tenders — and when should you use it?

Give this actor keywords, buyer countries, CPV sectors, notice types and a date range, and it returns the matching notices from Tenders Electronic Daily (TED), the EU public-procurement journal (official open data) — as clean rows you can filter, export or feed to an AI agent. Every run queries the official TED search API live, so the data is as fresh as the journal itself.

Use it when you need: EU tender opportunities by sector or keyword; the notices that mention a public buyer; or a daily pipeline of new notices.

Use something else when: you need company firmographics — TED is procurement notices, not a company registry.

🤖 Use with AI agents

Already on the Apify MCP server? Ask for this Actor by name: foxlabs/ted-tenders.

Your agent can pay for its own runs. This Actor is pay-per-event with agentic payments, so an agent can discover it, run it and settle the bill over x402 (USDC on Base) or Skyfire — no Apify account or API token of its own. Billing is the same either way: per notice delivered.

Otherwise paste this into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

I want to pull EU public tender notices using the Apify Actor `foxlabs/ted-tenders`.
Input: `keywords` (words searched in the notice text, comma = alternatives), `countries` (ISO3 buyer countries, e.g. DEU),
`cpvCodes` (CPV divisions), `datePreset` (last_24_hours, last_7_days, last_30_days, last_90_days, ytd) and `maxResults`.
Start with: {"keywords":"software","countries":["DEU"],"datePreset":"last_30_days","maxResults":50}
Ask me what to look for, run the Actor, then summarise the notices as a table.

The machine-readable API, MCP config and OpenAPI definition live at apify.com/foxlabs/ted-tenders.md.

📋 Overview

Everything you need to turn Tenders Electronic Daily (TED), the EU public-procurement journal (official open data) into clean, structured data — in one actor, with no login, cookies or API key.

Why teams pick this actor:

  • ✅ Keyword search on the official feed — words are matched in the full notice text, combined with country, sector, notice-type and date filters.
  • 🧹 No empty-promise columns — only fields TED actually fills.
  • 🔗 Stable identifiers — every row carries TED's publication number and links, ready to join across runs.
  • 💰 Pay only for results — per notice delivered; a search that finds nothing costs only the run start.
  • 🤖 Agent-ready — MCP + x402 agentic payments.

✨ Features

  • 🔎 Keywords — full-text search across the notice (software, cloud services); commas separate alternatives.
  • 🌍 Filters — buyer country, CPV sector, notice type, date presets or a custom range (20260501, 2026-05-01 or 01.05.2026).
  • 🧠 Expert mode — paste a native TED expert query when you need more (total-value>=1000000 AND classification-cpv=72000000).
  • 🌐 Language — titles, descriptions and buyer names in the language you pick, falling back to English.
  • 🧹 Clean schema — camelCase rows, ready for CSV/Excel/JSON.

🎬 Quick Start

curl -X POST "https://api.apify.com/v2/acts/foxlabs~ted-tenders/runs?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"keywords":"software","countries":["DEU"],"datePreset":"last_30_days","maxResults":50}'

🚀 Getting Started (3 steps)

  1. Choose your filters — keywords, buyer countries, CPV sectors and a date range.
  2. Set the cap — maxResults limits the rows (0 = no limit).
  3. Run and export — get a clean dataset as JSON, CSV or Excel.

📥 Input

{"keywords":"software","countries":["DEU"],"datePreset":"last_30_days","maxResults":50}
FieldTypeDescription
datePresetstringlast_24_hours, last_7_days (default), last_30_days, last_90_days, ytd or custom.
publicationDateFrom / publicationDateTostringCustom range, used when datePreset is custom: 20260501, 2026-05-01 or 01.05.2026 (day first).
keywordsstringWords to find in the notice text; commas separate alternatives, each entry is matched as an exact phrase.
countriesarrayBuyer countries as ISO3 codes (DEU, FRA, …). Empty = all.
cpvCodesarrayCPV main divisions (exact match). Empty = all sectors.
noticeTypesarrayNotice types to keep. Empty = all.
languagestringLanguage for titles, descriptions and buyer names (default ENG).
maxResultsintegerMost rows in one run (default 500, the form suggests 100; 0 = no limit).
querystringPower users: a native TED expert query; it replaces the filters above. Plain words here are searched like keywords. Two-letter countries (DE), CPV codes with a check digit (72000000-5) and the old TED syntax for country, CPV, date and full text (CY=[DE] AND PC=[72000000]) are rewritten automatically. Results come newest first unless the query has its own SORT BY.
pageSizeintegerNotices per API call (max 250).

📤 Output

One row per notice, saved to the dataset. Every row carries scrapedAt and links to the notice on TED.

{
"publicationNumber": "650347-2026",
"publicationDate": "2026-09-22",
"title": "Germany – Health services – Videosprechstunde",
"noticeType": "cn-standard",
"procedureType": "open",
"buyerName": "AOK Bayern - Die Gesundheitskasse",
"buyerCountry": "DEU",
"buyerCity": "München",
"buyerEmail": "vergabestelle1@by.aok.de",
"totalValue": 2600500,
"totalValueCurrency": "EUR",
"cpvCodes": ["85100000"],
"deadlineDate": "2026-10-05",
"detailUrl": "https://ted.europa.eu/en/notice/-/detail/650347-2026",
"scrapedAt": "2026-09-29T19:35:39.878Z"
}
FieldDescription
publicationNumberTED publication number
publicationDatePublication date
titleNotice title
noticeTypeNotice type
noticeSubtypeNotice subtype
procedureTypeProcedure type
buyerNameContracting buyer
buyerCountryBuyer country (ISO3)
buyerCityBuyer city
buyerEmailBuyer email, when published
buyerPhoneBuyer phone, when published
buyerUrlBuyer website
totalValueEstimated or awarded value
totalValueCurrencyCurrency of the value
cpvCodesCPV codes
deadlineDateTender deadline
descriptionNotice description
placeOfPerformanceCountryPlace of performance country
placeOfPerformanceCityPlace of performance city
detailUrlNotice page on TED
xmlUrlNotice XML on TED

💼 Use cases

1. Bid pipeline — find open EU tenders in your field. Input: keywords and/or CPV sectors, last_24_hours. Output: new notices with value and deadline. Use: a daily bid feed.

2. Buyer intelligence — follow a public buyer. Input: the buyer's name as a keyword (matched in the full notice text, so notices that mention the buyer appear too). Output: those notices. Use: anticipate demand.

3. Market sizing — size public spend in a category. Input: CPV sectors and a longer date range. Output: notices with values. Use: estimate market size.

🔗 Integration

JavaScript / Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('foxlabs/ted-tenders').call({"keywords":"software","countries":["DEU"],"datePreset":"last_30_days","maxResults":50});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);

Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('foxlabs/ted-tenders').call(run_input={"keywords":"software","countries":["DEU"],"datePreset":"last_30_days","maxResults":50})
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item)

Written for apify-client 3 for Python, where call() returns a run object; with version 1 or 2 it returns a dict — write run['defaultDatasetId'] there.

Automation (n8n / Zapier / Make): schedule a daily run with datePreset: last_24_hours → handle the JSON dataset → push new notices to a sheet, CRM or chat.

📊 Pricing

Pay-per-event: per notice delivered to the dataset, plus Apify's small run-start event. A search that matches nothing costs only the run start. View current pricing.

❓ FAQ

Do I need an account, login or API key? No. This reads Tenders Electronic Daily (TED), the EU public-procurement journal (official open data).

What do I search by? Keywords, buyer countries, CPV sectors, notice types and dates — or a native TED expert query.

How current is the data? Every run queries TED live, so results are as fresh as the journal.

What does each row represent? One TED notice: the contracting buyer, title, value, CPV codes, deadline and country.

Can I export to CSV / Excel / JSON? Yes — directly from the Apify dataset.

🐛 Troubleshooting

  • Fewer rows than expected — raise maxResults, widen the date range or remove a filter.
  • No rows for a keyword — each comma-separated entry is an exact phrase; try a shorter word or the term in the notice's language.
  • The run failed with "TED rejected the query" — the advanced field needs TED expert syntax (field operator value); put plain words in keywords instead. Country, CPV, date and full-text fields in the old syntax (CY=[DE], PC=[…], PD=[…], FT=[…]) are translated for you; other old fields such as TD=[3] stop the run with a message naming them — use the notice-type filter instead.

This actor reads public procurement notices published on TED as open data. Results can still contain personal data (e.g. a person’s name); personal data is protected by the GDPR and similar laws, so only process it with a legitimate basis. See Apify’s blog post on the legality of web scraping.

🤝 Support & contact

Changelog

0.6.13 — 2026-10-08 — README: the Python example works with the current Apify client

  • The README's Python example read the results with run['defaultDatasetId']. With the current Apify client for Python (version 3) call() returns a run object, not a dict, and that line raised TypeError: 'Run' object is not subscriptable — after the run itself had finished. The example now reads run.default_dataset_id; with client version 1 or 2, keep run['defaultDatasetId']. Checked with apify-client 3.2.1, 2.5.1 and 1.12.2.
  • No code, output field or pricing change.

0.6.12 — 2026-10-07 — a run that Apify starts again does not write a notice twice

  • A run that the platform starts again no longer repeats what it has written. Apify can move a run to another server while it is going; the Actor then starts again from the first page with the same dataset. Until now it wrote every page again: in a test with maxResults 1500 that was started again after 400 rows, the dataset ended with 1,900 rows, 171 notices twice. The Actor now first reads which notices its own dataset already holds; they count towards maxResults and are not written or charged again.
  • No output field changed, no pricing change.

0.6.11 — 2026-10-02 — SORT BY … ASC no longer fails the run

  • TED rejects the ASC keyword (SORT BY publication-date ASC → HTTP 400 "extraneous input 'ASC'"); it sorts ascending without a keyword. ASC / ASCENDING are now dropped and DESCENDING becomes DESC before the query is sent.

0.6.10 — 2026-10-02 — every run returns the newest notices first

  • Result order changed: newest notices first. TED returns notices oldest first, so a form run used to start at the oldest day of the chosen window — maxResults: 20 on "last 7 days" gave the week's 20 oldest notices. Every run now asks TED for SORT BY publication-date DESC, as the TED website lists them, so a capped run keeps the most recent notices. An expert query with its own SORT BY keeps its order. Output fields and price are unchanged.

0.6.9 — 2026-10-02 — expert queries without a date return the newest notices first

  • An expert query with no publication date returned the oldest notices first — TED's archive starts in October 2016, and those old-format notices carry no buyer e-mail, phone or deadline (measured: CY=[DE] AND PC=[72000000] returned 20 notices from 2016-10-01…04). Such a query now asks TED for the newest notices first, as the TED website lists them. Queries that set a publication date or their own SORT BY, and the form filters, keep their order.

0.6.8 — 2026-10-02 — common expert-query mistakes no longer fail the run

  • Three mistakes in the advanced field used to fail the run with HTTP 400 (measured on the TED API): a two-letter country (buyer-country=DE), a CPV code written with its check digit, as CPV codes are officially printed (classification-cpv=72000000-5), and the old TED expert syntax (CY=[DE] AND PC=[72000000]). They are now rewritten before the query is sent — DE → DEU (also EL → GRC, UK → GBR), 72000000-5 → 72000000, and old CY, PC, PD (dates and <> ranges) and FT fields into the current syntax. The log lists every rewrite.
  • An old-syntax field that cannot be translated (for example TD=[3]) now stops the run with a message naming that field, instead of TED's generic syntax error.
  • No change to output fields, filters or price.

0.6.7 — 2026-09-29 — keyword search; plain words no longer fail the run

  • New keywords field. Words are searched in the full notice text (TED full-text search); commas separate alternatives.
  • Plain words in the advanced field used to fail the run. TED answers anything that is not expert syntax with an error, so a query like software ended as a failed run. Text with no field operator is now searched as keywords, together with the filters; a real expert-syntax error now says how to fix it.
  • Custom dates in more formats: 20260501, 2026-05-01 and 01.05.2026 are accepted (the form used to take only 20260501).
  • README corrected against the real input. Every example used input keys this Actor does not have (queries, maxResultsPerQuery, with a literal undefined value), listed phantom fields (maxConcurrency, includeRaw) and described company-registry features ("name or registry-ID lookup", "legal form, formation date"). Examples, input and output now match the Actor. No price change.

0.6 — 2026-09-07

  • Enabled AI-agent payments (x402) + rebuilt the README to the full standard (What-is / when, AI-agents + x402 agentic payments + MCP, Overview, Features, Use cases, Integration, FAQ, Troubleshooting, Support & contact).

0.0

  • Initial release: EU procurement notices from Tenders Electronic Daily (TED), the EU public-procurement journal (official open data).