Canada Government Tenders - Aggregated & Normalized avatar

Canada Government Tenders - Aggregated & Normalized

Pricing

from $4.00 / 1,000 results

Go to Apify Store
Canada Government Tenders - Aggregated & Normalized

Canada Government Tenders - Aggregated & Normalized

Every open Canadian government tender - federal, provincial, and municipal - pulled live and normalized into one schema, with bid documents, amendment tracking, and procurement method. Delta mode turns it into a bid-alert feed.

Pricing

from $4.00 / 1,000 results

Rating

0.0

(0)

Developer

Goodland Consulting

Goodland Consulting

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

7 days ago

Last modified

Share

Canada Government Tenders — Aggregated & Normalized

The fastest way to track Canadian government tenders as they're published — federal, provincial, and municipal, pulled live on every run and normalized into one clean schema. No 40MB bilingual CSVs, no juggling seven different portal layouts.

Every run hits the source portals directly, so what you get is exactly what's published right now — not a cached snapshot from an intermediary database.

Do you love this Actor? Please leave a review! Found a bug, or need a source we don't cover yet? Please create an issue!

Need higher volume, a login-gated source (e.g. your own MERX account), or a delivery pipeline into your CRM/Slack? See "Need something custom?" below and get in touch — otherwise, read on.

What you get

  • One schema, every portal. Federal, provincial, and municipal tenders come out with the same fields (title, category, regions, closingDate, contactEmail, ...) no matter which source they came from.
  • Built-in filtering. Keyword, province, and procurement-category filters run before data ever reaches your dataset — see Filter behaviour by source for exactly what each source supports.
  • Delta mode for alerts. Run it on a schedule and get only tenders you haven't seen before — turn this into an instant bid-alert pipeline via Apify's Slack, email, or webhook integrations.
  • Resilient by design. Every source fails soft — a broken portal is logged and skipped, never fatal to the run, so one bad day on one site doesn't kill your data.
  • Indigenous procurement flagging. Federal notices are checked against Canada's Indigenous set-aside program (PSIB/TIPS) and flagged automatically.

Sources covered

SourceCoverage
CanadaBuysAll federal tenders — the official Government of Canada open data feed
SEAOQuebec public sector, via Données Québec open data
Alberta Purchasing ConnectionAlberta ministries and public entities
CivicInfo BCBC local government — municipalities, regional districts, school districts
bids&tendersHundreds of Canadian municipalities, school boards, universities, and agencies — pick your organizations (see below)
SaskTendersSaskatchewan ministries, crown corporations, municipalities, school divisions, health authorities
Nova ScotiaNS public sector including the MASH sector (municipalities, academic, school boards, health)

Technical details

Freshness. CanadaBuys new-tender notices refresh every 2 hours (06:15–22:15 ET); its full open-tenders file refreshes daily (~07:00–08:30 ET). SEAO publishes weekly. Every other source is fetched live, straight off the portal, on each run.

Memory. Alberta, bids&tenders, Nova Scotia, and SaskTenders are more resource-intensive to fetch — give runs that include any of these sources at least 2048 MB. CanadaBuys, SEAO, and CivicInfo BC run fine on the default memory.

A source returned nothing — is it broken? Possibly something changed on the source's end. Sources fail soft (logged and skipped, never fatal to the run) — if a source looks stuck at 0 for a while, open an issue and we'll take a look.

Run order and maxItems. Sources are fetched in the order you list them in sources. Once the run has pushed maxItems tenders, remaining sources in the list are skipped entirely for that run — put your highest-priority source first if you're running a tight cap.

Expired notices. Dropped by default based on closingDate at run time (includeExpired: true to keep them). SEAO's weekly dumps in particular carry a lot of already-closed notices.

Filter behaviour by source

Not every source carries every field, so filters apply differently depending on where a tender came from:

  • Keywords — matched case-insensitively against title + description on every source.
  • Provinces — supported on every source. Sources that only ever cover one province (Alberta, CivicInfo BC, SaskTenders, Nova Scotia) are simply included or excluded based on whether that province is in your filter.
  • Categories (CNST/GD/SRV/SRVTGD) — only CanadaBuys and SEAO carry a real category code and are filtered by it. On other sources the categories filter has no effect — tenders come through regardless of category, and category is null (or a best-effort value on bids&tenders) in the output.
  • newSinceHours — supported on every source. SEAO's data is published weekly, so short windows round up to the nearest week.

Choosing bids&tenders organizations

The bidsandtenders source works against any organization hosted at {org}.bidsandtenders.ca. Set bidsAndTendersOrgs to the subdomains you want; leave it empty for a diverse national starter set (Saskatoon, Metro Vancouver, TDSB, Yukon, Halifax, Red Deer).

ProvinceExample orgs
Ontariotdsb, durham, guelph, kitchener, waterloo, barrie, london, burlington
Albertareddeer, ae-ab
Saskatchewansaskatoon, ae-sk
British Columbiametrovancouver, bidcentral
Nova Scotiahalifax
Manitobamwsb (Manitoba Water Services Board)
Yukonyukon
National co-opscanoe (Canoe Procurement Group of Canada), bids

To check whether an organization is on the platform, open https://{org}.bidsandtenders.ca/Module/Tenders/en — if it loads a listing, the subdomain works.

Indigenous procurement

Ottawa mandates a minimum 5% of federal contract value go to Indigenous business (the Procurement Strategy for Indigenous Business / Transformative Indigenous Procurement Strategy). This actor detects those set-asides automatically on CanadaBuys notices and flags them indigenousSetAside: true (false on other CanadaBuys notices; the field is omitted entirely on every other source, since they have no way to determine it). Set indigenousOnly: true to keep only flagged notices:

{
"sources": ["canadabuys"],
"indigenousOnly": true
}

Example input

Construction tenders in the Prairies, published in the last day:

{
"sources": ["canadabuys"],
"categories": ["CNST"],
"provinces": ["MB", "SK", "AB"],
"newSinceHours": 24
}

Turn it into a bid-alert pipeline

Set deltaMode: true and run this actor on a schedule (hourly, daily — your call). Each run only returns tenders it hasn't emitted before, so you can wire it straight into Apify's Slack, email, or webhook integrations for instant new-tender alerts:

{
"sources": ["canadabuys", "seao", "bidsandtenders"],
"keywords": ["paving", "excavation", "snow removal"],
"deltaMode": true
}

Input parameters

sources — array, default ["canadabuys"]. Which portals to pull from: canadabuys, seao, apc, civicinfobc, bidsandtenders, sasktenders, novascotia.

keywords — array, default []. Case-insensitive match against title and description, on every source. Empty matches everything.

provinces — array, default []. Only tenders deliverable in these provinces; Canada-wide tenders always match regardless of this filter. See Filter behaviour by source for how matching differs by source.

categories — array, default []. CNST (construction), GD (goods), SRV (services), SRVTGD (services related to goods). Only actually narrows CanadaBuys and SEAO — see the caveat above before relying on it for other sources.

newSinceHours — integer, default 0. Only tenders published in the last N hours; 0 returns all open tenders. Behaviour varies slightly by source (see above) — none of that changes the output shape, just how the window is applied.

deltaMode — boolean, default false. Skip tenders already emitted by a previous run of this actor (tracked by tender id, persisted between runs). Pair with an Apify schedule for a standing bid-alert feed.

maxItems — integer, default 1000. Hard cap on tenders pushed to the dataset in a single run, across all sources combined. Sources are processed in list order and stop being fetched once this is hit.

bidsAndTendersOrgs — array, default [] (national starter set). Org subdomains for the bidsandtenders source — see Choosing bids&tenders organizations.

includeExpired — boolean, default false. Keep notices whose closing date has already passed.

includeRaw — boolean, default false. Attach the original source record to each item as raw. Useful when a field looks off and you want to see exactly what the source portal sent.

indigenousOnly — boolean, default false. Keep only CanadaBuys notices detected as Indigenous set-asides. Pair with "sources": ["canadabuys"] — other sources produce nothing under this filter.

enrich — boolean, default true. Emit the deep record: bid documents, amendment tracking, procurement method, selection criteria, trade agreements, bilingual title and description, and the full contact block. Set it to false for a leaner, cheaper record — the tender enriched event isn't charged when it's off.

Pricing

Pay-per-event:

EventPriceCharged
Actor start$0.15Once per run
Result$0.004Per normalized tender returned
Tender enriched$0.006On top of Result, for each record carrying the deep record (bid documents, amendment tracking, procurement method, selection criteria, trade agreements, bilingual text, full contact block). Not charged when enrich: false

An enriched tender costs $0.01 all-in; a lean one (enrich: false) costs $0.004. A daily-scheduled delta feed of the federal source runs about $11/month — you only pay for tenders that are new or have changed since your last run.

Output schema

Every key is present on every record from every source. A field a source can't supply is null (or []) — never omitted. Ragged records break typed consumers, and in a CSV export an omitted key produces a column where "missing" and "false" look identical.

FieldTypeDescription
idtextSource-prefixed unique id, e.g. canadabuys:ws1234
sourcetextcanadabuys | seao | apc | civicinfobc | bidsandtenders | sasktenders | novascotia
referenceNumbertext | nullThe source's own notice id
solicitationNumbertext | nullThe number humans quote — distinct from referenceNumber. Your join key against email, CRM, and the portal itself
title / titleFrtextTender title, English and French
description / descriptionFrtextTender description, English and French (see source notes below)
categoriestext[]CNST / GD / SRV / SRVTGD. Always an array — [] where the source has no category
noticeTypetext | nulle.g. RFP, RFI, ITT, ACAN
procurementMethodtext | nulle.g. Competitive - Open bidding, sole-source. The bid/no-bid decision
selectionCriteriatext | nullLowest price vs best value
tradeAgreementstext[]CETA / CFTA / CPTPP / WTO-GPA — determines who is eligible to bid
procurementEntitytext | nullThe contracting organization
endUserEntitytext | nullThe end user of the contract, where distinct from the procuring entity
contactName / contactEmail / contactPhonetext | nullFull contact block
regionstext[]Provinces where the work is delivered
publicationDatetimestamp | nullISO 8601
closingDatetimestamp | nullISO 8601
expectedContractStartDate / expectedContractEndDatetimestamp | nullFor capacity planning
statustext | nullNormalized to Open across sources for active notices
amendmentNumbertext | null"000" = never amended. See "Amendments" below
amendmentDatetimestamp | nullWhen the notice was last amended
gsin / gsinDescriptiontext | nullCanadian commodity classification
unspsctext[] | nullUNSPSC commodity codes
unspscDescriptiontext | nullHuman-readable label for those codes
documentstext[]Links to the bid documents and addenda — the thing a bidder actually opens. Available on CanadaBuys and SEAO; [] elsewhere (see below)
urltext | nullLink to the notice. Every CanadaBuys item resolves to a working URL — native notices link to a search pre-filled with the solicitation number
indigenousSetAsidebool | nulltrue/false on CanadaBuys notices (detected PSIB/TIPS set-aside). null means the source can't determine it — which is not the same as "no"
enrichedboolWhether the deep record was populated (see enrich)
scrapedAttimestampWhen we saw this record. Needed for incremental sync
rawjsonOriginal source record, only present when includeRaw: true

SEAO's open data doesn't include full notice body text, so description for SEAO items is synthesized from structured fields (notice type, buyer, commodity labels, delivery region) and url links to the full notice on seao.gouv.qc.ca instead.

Field coverage varies by source. On CanadaBuys, measured against the live feed: solicitationNumber, amendmentNumber, procurementMethod, contactName and the French fields are ~100% populated; tradeAgreements 100%; selectionCriteria 81%; amendmentDate 71%; expectedContractStartDate 55%; contactPhone 42%; documents 41%; gsin 5%.

Bid documents

documents carries links to the actual bid documents and addenda on CanadaBuys and SEAO. It is [] on the other sources, and honestly so: bids&tenders keeps its bid documents behind a vendor login ("a free preview of the bid documents is available" — the rest needs an account). We don't authenticate to portals, so we don't have those files, and we'd rather say that than quietly ship an empty column and let you find out.

Amendments

Tenders get amended — closing dates move, scope changes, addenda land. 57% of open federal notices carry at least one amendment.

In deltaMode, a tender is re-emitted when it is new or when it has changed since we last sent it to you. Change is tracked by content fingerprint (the source's amendment counter where one exists, otherwise the title, closing date, and document set), so an amended notice reaches your alert pipeline instead of being silently swallowed as "already seen." An unchanged notice is never re-emitted.

Deploy a pre-filtered copy

Every filter can also be set as an actor environment variable (Actor Settings → Environment variables). Run input always overrides the environment, so you can deploy a narrowed copy of this actor — e.g. "Manitoba Construction Tenders" — that needs no input at all:

VariableFormatExample
TENDERS_SOURCEScomma-separatedcanadabuys,seao
TENDERS_KEYWORDScomma-separatedpaving,excavation,snow removal
TENDERS_PROVINCEScomma-separated codesMB,SK,AB
TENDERS_CATEGORIEScomma-separatedCNST,SRV
TENDERS_NEW_SINCE_HOURSinteger24
TENDERS_MAX_ITEMSinteger500
TENDERS_DELTA_MODEtrue/falsetrue
TENDERS_INCLUDE_RAWtrue/falsefalse
TENDERS_BNT_ORGScomma-separated subdomainssaskatoon,tdsb,halifax,mwsb
TENDERS_INCLUDE_EXPIREDtrue/falsefalse
TENDERS_INDIGENOUS_ONLYtrue/falsetrue

FAQ

Wait, is this actually scraping live, or a pre-built database? Live. Every run fetches directly from each source portal you select, in real time. There's no intermediary database or caching layer; what you get is what's on the portal right now.

Where does the data come from? Federal data comes from the Government of Canada's official open data files under the Open Government Licence. Provincial and municipal sources are each portal's own public, unauthenticated data — no login-protected portal is accessed.

Can I get a province or portal that isn't listed? We're regularly expanding coverage. If there's a province or portal you need, get in touch — see "Need something custom?" below.

Can I access a login-gated source like MERX? Not through this public actor — MERX (used by Manitoba's government and Ontario's broader public sector, among others) is login-walled and its terms of service prohibit automated access. If you hold your own MERX credentials and want a private pipeline built against them, that's a custom engagement — see below.

How do I get a scheduled export as a file I can pull automatically?

  1. Save your configured input as an Apify task.

  2. Add a schedule to that task (e.g. hourly).

  3. Pull the latest successful run's dataset from: https://api.apify.com/v2/actor-tasks/TASK_ID/runs/last/dataset/items?token=YOUR_API_TOKEN&format=json&status=SUCCEEDED

    Replace TASK_ID with your task's id and YOUR_API_TOKEN with your token from Settings → API & Integrations. Swap format=json for csv, xml, xlsx, or others — see the dataset items API docs.

Need something custom?

Custom work is available: additional provincial or MERX-account-based feeds, closing-date reminders, CRM/Slack delivery, or tender-to-capability matching against your service catalog. Contact us via Apify to discuss.

Federal data comes from the Government of Canada's open data portal under the Open Government Licence. This actor does not access login-protected portals.