TED (EU tenders) logo

Open data · Live on Apify

EU TED Tenders Scraper and Monitor

Find EU public tenders on TED with your own filters. Get one row per notice with buyer, deadline and value. Run it every morning to see only new tenders.

About $3.51 for 1,000 tender notices$0.0035 per tender notice + $0.01 per run. Apify bills you, not us.Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed.

Run it on Apify Opens apify.com, the website where our tools run. Sign up free with Google or email, no card needed.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure

What you get, for example

publicationNumber700154-2026
procedureIdc8e5ed0b-9c1a-4c7b-b32a-130c6ceda6a4
noticeTypecn-standard

How to use it: 3 steps

  1. Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
  2. Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example: 72000000 in CPV codes. Each start is one run.
  3. Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.

What it does

EU TED Tenders Scraper & Monitor searches public tender notices on TED (Tenders Electronic Daily, the EU's official journal for public procurement) by publication date, CPV code, buyer country, notice type and keywords, and saves one clean row per notice: title, buyer, deadline with time zone, estimated value with currency, lots and direct TED links.

  • search — returns every matching notice in the date window, newest first, up to maxResults.
  • monitor — returns only notices that earlier runs of the same monitor did not deliver yet. Schedule it every day and you get only new tenders.

Good for

  • Sales and bid teams who want new contract notices for their CPV codes and countries every morning.
  • Market research on who buys what in the EU: award notices with values and currencies.
  • Lead generation: buyer name, country, city and website for each tender.

Not a good fit

  • Full tender documents. The Actor gives procurementDocumentsUrl, pdfUrl and xmlUrl, but does not download them.
  • Personal contacts. E-mail addresses and phone numbers are not in the output; e-mails inside descriptions are replaced with [e-mail removed].
  • Very old archives in one run. One run covers at most 31 days.

Who uses it

Bid and sales teams

Get new contract notices for your CPV codes each day.

Market researchers

See who buys what in the EU, with award values.

Consultants

Build lists of public buyers by country and city.

Price

Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.

What you pay forPriceWhen
Start fee$0.01Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more.
Notice record$0.0035One TED notice saved to the Dataset. Runs with no matches and monitor runs with no new notices save no records.

Examples

  • One tender notice: about $0.01.
  • 1,000 tender notices: about $3.51.
  • Every day 100 tender notices, for 30 days: about $10.80 a month.

Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 1,400 tender notices.

Prices checked on 24 October 2026. See the current price on Apify.

Questions

Do I need a TED account or API key?

No. The tool uses the public TED Search API without a key.

Does it download the tender documents?

No. It gives you links to the documents, PDF and XML. You open them yourself.

Why do I see one procedure many times?

A procedure can have several notices, like a correction or an award. Each notice is one row.

When does TED publish new notices?

TED publishes on working days, Monday to Friday.

Is this an official TED product?

No. This Actor is not affiliated with or endorsed by the Publications Office of the European Union. Source: TED — Tenders Electronic Daily, Publications Office of the European Union, reused under the Commission's reuse decision 2011/833/EU. Always check the official notice before you bid. Each row links to the official notice on ted.europa.eu.

How fresh is the data?

Each run reads TED live, so you get what TED shows at that moment. TED publishes new notices on working days (Monday–Friday).

Why are there several rows with the same procedure?

A procedure can have several notices: a contract notice, corrections, an award notice. Each notice is its own row; procedureId connects them.

What is a CPV code?

The Common Procurement Vocabulary is the EU code list for what is bought. You can search codes on SIMAP.

Details

Step by step on Apify
  1. Open the Input tab. The form is already filled: CPV 72000000, last 7 days, 20 notices.
  2. Optional: add buyer countries, for example DEU and FRA, or choose a notice type such as cn-standard.
  3. Click Start.
  4. Open the Output tab and look at the Overview view: title, buyer, country, deadline, value and link.
Use cases
TaskInputKey fieldsNext step
Find open tenders to bid oncpvCodes, buyerCountries, noticeTypes: ["cn-standard"]title, tenderDeadline, estimatedValue, procurementDocumentsUrlSend to a sheet or CRM
Daily tender alertsmode: "monitor", schedulemonitorStatus, title, noticeUrlSlack or e-mail via integrations
Market and competitor researchnoticeTypes: ["can-standard"], dateFrom/dateTobuyerName, totalValue, totalValueCurrency, cpvCodesExport to CSV or BI
Public-sector lead listsbuyerCountries, cpvCodesbuyerName, buyerCity, buyerWebsiteEnrich in your CRM
Tips for better results
  • Use monitor mode on a daily schedule. You get only notices you have not seen.
  • One run covers up to 31 days. Use several runs for longer periods.
  • Always open the official TED link and check the notice before you bid.
Limits and good to know
  • Window: at most 31 days per run. For longer periods, run once per month
  • Rows: at most 2,500 rows per run (maxResults). In our tests 2,500 rows took about 25 seconds
  • TED query window: TED serves only the first 15,000 notices of one query. A monitor run with very broad filters stops there with status PARTIAL and a warning; narrow the filters or use lastDays of 1–3
  • Run time: the Actor stops reading TED after about 4 minutes and keeps the rows it has (PARTIAL)
  • Values as published: deadlines keep the time zone offset that TED publishes, even if it looks unusual. An estimatedValue of 0 means the buyer published 0; a missing value is null
  • Languages: buyer names and descriptions are often only in the original language. The …Language fields tell you which language you got
  • No personal contacts: contact e-mails and phone numbers are not returned

For developers

Sample result

One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.

one result · JSON
{
  "publicationNumber": "700154-2026",
  "procedureId": "c8e5ed0b-9c1a-4c7b-b32a-130c6ceda6a4",
  "noticeType": "cn-standard",
  "formType": "competition",
  "procedureType": "open",
  "publicationDate": "2026-10-09",
  "title": "Germany – IT services: consulting, software development, Internet and support – Wartungleistungen von Server- und Storagesystemen sowie Switchen",
  "titleLanguage": "ENG",
  "buyerName": "Land Hessen, vertreten durch die Hessische Zentrale für Datenverarbeitung",
  "buyerNameLanguage": "DEU",
  "buyerCountry": "DEU",
  "buyerCity": "Wiesbaden",
  "buyerWebsite": "https://vergabe.hessen.de",
  "mainCpvCode": "72000000",
  "tenderDeadline": "2026-11-09T10:00:00+01:00",
  "tenderDeadlineDateOnly": false,
  "requestDeadline": null,
  "estimatedValue": 345600,
  "estimatedValueCurrency": "EUR",
  "estimatedValueSource": "procedure",
  "lotsCount": 1,
  "lotIds": ["LOT-0000"],
  "noticeUrl": "https://ted.europa.eu/en/notice/-/detail/700154-2026",
  "pdfUrl": "https://ted.europa.eu/en/notice/700154-2026/pdf",
  "xmlUrl": "https://ted.europa.eu/en/notice/700154-2026/xml",
  "linkLanguage": "ENG",
  "dataModel": "eforms",
  "monitorStatus": null,
  "source": "TED",
  "fetchedAt": "2026-10-11T02:17:31.898Z"
}

Use it from code

Actor ID: cliqtomedia/eu-ted-tenders-scraper. You need your Apify API token from Apify Console → Settings → API & Integrations.

Python · apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/eu-ted-tenders-scraper").call(run_input={
    "mode": "search",
    "lastDays": 7
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
cURL
curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~eu-ted-tenders-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "search", "lastDays": 7}'
LangChain · langchain-apify
# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("cliqtomedia/eu-ted-tenders-scraper")
result = tool.invoke({"run_input": {"mode": "search", "lastDays": 7}})
print(result)

The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.

Data fields (40)
FieldTypeMeaning
publicationNumberstringTED publication number, e.g. 674231-2026. One row per published notice; a corrected or changed notice is a new row with its own number.
noticeIdstringeForms notice identifier (UUID). Null for legacy notices published before eForms.
noticeVersionintegereForms notice version (1, 2, …). Null for legacy notices.
procedureIdstringeForms procedure identifier (UUID) shared by all notices of one procedure. A procedure is not a notice: several rows can share it.
isChangeNoticebooleanTrue when this notice changes an earlier notice (eForms change notice).
changesNoticestringWhich notice this one changes, as given by TED: a publication number (657981-2026) or an eForms notice id with version suffix.
changeReasonCodestringTED change reason code, e.g. cor-buy (buyer correction), cor-pub, update-add.
noticeTypestringeForms notice type, e.g. cn-standard (contract notice), can-standard (award), pin-only (prior information), corr (legacy correction).
noticeSubtypestringeForms notice subtype number (1–40, E1–E6) as published.
formTypestringeForms form type: planning, competition, result, dir-awa-pre, cont-modif, change, consultation.
procedureTypestringProcedure type code, e.g. open, restricted, neg-w-call. Null when TED gives none.
publicationDatestringPublication day in the Official Journal S (YYYY-MM-DD, as published, not shifted to UTC).
publicationDateRawstringPublication date exactly as TED returns it, with its time zone offset, e.g. 2026-10-01+02:00.
dispatchDatestringDay the buyer sent the notice to TED (YYYY-MM-DD).
ojsNumberstringOfficial Journal S issue, e.g. 190/2026.
titlestringNotice title in the preferred language, or the fallback shown in titleLanguage.
titleLanguagestringLanguage of title (ISO 639-2, e.g. ENG). Differs from preferredLanguage when TED had no translation.
originalTitlestringShort procedure title in the buyer's original language.
descriptionstringProcedure description in the preferred language or the fallback in descriptionLanguage, cut at 4,000 characters. Usually only in the original language.
descriptionLanguagestringLanguage of description (ISO 639-2).
buyerNamestringBuyer (contracting authority) name. TED publishes it only in the original language, so buyerNameLanguage often differs from preferredLanguage.
buyerNameLanguagestringLanguage of buyerName (ISO 639-2).
buyerNamesarrayAll buyer names of a joint procurement, in the same language as buyerName.
buyerCountrystringBuyer country, ISO 3166-1 alpha-3 (e.g. DEU).
buyerCountriesarrayAll buyer countries (alpha-3), for joint cross-border procurements.
buyerCitystringBuyer city as published.
buyerWebsitestringBuyer organisation website as published in TED; some buyers give a bare domain without https://. Not a personal contact.
cpvCodesarrayAll CPV codes of the procedure and its lots, without duplicates (8 digits, no check digit).
mainCpvCodestringMain CPV code of the procedure.
placeOfPerformanceCountriesarrayCountries of performance (alpha-3), when published.
tenderDeadlinestringEarliest deadline for tenders across lots, ISO 8601 with the published offset, e.g. 2026-11-04T10:00:00+01:00. Only the date when TED gives no time (see tenderDeadlineDateOnly). Null when the notice has no tender deadline (e.g. award or prior information notices).
tenderDeadlineDateOnlybooleanTrue when TED gave a deadline day without a time. Null when there is no deadline.
requestDeadlinestringEarliest deadline for requests to participate (restricted and negotiated procedures): ISO 8601 date-time with the offset published by TED, or a YYYY-MM-DD date when TED gives no time.
estimatedValuenumberEstimated value without VAT: the procedure estimate, or the sum of lot estimates when all lots have one in the same currency (see estimatedValueSource). Null when not published — never 0 as a placeholder.
estimatedValueCurrencystringCurrency of estimatedValue (ISO 4217, e.g. EUR, CZK).
estimatedValueSourcestringprocedure = published procedure estimate; lots_sum = sum of the lot estimates.
totalValuenumberTED total value: for award notices the total awarded value, for other notices the total published value. Null when absent or published in several currencies.
totalValueCurrencystringCurrency of totalValue.
lotsCountintegerNumber of lots in the notice (0 for legacy notices without lot data).
lotIdsarrayLot identifiers, e.g. LOT-0001. A lot is part of the notice, never its own row.
Input settings (11)

The main fields of the input form. With the API you send them as JSON.

SettingName in the APITypeExample value
Modemodestring"search"
Last N dayslastDaysinteger7
Date fromdateFromstring
Date todateTostring
CPV codescpvCodesarray["72000000"]
Buyer countriesbuyerCountriesarray
Notice typesnoticeTypesarray
Keywordskeywordsstring
Preferred languagepreferredLanguagestring"ENG"
Max resultsmaxResultsinteger20
Monitor namemonitorStateNamestring"default"

Use cases with this tool

Each guide shows all the steps and the other tools.

Start on Apify

Make a free Apify account: you get $5 of free usage every month. Missing a tool? Suggest it. We read every idea, but we do not promise to build it.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure