Bonfire / Euna Procurement Opportunities Scraper
Pricing
from $4.00 / 1,000 opportunities
Bonfire / Euna Procurement Opportunities Scraper
Open RFPs/tenders across hundreds of US/Canada local government agencies on Bonfire (Euna).
Pricing
from $4.00 / 1,000 opportunities
Rating
0.0
(0)
Developer
Alexei Pannicov
Maintained by CommunityActor stats
2
Bookmarked
18
Total users
10
Monthly active users
8 hours ago
Last modified
Categories
Share
Scrape open government procurement opportunities (RFPs, tenders, bids) published by hundreds of US and Canada local government agencies on the Bonfire / Euna Procurement platform. Get a clean, normalized feed of solicitations — with type, deadline, status and addenda — without logging in and without writing a parser for every portal.
Government agencies publish bids on thousands of fragmented portals, so monitoring them by hand is impossible. Incumbent aggregators (BidNet, DemandStar, GovWin, BidSync) charge $100–500/month. This Actor delivers the same public Bonfire data cheaply — you pay only for the opportunities you collect. Also works as a government RFP scraper, bid tracker, or bid-monitoring feed for Bonfire / Euna Procurement (bonfirehub.com) portals.
What this Actor does
- Collects open opportunities from any Bonfire agency portal (
{slug}.bonfirehub.com). - Normalizes each opportunity: parses solicitation type (RFP/ITB/RFQ/CSP/…) and converts the closing date to UTC ISO 8601.
- Optionally enriches each opportunity with public notices / addenda (extension notices, revised scopes, Q&A) — never miss an addendum that could disqualify a bid.
- Optionally adds past opportunities (closed / awarded / cancelled) from the agency archive, and the agency's public contracts in a separate dataset.
- Covers hundreds of agencies with one Actor: every Bonfire portal shares the same public API, parameterized only by the agency subdomain.
- Picks agencies for you from a built-in catalog of ~250 agencies by state / province and agency type (city, county, transit, K-12, …), or scans all of them.
- Filters opportunities by keywords in the title and by deadline window. Filtered-out opportunities are not returned and not charged.
Who is it for
Contractors and suppliers selling to government, bid consultants, lead‑gen and market‑intelligence services that build products on procurement data.
🚀 How to use
- Choose agencies: pick them by name in Agency slugs (or type any other Bonfire slug), and/or add whole groups with States / provinces and Agency types. Leave all three empty to scan every catalog agency.
- (Optional) narrow results with Keywords, Exclude keywords, Closing within (days) and Minimum days left.
- (Optional) enable Include notices to also fetch addenda/change feed per opportunity.
- (Optional) set Maximum opportunities to cap how many results (and your spend).
- Run the Actor. Results stream into the dataset; export as JSON, CSV, Excel, or pull via API.
- Schedule it (e.g. daily) to keep an up‑to‑date feed.
Input
All fields are optional.
| Field | Type | Description |
|---|---|---|
agencySlugs | string[] | Agency slugs — Bonfire agencies to scrape, always included. Pick from the list or type any other slug, e.g. dallascityhall. |
states | string[] | States / provinces — add all catalog agencies from these US states / Canadian provinces, e.g. TX. |
agencyTypes | string[] | Agency types — add all catalog agencies of these types: city, county, state-agency, k12, higher-ed, transit, airport, port, utility, housing, workforce, healthcare, other. |
includeNotices | boolean | Include notices (addenda) — fetch public notices/addenda per opportunity (slower). Default false. |
includeActiveOpportunities | boolean | Include active opportunities — fetch currently open opportunities. Default true. Turn off if you only want past opportunities and/or public contracts. |
includePastOpportunities | boolean | Include past (closed) opportunities — also fetch the agency archive. Default false. ⚠️ A large agency can add 1,000+ closed records, each charged — set maxItems too. |
includeContracts | boolean | Include public contracts — collect the agency's public contracts into a separate dataset. Default false. ⚠️ Up to 2,000+ contracts per agency, charged per record — set maxItems too. |
maxItems | integer | Maximum opportunities — cap on records returned per run in total, counted after filters. Shared across opportunities and contracts: contracts take whatever is left after opportunities. Empty = no limit. |
keywords | string[] | Keywords — keep opportunities whose title contains any of these words/phrases. Whole word, case-insensitive; roof* = prefix. |
excludeKeywords | string[] | Exclude keywords — drop opportunities whose title contains any of these. Wins over Keywords. |
closingWithinDays | integer ≥ 1 | Closing within (days) — deadline at most N days away. |
minDaysLeft | integer ≥ 0 | Minimum days left — deadline at least N days away. |
Which agencies are scanned: your agencySlugs plus catalog agencies matching states and agencyTypes (if only one of the two is set, the other doesn't restrict). If agencySlugs, states and agencyTypes are all empty, every catalog agency is scanned.
Specific agencies:
{"agencySlugs": ["dallascityhall", "harriscountytx"],"includeNotices": false}
All transit agencies in Texas:
{ "states": ["TX"], "agencyTypes": ["transit"] }
Roofing and HVAC bids closing within 30 days, across all agencies:
{ "keywords": ["roof*", "hvac"], "closingWithinDays": 30, "maxItems": 100 }
Behavior change: an empty
agencySlugswith nostates/agencyTypesused to return nothing; it now scans all catalog agencies (~1,500 opportunities, charged per item). If you buildagencySlugsprogrammatically, make sure the list is not empty — or setmaxItems.
Output
Each opportunity is one dataset record:
{"agency": "dallascityhall","agencyName": "City of Dallas","agencyRegion": "TX","agencyType": "city","projectId": "228905","referenceId": "BHZ26-00029887","title": "RFP - Event Production Services","solicitationType": "RFP","closeDate": "2026-05-29T18:00:00.000Z","closeDateLocal": "2026-05-29T13:00:00-05:00","agencyTimezone": "America/Chicago","status": "open","departmentId": "1013","url": "https://dallascityhall.bonfirehub.com/opportunities/228905","scrapedAt": "2026-05-29T10:00:00.000Z","notices": [{"threadId": "t1","subject": "Addendum No. 1 has been uploaded","content": "See revised scope of work.","dateCreated": "2026-05-20T12:00:00.000Z"}]}
notices is present only when Include notices is enabled. agencyRegion and agencyType come from the built-in agency catalog and are null for slugs outside it; agencyName falls back to the name published on the agency portal.
status mirrors the status badge on the agency's Bonfire portal:
status | Meaning |
|---|---|
open | Accepting submissions. |
closed | Past the deadline, no published award (includes solicitations still under evaluation). |
awarded | Past the deadline, the agency published the award. |
cancelled | The agency cancelled the solicitation. |
closed, awarded and cancelled appear only when Include past opportunities is enabled.
closeDate is always UTC. closeDateLocal is the same moment in the agency's own time zone (read from its portal), because vendors work from "closes Friday 5 PM EDT", not from a UTC timestamp. Both are null when the portal is unreachable.
Past (closed / awarded / cancelled) records never carry notices (a closed solicitation gets no new addenda) and are excluded by the closingWithinDays / minDaysLeft filters, since a past deadline is not "N days away". Keywords / Exclude keywords apply to them as usual.
Contracts dataset
With Include public contracts, contracts go to a separate dataset (contracts), one record each:
{"agency": "hillsboroughcounty","agencyName": "Hillsborough County","agencyRegion": "FL","agencyType": "county","contractId": "158896","name": "Consulting Liaison for Special Districts","status": "3","isExtendable": true,"startDate": "2021-06-08T04:00:00.000Z","endDate": "2027-04-30T04:00:00.000Z","departmentId": "6791","scrapedAt": "2026-09-23T10:00:00.000Z"}
An expiring contract is an early signal of a future solicitation — months of warning instead of days. Only agencies that publish public contracts return any; the rest are skipped without a request. Keyword and deadline filters do not apply to contracts. status is Bonfire's raw contract status code. No vendor details are collected.
How it works
The Actor calls Bonfire's public endpoints (no login required):
- Open opportunities list —
GET /PublicPortal/getOpenPublicOpportunitiesSectionDataper agency. - Past opportunities (optional) —
GET /PublicPortal/getPastPublicOpportunitiesSectionData, one extra request per agency. - Public contracts (optional) —
GET /PublicPortal/getPublicContractsSectionData, only for agencies that have the feature enabled. - Agency portal —
GET /portal/, once per agency per run, for the time zone and agency name. - Public notices (optional) —
GET /opportunitiessingle/getpublicnotices/{projectId}, joined by message thread.
A failing agency never aborts the run (each agency is isolated), and a failed notices fetch never drops the opportunity itself. If an agency portal is unreachable, the run continues with closeDateLocal and agencyTimezone set to null rather than failing.
Pricing
Pay‑per‑event — you pay per opportunity returned, far below the $100–500/month incumbents:
- Basic — charged per opportunity (open‑opportunities list).
- Premium (Include notices) — charged at a higher rate per open opportunity; adds the addenda/change feed.
- Closed opportunities (Include past opportunities) — always charged at the basic rate, even with Include notices on (closed records carry no notices feed).
- Contracts (Include public contracts) — charged at the basic rate, and counted against the same Maximum opportunities budget.
Failed agencies and opportunities removed by filters are never charged — only delivered opportunities are. Cap your spend with the run budget and the Maximum opportunities input.
Limitations & notes
- Closing‑date timezone: Bonfire returns
DateClosein UTC, socloseDateis exposed as UTC ISO 8601 (verified against the portal's displayed local time), andcloseDateLocaladds the agency's local time. - Status codes: opportunity
statusfollows the same rules the Bonfire portal uses for its status badge. The raw contractstatuscode is passed through as-is — Bonfire does not publish what its codes mean. - Departments:
departmentIdis a raw ID; Bonfire publishes no public name mapping. - Scale / anti‑bot: portals sit behind Cloudflare. At scale, run with Apify Proxy (datacenter, escalating to residential) to avoid rate limiting.
- Agency discovery: the agency catalog is best‑effort (sourced from Common Crawl). Agencies missing from it can still be added to Agency slugs by hand.
- Filters: Bonfire's public list exposes only the title and deadline of an opportunity (no category, description or publish date), so keyword and deadline filters are the ones available.
Legality
This Actor collects only publicly available data that agencies are legally required to publish for transparency. It does not access anything behind a login and respects rate limits.
❓ FAQ
Do I need a Bonfire / Euna login? No. The Actor uses only public endpoints; login is required only to download documents or submit a bid, which it does not do.
Which agencies are supported? Any agency portal on Bonfire ({slug}.bonfirehub.com). The built-in catalog lists ~250 of them by name, state and type; you can also enter any other slug.
Can I search all agencies at once? Yes — leave Agency slugs, States and Agency types empty. Combine with Keywords or Maximum opportunities to keep the result (and cost) small.
Do I pay for opportunities removed by filters? No. Filters run before results are saved and charged.
How do deadline filters treat unclear dates? If an agency's closing date can't be parsed, the opportunity is dropped when Closing within or Minimum days left is set, and kept otherwise.
Why doesn't the keyword IT match "Unit"? Keywords match whole words, so short terms don't produce false hits. Use * at the end for a prefix: roof* matches "Roofing".
What happens if I enter an agency slug that doesn't exist? It is skipped and reported as failed — the run continues with the other agencies, and you are not charged for it.
How do I avoid missing an addendum? Enable Include notices to pull each opportunity's public notices/addenda (extensions, revised scopes, Q&A).
How fresh is the data? It reflects each portal at run time. Schedule the Actor (e.g. daily) for a continuously updated feed.
Why is closeDate in UTC? Deadlines are normalized to UTC ISO 8601 for reliable comparison; closeDateLocal gives the same deadline in the agency's own time zone.
Can I track bids for a specific state or region? Yes — set States / provinces (e.g. TX), optionally with Agency types, or start from one of the ready-made Actor Tasks.
Does this send bid alerts? Not on its own — the Actor is pull-based: each run writes results to a dataset, it doesn't push notifications. To get alerts, schedule the Actor (e.g. daily) and wire up your own integration on the run's output (webhook, dataset export, etc.).
📝 Changelog
See the Changelog tab (CHANGELOG.md) for what changed between versions — including output fields that were renamed or removed.
🛟 Support & feedback
Found a missing agency, a bug, or have a feature request? Open an issue on the Actor's Issues tab and we'll take a look.