UK Contracts Finder Scraper - Tenders & Awards
Pricing
from $4.00 / 1,000 contract awards
UK Contracts Finder Scraper - Tenders & Awards
Scrape UK public contracts from Contracts Finder, one row per supplier: who won, for how much, from which buyer, the buyer's named contact, and the days until the contract expires, which tells you what goes back to tender soon. Filter by keyword, category, date.
Pricing
from $4.00 / 1,000 contract awards
Rating
0.0
(0)
Developer
Tom Awake
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
16 hours ago
Last modified
Categories
Share
What does UK Contracts Finder Scraper do?
Who won which UK public contract, for how much, from which buyer — and how many days until that contract expires.
Contracts Finder publishes UK public procurement in OCDS format. A notice
nests a tender, an array of awards, and a separate parties array
where the supplier's address and the buyer's contact live. Nothing is
joined, and the supplier's address arrives as a single line-broken blob.
This Actor returns one row per supplier per award, joined, with the things the source leaves implicit.
No API key. No account.
The four things this does that the source does not
1. One row per supplier.
An award can name sixteen suppliers. The source stacks them in an array; we explode them, so every row is one contactable party with its own share of the record. Measured: 319 supplier rows out of 300 awards.
2. The parties join — 100%, no orphans.
awards[].suppliers carries only an id and a name. The address, the
company size, and the buyer's named contact all live in a separate
parties array. We join them. Measured on 300 recent awards: every
supplier resolved, zero orphans.
That join is what produces the buyer contact — name, email and phone on 100% of notices. It is the most valuable field here and it is not in the award object at all.
3. Days until the contract ends.
This is the sales signal: a contract expiring in six months is a procurement about to reopen, and the incumbent is named. The source gives an end date, never a countdown. Measured on recent awards, 73 of 305 contracts expire within 180 days.
4. The supplier's postcode, parsed out of the address blob.
postalCode is populated on 0% of supplier parties. The postcode is
nevertheless there, buried in streetAddress between line breaks:
"IW HOUSE\n QUARRY ROAD\n CHIPPING SODBURY\n BS37 6JL". We extract it
and normalise the whitespace — 88.7% coverage.
Getting past the 300-result ceiling
The API's cursor pagination stops after three pages. It simply stops
returning a next link beyond 300 notices — about four days of
publications — no matter what you ask for.
This Actor walks backwards through time in date windows, sizing each window to the density it actually finds: narrower where notices are dense, wider where they are sparse. When a window hits the 300 ceiling it resumes from the oldest notice actually returned, rather than stepping over the ones it could not see.
Filters are applied during pagination, not after it. Asking for 300 rows with a selective filter returns 300 rows — an earlier version returned 44, because the loop counted rows before filtering.
Field coverage
Measured on a run of 300 awards with a 180-day expiry filter, and on 305 unfiltered awards.
| Field | Coverage |
|---|---|
supplierName | 100% |
buyerName, buyerContactEmail, buyerPostcode | 100% |
contractEndDate, daysUntilContractEnd, contractDays | 100% |
cpvCode, cpvDescription | 100% |
awardValue | 96.7% |
supplierPostcode | 88.7% |
supplierScale (large / sme) | 83.3% |
daysToPublication | 79.0% |
buyerContactPhone | 47.5% |
supplierCompanyNumber | 37.7% |
Re-measured 17 September 2026 on a 500-row run: daysUntilContractEnd
was present on 500 rows out of 500 and agreed with contractEndDate on
all 500 — zero discrepancies. Median 74 days; 289 of the 500
contracts expire within 90 days.
supplierCompanyNumber is the Companies House number, extracted from ids
of the form GB-COH-06472932. The other ids (GB-CFS-…) are internal to
Contracts Finder and resolve to nothing, so that field is deliberately
empty rather than filled with an identifier that looks useful and is not.
There is no supplier city field, on purpose
Contracts Finder never populates locality for suppliers — the field
came back empty on 500 rows out of 500, so it was removed rather than
shipped as a column of blanks.
Deriving it from the address was tried and measured: 66% of addresses
yielded something, but the results included England 39 times,
United Kingdom 24 times, counties (Staffordshire, Hampshire) and
street names (70 Chancery Lane). A field that is right two thirds of
the time is worse than an absent one, because it gets filtered and
counted as though it were reliable.
Use supplierPostcode for geography: it is validated against the UK
postcode format and present on 86-89% of rows. The buyer side is
unaffected — buyerCity comes from a field the source does fill, and is
present on 100% of rows.
What it is for
- Selling to the public sector. Filter
endingWithinDaysto 180, and each row is a contract about to be re-tendered — with the incumbent, the value, and the buyer's direct email. - Competitive intelligence. Every award your competitors have won, by value, buyer and category.
- Market sizing. 96.7% of awards carry a value. Aggregate by CPV code or by buyer.
- Supply chain and credit. Suppliers with Companies House numbers can be joined to any UK company dataset.
- SME policy research.
smeSuitableandvcseSuitableare the buyer's own flags;supplierScaleis what the supplier actually is. Comparing the two is a question the source cannot answer on its own.
Three dataset views ship with the Actor: Awards, Coming up for renewal, and Suppliers.
Running this as a scheduled watch
Contract award notices appear continuously, and the value of this Actor is time-sensitive: a contract expiring in six months is a procurement about to reopen, and you want to know before your competitor does.
Set publishedWithinDays instead of a fixed date, then schedule the
Actor in Apify. The window moves with each run.
{"stage": "award","publishedWithinDays": 7,"cpvCodes": ["72000000"],"maxItems": 500}
Measured 17 September 2026: publishedWithinDays: 7 returned 308 rows
published between the 12th and the 16th; 30 returned 500 rows going
back to the 4th.
Why not a fixed publishedFrom date? A schedule replays the same
input every time. With a fixed date the window never moves, so every run
returns the same rows — and charges you for them again. The rolling
window is the only setting that makes a weekly watch honest.
Limits
Stated plainly, because they affect what you can conclude.
- Rate limiting is real. The service returns HTTP 429 under sustained querying. Requests are paced and retried with a long backoff, so large runs take minutes rather than seconds. If a run is throttled part-way through, the rows already collected are returned rather than discarded.
- Publication dates, not award dates. The date windows filter on when
a notice was published.
daysToPublicationshows the gap: median 14 days, but up to 1,732 observed. A notice published this week can concern an award made years ago. - Negative publication delays are dropped. 10 of 300 awards had a
publication date earlier than the award date. That has no business
meaning, so
daysToPublicationis left empty rather than negative. - Contract end dates are as filed. Some are wrong, some contracts get
extended without a new notice, and 12 of 305 had already ended.
contractExpiredflags those. - Values are what the buyer published. Median £63,000, largest £135M observed, and some are £0. Framework call-offs sometimes carry the framework's value rather than the call-off's.
sourceUrlis for a browser. The link points at the notice page on Contracts Finder, which rejects automated requests with HTTP 403. It opens normally in a browser; it will not fetch from a script. Theocidfield is the canonical OCDS identifier if you need one.- UK only, GBP only. Every value observed is in GBP. Scotland, Northern Ireland and Wales also run their own portals; contracts published only there do not appear here.
How much does it cost?
You pay per contract award returned: $0.006 each, that is $6.00 per 1,000. There is no start fee, and subscription plans pay less per contract award.
The example input below asks for up to 500 contract awards, so it costs $3.00 at most.
If a run reaches the spending limit you set, the output stops at that limit and never goes past it. You are never charged for rows that were not delivered.
Use UK Contracts Finder Scraper as an API
Call it from your own code with the Apify client, here in Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("DataIO/uk-public-contract-awards").call(run_input={'stage': 'award', 'endingWithinDays': 180, 'maxItems': 500})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item)
It also works from JavaScript, Make, Zapier, n8n, and from AI agents through the Apify MCP server.
Other actors you might like
- TED Tenders Scraper: EU Public Procurement
- USAspending Scraper: Federal Contract Awards
- Federal Register Scraper: Comment Deadlines
FAQ
Is it legal to use this data?
The actor reads public data from its official source, without logging in and without bypassing any access control. What you do with the data, for example contacting people listed in it, is your responsibility under the laws that apply to you, such as GDPR in Europe.
Can I run it on a schedule?
Yes. See Running this as a scheduled watch above: use the rolling-window setting so each run returns only what is new.
Can AI agents use it?
Yes. It is available through the Apify MCP server, and every input field is described in its input schema, so an agent can call it directly.
Source
Contracts Finder, published by the Cabinet Office under the Open Government Licence v3.0, in OCDS 1.1. Public, no authentication. This Actor is not affiliated with the Cabinet Office.