CanadaBuys Tenders and Awards Scraper avatar

CanadaBuys Tenders and Awards Scraper

Pricing

from $13.40 / 1,000 procedure deltas

Go to Apify Store
CanadaBuys Tenders and Awards Scraper

CanadaBuys Tenders and Awards Scraper

Scrape Canadian federal tenders and contract awards from CanadaBuys: title, buyer, closing date, supplier and value. Every run returns the current records as a dataset. Optional watch mode returns only what changed since your last run. Pay per result.

Pricing

from $13.40 / 1,000 procedure deltas

Rating

0.0

(0)

Developer

NexGen Watch

NexGen Watch

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

2

Monthly active users

16 days ago

Last modified

Share

πŸ“œ CanadaBuys Tenders and Awards Scraper

Scrape every open Government of Canada tender opportunity from CanadaBuys β€” title, buyer, province, closing date, procurement method and UNSPSC codes β€” as clean rows. One run reads the official CanadaBuys open-data file of all currently open tenders (878 notices on 2026-10-05) and returns them as a dataset, capped by maxItems. Turn on watch mode and a scheduled run returns only the notices that are new or changed since your last run.

The source is the public, logged-out CanadaBuys open-data CSV at canadabuys.canada.ca β€” no account, no API key. The unit of output is one tender_notice row per open tender (or, in watch mode, one procedure_delta row per change), and billing is pay-per-event: a $0.02 start fee per run, then $0.004 per tender notice (or $0.02 per delta) plus one $0.10 source check per run that read the source.

Who buys this

Buyers usually search for CanadaBuys or Canada government tenders.

  • Bid teams and suppliers following CanadaBuys in their category.
  • Procurement-intelligence vendors and consultancies tracking Canada government tenders and incumbents.
  • Analysts researching who buys what from whom in the public sector.

πŸ“Š Sample Output

CanadaBuys Tenders and Awards Scraper sample output β€” a table of real open tender rows (reference_number, notice_title, buyer_names, buyer_province, publication_date, deadline) from run 9Dgn6opY7uTMoNHaF on build 0.1.36

Real rows from run 9Dgn6opY7uTMoNHaF on build 0.1.36 (2026-10-05), the same input as the Quick start below β€” every value is as the source published it (long text shortened). Notice that the first rows of the file are long-running Defence Construction Canada source lists: the file is in the source's own order, so a small maxItems shows the front of the file, not the newest notices. Use publishedFrom to get recent notices only.

reference_numbernotice_titlebuyer_namesbuyer_provincepublication_datedeadline
MX-443841357513Open Construction Source List for CFB HalifaxDefence Construction Canada - Atlantic RegionNova Scotia2026-01-232029-03-31
MX-443841357514Open Construction Source List for 9 Wing GanderDefence Construction Canada - Atlantic RegionNova Scotia2026-01-232029-03-31
MX-443841357515Open Construction Source List for 5 Wing Goose BDefence Construction Canada - Atlantic RegionNova Scotia2026-01-232029-03-31
MX-443841876264Open Construction Source List for CDSB GagetownDefence Construction Canada - Atlantic RegionNova Scotia2026-01-232029-03-31
MX-443841876266Open Construction Source List for 14 Wing GreenwDefence Construction Canada - Atlantic RegionNova Scotia2026-01-232029-03-31
MX-443840130570Open Construction Source List for CFB Esquimalt,Defence Construction Canada - Pacific RegionBritish Columbia2026-01-222029-03-31
MX-443840130685Open Construction Source List for 19 Wing Comox,Defence Construction Canada - Pacific RegionBritish Columbia2026-01-222029-03-31
MX-443840195575Open Construction Source List for ASU ChilliwackDefence Construction Canada - Pacific RegionBritish Columbia2026-01-222029-03-31

The run finished with the status message: CAPPED: reason=CAPPED_MAX_ITEMS; pages=1/1; records=10 β€” the file held 878 open tenders and the cap of 10 was reached.

βœ… What you get

Every row is flat JSON. The dataset holds tender_notice rows (snapshot mode) or procedure_delta rows (watch mode); diagnostics never land in the dataset. A field the source does not publish for a given row is null.

tender_notice fields (snapshot mode, and the after block of a delta):

  • record_type (string) β€” tender_notice.
  • run_id (string) β€” Apify run id that produced this row.
  • jurisdiction (string) β€” always CA.
  • source_url (string) β€” the open-data file the row was read from.
  • observed_at (string) β€” RFC3339 UTC time the file was read.
  • source_id / reference_number (string) β€” CanadaBuys reference number, e.g. MX-443841357513 or cb-345-59054122. Stable for the life of the notice; the watch baseline is keyed on it.
  • amendment_number (string/null) β€” 000 for the original notice, higher for amendments.
  • solicitation_number, procedure_key, procedure_identifier (string/null) β€” the buyer's solicitation number; used to group a notice and its amendments.
  • notice_title (string) and notice_title_fr (string/null) β€” English and French titles.
  • status (string) β€” the source's status; every row in the open-tenders file is Open.
  • publication_date (string) β€” ISO date the notice was published.
  • deadline (string/null) β€” ISO closing date.
  • amendment_date (string/null) β€” ISO date of the latest amendment.
  • notice_type (string/null) β€” e.g. Request for Proposal, Request for Standing Offer, Request for Information; empty for some notices.
  • procedure_type (string/null) β€” procurement method, e.g. Competitive - Open bidding.
  • procedure_category (string/null) β€” source category code such as CNST, GD, SRV.
  • procedure_description (string/null) β€” the notice description as published.
  • buyer_names (array) β€” contracting entity, e.g. ["Defence Construction Canada - Atlantic Region"].
  • buyer_province (string/null) β€” province as the source writes it (Ontario and ON both occur).
  • buyer_countries (array) β€” always ["CA"].
  • end_user_entities (array) β€” end-user department when published.
  • cpv_codes (array) and main_cpv_code (string/null) β€” UNSPSC/GSIN codes; 736 of the 878 open notices carried at least one on 2026-10-05.
  • estimated_value, estimated_currency β€” always null; the source does not publish an estimated value in this file.
  • notice_url (string) β€” the public notice page (canadabuys.canada.ca or merx.com).
  • content_hash (string) β€” SHA-256 over the fields that can change; a changed hash is what makes a notice_updated delta.
  • raw (object/null) and raw_truncated (boolean) β€” the original CSV row when includeRaw is true.

procedure_delta fields (watch mode): delta_type (new_opportunity or notice_updated), source_id, procedure_key, changed_fields (sorted field names that changed), before (null for a new notice) and after (the compact record), baseline_id, first_seen_at, observed_at, source_url.

Every run also writes a RUN_RECEIPT record to its key-value store with the terminal state, counts, HTTP statuses and the charged counts β€” never billed, never in the dataset.

βš™οΈ Sample inputs

1. Quick start β€” the Store example (this is what the sample above came from)

{
"maxItems": 10,
"watchMode": false
}

The first 10 open tenders in the file. The sample run charged exactly: 1 Γ— $0.02 apify-actor-start + 10 Γ— $0.004 tender_notice + 1 Γ— $0.10 source_check = $0.16 on the Free tier.

2. Narrowed to recent Ontario IT notices

{
"publishedFrom": "2026-09-01",
"provinces": ["Ontario", "ON"],
"unspscCodes": ["4321", "8111"],
"maxItems": 500,
"watchMode": false
}

Only notices published on or after 1 September 2026, by an Ontario buyer, whose UNSPSC codes start with 4321 (computer equipment) or 8111 (computer services). On the 2026-10-05 file this input passes 12 of the 878 open notices (198 without the UNSPSC filter). UNSPSC prefixes must be 4–8 digits. Filters are applied after the whole file is read, so they never cost extra β€” you pay $0.004 per row that passes, plus the start fee and the source check: 12 rows = $0.168.

3. Watch mode on a schedule β€” changes only

{
"watchMode": true,
"maxItems": 500
}

The first run reads all open tenders into a private baseline and returns zero rows (start fee + source check only). Every later run returns one procedure_delta row per notice that is new or amended since the baseline, billed at $0.02 each. The baseline is named from your filters, so the same input always continues the same watch; set baselineId to name it yourself.

🧾 JSON sample record

One real record from run 9Dgn6opY7uTMoNHaF, exactly as it lands in the dataset (the description is shortened here):

{
"record_type": "tender_notice",
"schema_version": "1.0",
"run_id": "9Dgn6opY7uTMoNHaF",
"jurisdiction": "CA",
"source_url": "https://canadabuys.canada.ca/opendata/pub/openTenderNotice-ouvertAvisAppelOffres.csv",
"observed_at": "2026-10-05T17:30:35Z",
"source_id": "MX-443841357513",
"reference_number": "MX-443841357513",
"amendment_number": "000",
"solicitation_number": "AR26SLHX_86026",
"procedure_key": "AR26SLHX_86026",
"procedure_identifier": "AR26SLHX_86026",
"notice_title": "Open Construction Source List for CFB Halifax",
"notice_title_fr": "RΓ©pertoire ouvert d’entrepreneurs en construction pour la BFC Halifax",
"status": "Open",
"publication_date": "2026-01-23",
"deadline": "2029-03-31",
"amendment_date": null,
"notice_type": null,
"procedure_type": "Competitive - Open bidding",
"procedure_category": "CNST",
"procedure_description": "Defence Construction Canada (DCC) is inviting contractors and suppliers to apply to be placed on an Open Construction Source List (OCSL) for commercial, residential, industrial, institutional, and civil work required by …",
"buyer_names": [
"Defence Construction Canada - Atlantic Region"
],
"buyer_province": "Nova Scotia",
"buyer_countries": [
"CA"
],
"end_user_entities": [],
"cpv_codes": [],
"main_cpv_code": null,
"estimated_value": null,
"estimated_currency": null,
"notice_url": "https://www.merx.com/public/solicitations/3776296409/abstract?language=EN",
"content_hash": "7d4bf7ad3744a90ade2b3be0da33d9745f0ead12998dc7c82e2c82d5ca9fa064",
"raw": null,
"raw_truncated": false
}

πŸ”§ How it works

Source. One file: https://canadabuys.canada.ca/opendata/pub/openTenderNotice-ouvertAvisAppelOffres.csv, the CanadaBuys open-data export of every currently open tender (about 6 MB, 67 bilingual columns, 878 rows on 2026-10-05). The companion new tender notices file is not read: it holds only the latest daily batch of newly published notices and is empty between publications. (Builds before 0.1.36 read that file, which is why runs on 2026-10-04 and early 2026-10-05 returned GENUINE_EMPTY.) Notice detail pages are not fetched; notice_url links to them.

Transport. One plain HTTPS GET from the Apify platform, identified by a named user agent. No proxy, no login, no cookies, no CAPTCHA handling, no browser.

Parse and check. The CSV header must contain the reference number, English title, status and publication date columns; if the source renames them the run ends BLOCKED with shape_drift and bills nothing. Rows are normalized into the flat record above. A row without a reference number, title or publication date is counted as observed but not emitted.

Filter. publishedFrom / publishedTo, keywords (title and description, case-insensitive substring), unspscCodes (prefix match), buyerNames and provinces (substring) are applied client-side to the whole file. There is no server-side query, so the file is always read in full.

Snapshot mode. Rows that pass the filters are delivered in file order up to maxItems; reaching the cap ends the run CAPPED, which is a normal, fully-billed run.

Watch mode. The whole file is read on every run β€” maxItems never limits what the baseline sees. The first run for a baseline stores every in-scope notice (keyed on reference_number, with a content hash) and emits nothing. Later runs emit new_opportunity for a reference number not in the baseline and notice_updated when a stored notice's hash changed (amendment number, closing date, title, status, description). A notice that leaves the file produces no delta β€” absence is never read as a withdrawal. If more deltas exist than maxItems, the first maxItems are delivered and the rest stay un-absorbed so the next run delivers them; the status message says how many remain. Baselines created by builds before 0.1.36 (from the new-notices file) are re-seeded from the open-tenders file on their first run on this build, with zero deltas and a status message that says so, so the switch of source can never surface as hundreds of billed "new" notices.

Terminal states. NORMAL, CAPPED (your cap was reached), GENUINE_EMPTY (the file was read and no row passed your filters), PARTIAL (delivery stopped early; the message says why) or BLOCKED (HTTP error, timeout or changed columns β€” the run fails and bills no value event). A zero-row run is never a silent success.

Charging. Each row is pushed and charged in one step (tender_notice or procedure_delta), so the dataset count always equals the charged count. One source_check is charged per run that read the source successfully. The award_notice event exists for API compatibility with the sibling procurement actors; this file contains no award records, so it is never charged here.

⏰ Set it on a schedule

Open the actor in Apify Console β†’ Schedules β†’ Create new, add this actor with input 3 above (watchMode: true), and pick a cadence. Because every run reads the complete open-tenders file, the time of day does not matter β€” a notice published at any hour is picked up by the next run, whenever that is. The source republishes the file during the day (its last-modified time was 10:20 UTC on 2026-10-05).

  • Daily β€” 0 6 * * * (or any hour you like): every notice that stays open at least a day is caught once.
  • Twice daily β€” 0 */12 * * *: catches short-lived notices and amendments sooner.

Keep the same input on the schedule so each run continues the same baseline. Schedules can also POST results to a webhook (Console β†’ Integrations).

πŸ’° Pricing example

EventFreeBronzeSilverGold
Actor Start (apify-actor-start)$0.02$0.02$0.02$0.02
Tender notice (tender_notice)$0.004$0.0036$0.0032$0.00268
Award notice (award_notice)$0.006$0.0054$0.0048$0.00402
Procedure delta (procedure_delta)$0.02$0.018$0.016$0.0134
Source check (source_check)$0.10$0.09$0.08$0.067

Worked at the live Free-tier price:

  • Quick start, 10 tender notices: $0.02 start + $0.10 source check + 10 Γ— $0.004 = $0.16 (the sample run above)
  • A filtered run of 100 notices: $0.02 + $0.10 + 100 Γ— $0.004 = $0.52
  • Every open tender, 878 rows on 2026-10-05: $0.02 + $0.10 + 878 Γ— $0.004 = $3.63
  • A watch run with 25 changes: $0.02 + $0.10 + 25 Γ— $0.02 = $0.62

A run that delivers zero rows β€” the first watch run, a quiet watch run, or filters that nothing matched β€” charges the $0.02 start fee plus the $0.10 source check. A BLOCKED run fails and charges no value event. The start fee is charged once per GB of run memory; the default run memory is 512 MB.

Coverage. The file covers federal departments and agencies plus the provincial, municipal and Crown-corporation buyers that publish through CanadaBuys (Quebec and Ontario buyers made up 730 of the 878 open notices on 2026-10-05). Closed and awarded notices are not in this file, so the award_notice event never fires here. Estimated values are not published in the file. maxItems (default 500, maximum 5,000) is a hard ceiling on what is delivered and billed, never a target.

This actor reads a public, logged-out open-data file published by the Government of Canada on canadabuys.canada.ca. It collects only what the source publishes to any visitor, identifies itself with a named user agent, and does not access accounts, private data or anything behind authentication. The intended use is B2B bid research and procurement monitoring; use the output in line with the source's terms and your local law.

❓ FAQ

Q: Do I need an API key or a login?
A: No. The open-data file is public; the input schema has no key field and the actor carries no secrets.

Q: Why did my run return 0 rows?
A: Read the status message. GENUINE_EMPTY means the file was read and no open notice passed your filters β€” widen publishedFrom, drop a unspscCodes prefix, or check the spelling of a buyer name. In watch mode the first run for a baseline always returns zero deltas, and a later run returns zero when nothing changed. BLOCKED means the source refused or changed its columns; the run failed and billed no value event. A zero-row run bills the start fee plus one source check.

Q: Does it give me the newest notices first?
A: No β€” rows come in the file's own order. For recent notices set publishedFrom; for a continuous feed of new notices use watch mode.

Q: How many rows can one run return?
A: Up to maxItems (default 500, maximum 5,000). The file held 878 open tenders on 2026-10-05, so maxItems: 1000 returns all of them.

Q: What does watch mode remember between runs?
A: A private baseline in a named key-value store: every in-scope reference number with a content hash. Each later run reads the whole file again and emits only new or changed notices. Changing a filter changes the baseline name, so a different scope starts its own watch.

Q: How fresh is the data?
A: Every run reads the file live; nothing is cached except the watch baseline. The source republishes the file during the day; the run's observed_at tells you when it was read.

Q: What formats can I export?
A: The dataset downloads as JSON, CSV, Excel, XML or RSS from the run's Dataset tab or the Apify API, and any run can push to a webhook or integration.

Q: How is this different from the other procurement actors in this catalog?
A: Same record shape and billing model; this one covers CanadaBuys. The siblings under Related Actors cover AusTender, EU TED, GeBIZ and Japan β€” run several on one schedule for a combined feed.

πŸ†˜ Troubleshooting

  • Run FAILED with BLOCKED β†’ canadabuys.canada.ca returned an error, timed out, or renamed a required column β†’ nothing was billed beyond the start fee; retry later, and if it persists open an Issue with the run id.
  • Status says CAPPED β†’ your maxItems was reached (snapshot) or more deltas exist than maxItems (watch; the next run delivers the rest) β†’ raise the cap.
  • Status says "baseline re-seeded" β†’ your baseline was created before build 0.1.36 and has been rebuilt from the open-tenders file with zero deltas β†’ the next run reports changes as usual.
  • Input validation error on start β†’ a field is outside the schema (a date not in YYYY-MM-DD, a UNSPSC code that is not 4–8 digits, maxItems above 5,000) β†’ start from the Quick start block and change one field at a time.
  • Rows are all old source lists β†’ that is the front of the file β†’ set publishedFrom or raise maxItems.
  • First watch run shows no deltas β†’ expected: it seeds the baseline; changes appear from the second run.

⭐ Found this useful?

If this actor saved you a manual check, a quick review on the Apify Store helps other teams find it. Feature request or a source that changed? Open it from the Issues tab β€” every one is read.