Government Tenders Scraper - TED, SAM.gov, Procurement Data
Pricing
$2.90 / 1,000 tenders
Government Tenders Scraper - TED, SAM.gov, Procurement Data
19,795 notices in one week from the EU TED Tenders Electronic Daily API, where paged search stops at 15,000; 48 buyer countries in one measured window. UK and US SAM.gov notices with buyer email and phone. Government tenders API, SAM.gov contract opportunities search, public procurement database.
Pricing
$2.90 / 1,000 tenders
Rating
0.0
(0)
Developer
Snow Leo Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
TED, SAM.gov & UK Government Tenders and Procurement Scraper
Public procurement notices from four official feeds in one normalised dataset: TED (the European Union's Tenders Electronic Daily), UK Find a Tender, UK Contracts Finder and US SAM.gov Contract Opportunities.
One run, one row shape, one set of filters. A buyer looking for construction tenders above EUR 1 million closing this month writes that filter once, not four times.
48 buyer countries were present in a single measured window: 47 of them in
one 7-day slice of TED (2026-09-04 to 2026-09-11, 19 795 notices), plus the
United States from SAM.gov. Reproduce it with
python3 tools/measure_sources.py.
What this Actor collects
| Source | Covers | Notices measured |
|---|---|---|
| TED — Tenders Electronic Daily | EU, EEA, candidate countries; 47 buyer countries seen in one week | 19 795 in 7 days |
| UK Find a Tender | UK contracts above threshold | cursor feed, no published total |
| UK Contracts Finder | UK contracts below threshold | cursor feed, no published total |
| US SAM.gov Contract Opportunities | United States federal | 2 456 posted on 2026-09-10 alone |
Every one of the four is an open HTTPS endpoint that answers without an API key, without a proxy and without a browser. That was checked with live requests before this Actor was written, and it is why these four and not the dozen other portals that demand a registration key.
Why does the notice count matter more than the country count?
Because a country list is easy to pad. Anyone can name twenty portals in a description. The number that decides whether a monitor is useful is how many notices actually arrive per day and whether you get all of them — and that is where the two hard parts of this niche are.
The two things that break naive tender scrapers
What happens when a TED search returns more than 15 000 notices?
TED's search API accepts page and limit, and refuses any combination where
page × limit exceeds 15 000, with the error SEARCH_WINDOW_TOO_WIDE. It
does not warn you on the way in, and it does not tell you how many you lost.
Measured on 2026-09-11: a plain publication-date>=today(-7) query reports
19 795 matching notices. A client that walks pages therefore reaches 15 000
and stops, silently dropping 4 795 notices — 24.2% of the week.
This Actor uses TED's iteration cursor (paginationMode: ITERATION) instead of
page numbers, which has no such ceiling. The full 7-day window was walked end
to end in 80 requests of 250 and returned exactly 19 795 unique publication
numbers, with no repeats.
The live test suite proves both halves of that claim on every run:
t_ted_window_cap_is_real asks for page 61 and requires HTTP 400 mentioning
15000; t_ted_cursor_goes_past_the_cap collects more than 15 000 unique
notices through the cursor.
How do you read a 250 MB file without downloading 250 MB?
SAM.gov does not publish a date parameter at all. Its Contract Opportunities extract is a single CSV of 249 740 888 bytes and you are expected to take the whole thing.
Measured over the first 25 000 rows on 2026-09-11: the file's PostedDate
column is monotonically non-increasing — newest notices first. So the
reader can stop as soon as the dates leave the requested window. For a 7-day
window that is roughly 11 000 rows instead of the full file.
The saving is not theoretical: at the download rate measured that day, the full file took about 96 seconds of transfer before parsing began.
Because the whole trick rests on that ordering, the live suite re-checks it
every run (t_sam_is_sorted_newest_first). If SAM ever changes the order, the
test goes red rather than the data going quietly wrong.
What comes back
42 fields per notice. The ones that take work rather than copying:
days_to_deadlineandis_open— computed at run time from the notice's closing date.is_openisfalsefor awards and for passed deadlines, andnullwhen no deadline was published, which is not the same thing.cpv_divisionandcpv_division_label— the CPV sector spelled out in English ("45 — Construction work"). No source publishes the label, only the digits.value_eur_estimate— the published amount converted at a fixed rate table dated 2026-09-11, so that one sort works across 19 currencies. It is named an estimate because it is one;value_amountandvalue_currencyalways carry exactly what the source said.notice_type_label—cn-standardbecomes "Contract notice".buyer_country— ISO-3166 alpha-3 for every source. TED sendsDEU, the UK feeds sendGB, SAM.gov sendsUSA; you should not have to care.change_type—NEWorUPDATEDin monitor mode.
Plus the buyer's buyer_email, buyer_phone, buyer_contact_point,
buyer_website, the award_winner_name on award notices, submission_url,
and the notice's own public notice_url.
How full are those fields really?
Measured on 150 live rows from each source on 2026-09-11 with
python3 tools/fill_rates.py 150:
| Field | TED | Find a Tender | Contracts Finder | SAM.gov |
|---|---|---|---|---|
title, buyer_name, buyer_country, notice_url | 100% | 100% | 100% | 100% |
buyer_email | 100% | 100% | 100% | 100% |
buyer_phone | 100% | 21% | 50% | 44% |
cpv_codes | 100% | 97% | 100% | 0% |
deadline_date | 49% | 26% | 100% | 71% |
value_amount | 68% | 35% | 82% | 27% |
award_winner_name | 36% | 58% | 93% | 27% |
naics_code | 0% | 0% | 0% | 99% |
An empty cell here is the source not publishing the field, not this Actor failing to read it — with two exceptions that were this Actor failing to read it, and were fixed:
- CPV on Find a Tender went from 13% to 97%. The obvious place to read a
CPV code is
tender.classification. On 30 live releases that field carried a code in 3 of them;tender.items[].additionalClassificationscarried one in 15, and awards carry more. Reading only the obvious place leaves most of the feed with no sector at all, which then silently breaks every sector filter. - The public notice URL on Contracts Finder went from 7% to 100%. Only 7%
of releases publish an HTML document link. The rest are reachable by
stripping the trailing
-<serial>from the release id, which is what the service's own notice pages do.
Filters, and why they run before you are charged
Every filter in the input form is applied before a row is written to the dataset. On a pay-per-result Actor that is the difference between paying for what you asked for and paying for what the source happened to publish.
Where the source can do the filtering, it does. Keyword, country, sector and notice type are pushed into TED's own query language, so non-matching notices are never even downloaded. The UK and US feeds have no text or sector parameters, so the same filters run locally for them — still before the push.
Why is the keyword filter not applied twice to TED rows?
Because TED's full-text index searches the whole notice document, and this
Actor only downloads the fields it asked for. Re-running the keyword match
locally would throw away rows TED had already matched on text we never
received. Each source declares which filters it has already honoured
(filters.SERVER_SIDE), and those are not repeated. There is a test for it,
and a deliberate-breakage proof that the test catches its removal.
Can I exclude words, or watch one particular buyer?
Yes. Exclude keywords drops any notice containing one of your words in its title, description or buyer name. Buyer name contains keeps only notices from authorities whose name matches — one ministry, one council, one agency. Both run before billing, like every other filter. Closing dates can be bounded from both sides with Deadline from and Deadline to, or loosely with Deadline within N days.
What stops one source from eating the whole limit?
With several sources selected, maxItems is split evenly between them unless
you override it with maxItemsPerSource. Without that split, a request for
200 notices from four sources returns 200 notices from whichever source runs
first, and the run looks like a single-country scraper.
What does "only notices still open" actually drop?
Awards, and anything whose deadline has passed. It deliberately keeps notices with no published deadline: on these feeds a missing deadline is normal for prior information notices, and dropping them would hide a whole class of notice from everyone using the filter. Measured above: TED publishes a deadline on 49% of notices and Find a Tender on 26%.
Monitor mode
Turn on Monitor mode — only what changed and schedule the Actor daily.
It remembers which notices it has already delivered in a named key-value store, which survives between runs (the default store does not — it is wiped at the start of every run, and an incremental mode built on it quietly degrades into a full re-scrape that charges you again every morning).
Each delivered row is labelled NEW or UPDATED. A notice counts as
UPDATED when its title, buyer, deadline, value, notice type or the first
2 000 characters of its description changed — not when the source touched some
invisible internal field, which would make everything "updated" every day.
Unchanged notices are not returned at all unless you ask for them. You already paid for those rows once.
Memory holds 70 000 keys and discards the oldest first when it overflows.
What happens if a run is cut off half way through?
Rows are written to the dataset first and marked as delivered second, never the other way round. If the container is moved or the run times out mid-push, the notices that did not make it out are still unknown to the memory and arrive on the next run. The opposite order loses them permanently, which is the kind of bug you only find by testing for it — so there is a lifecycle test that cuts a multi-batch push in half and asserts that memory never runs ahead of delivery.
Output shapes for agents
- Compact output returns 15 fields instead of 42 — the ones a language model or a spreadsheet actually reads.
- Drop empty fields omits keys whose value is null or empty rather than sending them. Given the fill-rate table above, that is real noise removed, not cosmetics.
- Include the description text can be turned off entirely when you only need metadata; descriptions are by far the largest part of a row.
- Include the raw source record does the opposite: it adds a
rawfield holding the untouched payload the source sent, next to the normalised columns, for when you need something this Actor does not map yet.
Honest limitations
Named here rather than left for you to discover:
- SAM.gov has no CPV codes and no works/supplies/services split. The US
classifies with NAICS.
naics_codeis filled on 99% of SAM rows, but the sector filter in this form is CPV-based and therefore does not apply to SAM.gov. Filter US rows by keyword or by NAICS downstream. - The notice type filter applies to TED only. The UK feeds use OCDS tags
and SAM.gov uses its own vocabulary; both are reported in
notice_typeandnotice_stage, but the picker's eForms codes are TED's. value_eur_estimateuses a fixed rate table, not live rates. The table is dated in the code (normalize.EUR_RATES_DATE). For a contract closing next month that is entirely adequate; for currency arbitrage it is not.- TED publishes a deadline on about half its notices and Find a Tender on
about a quarter. That is the source, not the reader. Notices with no
deadline keep
days_to_deadlineandis_openasnullrather than guessing. - Descriptions come from one lot. A TED notice split into many lots has many descriptions; this Actor carries the first in your preferred language and the notice URL for the rest.
- No award values for UK Contracts Finder awards without a published amount — 18% of the measured sample had none.
- Tender documents are not downloaded.
documents_urlandsubmission_urlpoint at them; the files themselves stay where they are. Some competitors fetch attachments, at the cost of a much slower and much more expensive run. - There is no sub-country region filter. Buyer city and postcode are published; NUTS and state-level filtering is not exposed in this form.
- You cannot feed it individual notice URLs. This Actor searches the four APIs; it is not a single-page fetcher.
- There are no proxy or concurrency knobs, because all four sources answer plain requests without one. If a source ever starts blocking, that is a change to this Actor, not a setting for you to tune.
- No built-in webhook fields. Apify's own webhooks fire on run finish and do the same job without a second copy of the feature.
- This Actor does not bid for you. It finds and normalises notices.
FAQ
Do I need an API key for any of this?
No. All four sources answer anonymous HTTPS requests. There is nothing to register for and nothing to renew.
How fresh is the data?
TED publishes on working days; the window measured on 2026-09-11 held 19 795 notices from the previous seven days. SAM.gov's extract had 2 456 notices posted on 2026-09-10. The two UK feeds are cursor-based and return whatever has been published up to the moment of the request.
Can I search in a language other than English?
Yes. TED publishes titles and descriptions in up to 24 languages, and
Preferred language picks which one lands in the title and description
columns. If a notice has no text in your language the next available one is
used rather than leaving the row blank. languages_available tells you how
many translations existed.
What is CPV and why should I filter by it?
CPV is the European Common Procurement Vocabulary: an eight-digit code whose
first two digits name the sector. Picking division 45 in this form matches
every code inside it — 45213316, 45000000 and the rest — rather than
only notices tagged with the bare division code. Testing equality instead of
the prefix is a common mistake and returns a tiny fraction of the real matches.
Can I write my own TED query?
Yes. Advanced — TED expert query takes TED's expert search syntax verbatim and replaces every generated clause, for example:
publication-date>=today(-3) AND buyer-country IN (DEU AUT) AND classification-cpv IN (72000000)
The other sources keep using the form's filters.
How do I get only the awards, to see who won what?
Set Stage to "Awards only". award_winner_name, award_winner_country,
value_amount and value_currency carry the result. On the measured sample
that is 36% of TED rows and 93% of Contracts Finder rows.
Why are there two UK sources?
They cover different money. Find a Tender carries contracts above the public procurement thresholds; Contracts Finder carries the below-threshold ones plus a large stream of awards. Most UK suppliers want both, and they are separate services with separate APIs.
What does the run report contain?
The REPORT record in the key-value store holds the date window, per-source
delivered and scanned counts, how many rows each individual filter removed,
the NEW/UPDATED/UNCHANGED tally, the list of buyer countries seen, and
any source that failed. A source that fails does not kill the run; it is
reported and the others continue.
How do I check the claims in this README?
Every number above comes from a tool shipped with this Actor, in tools/:
python3 tools/measure_sources.py— notice counts, country count, the 15 000 ceiling and the SAM ordering, all against the live APIs.python3 tools/fill_rates.py 150— the fill-rate table.python3 tests/run_all.py --live— logic, deliberate-breakage proof, lifecycle and live-source suites.python3 tools/verify_readme.py— checks that the numbers written here still match the code and the schemas.
What else is this called?
Names buyers use: government tenders scraper, public procurement data, TED contract notices, SAM.gov opportunities, procurement deadline tracker. Every row carries the days left to the submission deadline, so a deadline tracker is the same feed read by date.
Other names for the same feed: public sector bidding data, TED Europa tenders, solicitation notices, contracting authority or buyer lookup, open tender procedure type, CPV code search. They map to the fields value_amount, source_label, notice_type, buyer_name, procedure_type and cpv_codes.