UK Tenders Scraper - Find a Tender & Contracts Finder avatar

UK Tenders Scraper - Find a Tender & Contracts Finder

Pricing

from $1.50 / 1,000 procurements

Go to Apify Store
UK Tenders Scraper - Find a Tender & Contracts Finder

UK Tenders Scraper - Find a Tender & Contracts Finder

Scrape UK public procurement from Find a Tender (above threshold) and Contracts Finder (below threshold). One row per procurement joins tender, award and contract notices - buyer, CPV codes, procedure, deadline, value, lots, suppliers, documents and notice link. Daily changes feed, JSON/CSV/Excel.

Pricing

from $1.50 / 1,000 procurements

Rating

0.0

(0)

Developer

Philip Kirkbride

Philip Kirkbride

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

18 hours ago

Last modified

Categories

Features

Limited permissions

Share

UK Procurement Tenders Scraper

UK public bodies publish their buying on two national services: Find a Tender for above-threshold procurements, and Contracts Finder for below-threshold ones. A procurement usually appears more than once — first as a tender notice, later as an award or contract notice — and the useful picture only appears when those notices are put together.

This actor reads both services and saves one clean row per procurement. It joins the tender, award and contract notices that share the same Open Contracting ID (OCID), so a row carries the buyer, the CPV codes, the procedure, the status, the submission deadline, the value, the lots, the suppliers and contract values when they are published, the documents and the link to the official notice.

Cost. $0.0015 per procurement plus a $0.005 run start, so the Console sample of 20 open procurements costs about $0.035 and 100 procurements about $0.155. See Pricing.

Who it is for

  • UK suppliers and bid teams looking for work they can still bid on, filtered by what is being bought (CPV) rather than by title wording alone.
  • Tender-alert and monitoring services that need one row per procurement with a stable id, plus only what changed since yesterday.
  • Market research and analytics teams measuring what the public sector buys, from which buyers, at what value and from which suppliers.
  • Award and contract tracking: turn on awards and read the suppliers, award values and contract dates once they are published.

Quick start

Open procurements from both services, 20 rows (the Console default):

{"maxItems": 20}

IT services on Find a Tender:

{"sources": ["fts"], "cpvPrefixes": ["72"], "maxItems": 50}

Construction on Contracts Finder, the below-threshold service:

{"sources": ["cf"], "cpvPrefixes": ["45"], "maxItems": 50}

A daily changes feed for one search — same input, on a schedule:

{"cpvPrefixes": ["72"], "mode": "changes", "stateKey": "it-services", "maxItems": 100}

Everything published in a date window, whatever its status:

{"publishedFrom": "2026-11-01", "publishedTo": "2026-11-30", "status": "all", "maxItems": 200}

What you get

  • Source and OCID — whether the procurement is from Find a Tender (FTS) or Contracts Finder (CF), and its stable Open Contracting ID
  • Title and description — as published, in full
  • Buyer — name and identifier (for example GB-FTS-9129 or a company number when the buyer published one)
  • CPV codes — every code the notice uses, with the published description
  • Procedure and status — for example "Open procedure", active, complete or cancelled
  • Open flag — whether bids can still be submitted at the moment the run started
  • Tender period — the start and the submission deadline, in the source's own time zone
  • Value and currency — when the notice states one
  • Lots — each lot with its description, status, value and contract period
  • Awards and contracts — suppliers (name and identifier), award value, award date, contract value and contract dates, when the source has published them
  • Documents — each published document with its type, description, link, date and format
  • Release history — every release of the procurement with its id, date and tags, the latest release, and any amendments the source records
  • Notice link — the official notice page
  • How complete the row is — Find a Tender rows (with awards on) are built from the procurement's full published record. Contracts Finder has no full record to read, so its rows are joined from the notices the run read, and older notices of a long-running procurement may be missing; joinedFrom and historyComplete say which case a row is. If a Find a Tender record cannot be read, only that row falls back to the notices in the window and recordIssue says why; the run keeps reading the other records. A single run reads the full published record for at most 300 Find a Tender procurements; any beyond that are joined from the notices the run read, and recordIssue names the reason.
  • Possible matches on the other service — listed separately, never merged

Everything is passed through as published, including buyer and supplier names. A field the notice leaves out is null; nothing is guessed, translated or filled in.

All filters are optional. By default the actor reads both services and keeps open procurements whose submission deadline is still ahead.

FilterWhat it does
ServicesFind a Tender, Contracts Finder, or both (default)
KeywordEvery word must appear in the title, description, buyer, CPV descriptions, lots or award suppliers
CPV code prefixesKeep procurements whose CPV codes start with any listed prefix, for example 72 for IT or 45 for construction
BuyerCase-insensitive buyer name or identifier match
Published from / toNotice publication date range
Deadline from / toSubmission deadline date range
StatusOpen only (default) or all statuses
Maximum procurementsHow many rows to save (50 by default, up to 1,000)
Include awards and contractsJoin award and contract notices to the row (on by default)

Narrow filters search a limited window. Find a Tender and Contracts Finder do not offer keyword or CPV search, so the actor reads the newest notices in order and applies those filters itself. It stops after five pages in a row with no match, and it never reads more than 40 pages per service. A narrow keyword or CPV search therefore looks at the most recent releases rather than the whole archive. Add a Published from / to range to search a particular period; the date range switches the five-page stop off (the window already bounds the search), so only the 40-page cap applies.

Change tracking

Set Mode to Changes since the last run and the actor stops repeating the whole result set. It remembers what it last delivered for each procurement, and each later run saves only what moved:

  • new — a procurement this state has not delivered before
  • amended — a tracked value changed; changedFields names the fields. previous gives the earlier value of each changed single value (title, status, deadline, value, buyer, latest notice). For text and lists (description, CPV codes, lots, awards, contracts, documents, amendments) the field is named, and previous shows the earlier content only when it was empty — for example "awards": [] when a first award appears
  • closed — it was open at the previous run and is no longer open: the notice was awarded, cancelled or withdrawn, or its submission deadline has passed. A tracked procurement whose deadline passes is reported as closed even if no new notice is published for it; that row is rebuilt from the values delivered earlier and says so (joinedFrom: "earlier runs")

A run only reads the most recent notices, so it may not see every notice of an older procurement again. A value the notices read this run do not carry is treated as unknown, never as a change: single values keep the value delivered earlier, and the field is named in fieldsNotInScan. A missing deadline never turns into a false "closed".

The first run of a state has nothing to compare against, so every row it delivers is new; the run status says so. Use the same State key on every run of the same search. If you leave it empty, the name is derived from the search filters, so the same filters resume the same state and a different search starts its own.

The state lives in a named store in your own Apify account. Only rows that were actually saved are remembered, so a run that stops early does not hide what it did not deliver. If the state cannot be read or is not one this actor wrote, the run fails before delivering or charging anything, instead of starting over and repeating every procurement as new. If the state cannot be saved, the run fails and its status says which rows the next run will deliver again. Procurements not seen for a year are dropped, and the store keeps at most 5,000 procurements, the most recently seen first; the status says when any were dropped.

When a run reaches Maximum procurements, it stops and says so in the status; in Changes mode the remaining changes are delivered by a later run.

Change rows also carry the source's own version markers: the release ids, dates and tags, the latest release tag, and any amendments the notice records.

Possible matches across the two services

Find a Tender and Contracts Finder cover different thresholds, so most procurements appear on only one of them. When the same buyer publishes a very similar title with overlapping dates on both services, each row lists the other as a possible match with a plain reason. These are hints for a human to check. The two procurements are never merged into one row, and no match is asserted as certain.

Good to know

  • Dates keep the time zone the source published them in (UK local time, with the offset stated).
  • Awards and contract values appear only when the source has published them; they are usually absent while a tender is still open.
  • A search that matches nothing finishes successfully with zero rows and a plain status message.
  • A narrow keyword or CPV search looks at a limited window of the newest notices; add a publication date range to target a particular period.
  • If one Find a Tender record cannot be read — because it is missing, gone, rejected by the source, empty or malformed — only that procurement falls back to the notices in the window; the rest of the run continues, and recordIssue names the reason on the affected row.
  • A source that cannot be read is reported as an error, never as "no results".
  • If one service is unavailable, the other service's rows are still delivered and the status says the run stopped early.
  • If a run reaches Maximum procurements, the status says so: more procurements may match.
  • A run that runs out of time before delivering anything fails, so an empty result never looks like "no matches".
  • Contains public sector information licensed under the Open Government Licence v3.0.

Pricing

  • $0.0015 per delivered procurement — one charge per row, whether the row is a tender, an amended tender or a closed one. A procurement that appears as a tender notice and later as an award notice is one row and one charge.
  • $0.005 per run start, charged per GB of memory, so the default 512 MB run is one start charge. It applies even when a search matches nothing.
  • Reading CPV codes, notices and awards, and filtering, adds run time, not charges.
RunRowsCost
Console sample: both services, maxItems 2020$0.035
A CPV or keyword search on one service50$0.08
A daily changes feed that finds 12 changes12$0.023
Everything published in one month1,000$1.505

See the Pricing tab for the current price.

Output example

One row per procurement. This example is a Changes-mode row shortened to show the shape; repeated array entries are shortened too.

{
"recordId": "FTS:ocds-h6vhtk-0323a9",
"ocid": "ocds-h6vhtk-0323a9",
"source": "FTS",
"title": "Provision of Conversion Support Services for Student Recruitment for Glasgow Caledonian University",
"description": "The University is seeking a Contractor for the Provision of a Conversion Partner who is equipped to provide a bespoke data driven, measurable series of conversion solutions…",
"buyerName": "Glasgow Caledonian University",
"buyerId": "GB-FTS-9129",
"buyerIdentifierScheme": null,
"buyerIdentifierId": null,
"cpvCodes": [
{"code": "79411100", "description": "Business development consultancy services", "scheme": "CPV"}
],
"procedure": "Open procedure",
"procedureCode": "open",
"status": "active",
"isOpen": true,
"tenderPeriodStart": null,
"tenderPeriodEnd": "2026-12-04T12:00:00+00:00",
"valueAmount": 800000,
"valueCurrency": "GBP",
"lots": [
{"id": "1", "title": null, "description": "The University is seeking an experienced Higher Education conversion partner…", "status": "active", "valueAmount": null, "valueCurrency": null, "contractPeriodStart": null, "contractPeriodEnd": null, "hasRenewal": true}
],
"awards": [],
"contracts": [],
"documents": [
{"id": "104855-2026", "documentType": "tenderNotice", "title": null, "description": "Tender notice on Find a Tender", "url": "https://www.find-tender.service.gov.uk/Notice/104855-2026", "datePublished": "2026-11-04T16:19:41+00:00", "format": "text/html", "language": null, "source": "tender"}
],
"releases": [
{"id": "104700-2026", "date": "2026-11-01T08:30:00+00:00", "tags": ["tender"]},
{"id": "104855-2026", "date": "2026-11-04T16:19:41+00:00", "tags": ["tenderUpdate"]}
],
"releaseIds": ["104700-2026", "104855-2026"],
"releaseDates": ["2026-11-01T08:30:00+00:00", "2026-11-04T16:19:41+00:00"],
"latestReleaseId": "104855-2026",
"latestReleaseDate": "2026-11-04T16:19:41+00:00",
"latestReleaseTag": "tenderUpdate",
"latestReleaseTags": ["tenderUpdate"],
"releaseTags": ["tender", "tenderUpdate"],
"amendments": [],
"noticeUrl": "https://www.find-tender.service.gov.uk/Notice/104855-2026",
"joinedFrom": "full record",
"historyComplete": true,
"recordIssue": null,
"fieldsNotInScan": [],
"observedAt": "2026-11-04T21:17:15+00:00",
"changeType": "amended",
"changedFields": ["tenderPeriodEnd", "latestReleaseId", "latestReleaseDate", "latestReleaseTag", "latestReleaseTags", "noticeUrl"],
"previous": {
"tenderPeriodEnd": "2026-11-27T12:00:00+00:00",
"latestReleaseId": "104700-2026",
"latestReleaseDate": "2026-11-01T08:30:00+00:00",
"latestReleaseTag": "tender",
"latestReleaseTags": ["tender"],
"noticeUrl": "https://www.find-tender.service.gov.uk/Notice/104700-2026"
},
"firstSeenAt": "2026-11-01T09:00:00+00:00",
"lastSeenAt": "2026-11-04T21:17:15+00:00",
"contentHash": "…"
}

In Full mode, changeType, previous, fieldsNotInScan, firstSeenAt, lastSeenAt and contentHash are null, and changedFields is an empty list.

FAQ

How much does a run cost? $0.0015 per delivered procurement plus a $0.005 run start: the 20-row Console sample costs $0.035 and 100 procurements cost $0.155. Filters do not add a charge; they only change how much of the sources has to be read.

How do I get only new tenders each day? Set "mode": "changes" with a stateKey and schedule the run with the same input. The first run is the starting point; later runs deliver only new, amended and closed procurements, with the fields that moved and their previous values.

Why is my keyword or CPV search slow? Neither service offers keyword or CPV search, so a narrow filter has to be applied to the newest notices in order, and it stops after five pages in a row with no match. Narrow the source (sources), add a publishedFrom / publishedTo window, or keep the filter broad; a search that matches nothing finishes successfully with zero rows and the run start charge.

Why do Contracts Finder rows have fewer fields than Find a Tender rows? Find a Tender publishes a full procurement record; Contracts Finder publishes notice by notice, so its rows are joined from the notices read. joinedFrom and historyComplete say which case a row is, and recordIssue names a record that could not be read.

Why did I get fewer rows than Maximum procurements? Either the filters matched less than you asked for, a service stopped after five pages with no match, or the run reached its time limit. The run status says which, and the next run continues from where it stopped in Changes mode.

Are the tender documents downloaded? No. Each row lists the published documents with their type, description, link, date and format; the files stay on the official notice page.

What happens when nothing matches? The run succeeds with an empty dataset and a plain status message. A source that cannot be read is reported as an error, never as "no results".

Can I call it from the API or on a schedule? Yes. Every Apify Actor runs from the API with the same JSON input and can be scheduled; see the API tab of this Actor.

Where does the data come from and what licence applies? Find a Tender (above threshold) and Contracts Finder (below threshold), both published under the Open Government Licence v3.0. Everything is passed through as published.