PlanetBids Scraper – Government Bids & RFPs avatar

PlanetBids Scraper – Government Bids & RFPs

Pricing

from $2.40 / 1,000 bids

Go to Apify Store
PlanetBids Scraper – Government Bids & RFPs

PlanetBids Scraper – Government Bids & RFPs

PlanetBids bid tracker: open bids, RFPs and RFQs from 272 city, county, school and water district portals (mostly California). Due dates, categories, estimated value, documents, addenda, awards and bid results. No login.

Pricing

from $2.40 / 1,000 bids

Rating

0.0

(0)

Developer

Alexei Pannicov

Alexei Pannicov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

PlanetBids scraper and bid tracker: open government bids, RFPs and RFQs from city, county, school district and water district portals on PlanetBids (mostly California), plus bid results and awarded contracts (who won and for how much). Collect every public bid opportunity (bids, RFPs, RFQs, RFIs, qualifications) with due dates, categories, estimated value, documents and addenda, no login needed. PlanetBids hosts procurement portals for hundreds of US public agencies: cities, counties, school districts, water and transit districts. This Actor reads each portal's own JSON API over plain HTTP (no browser), so runs are fast and cheap, and every field comes typed and normalised.

What you get

  • Every bid on a portal, with stage (planning, bidding, closed, award pending, awarded, canceled, rejected), type, invitation number, issue and due dates with the agency's time zone offset, and categories with names.
  • Bid details (optional): scope and details HTML, estimated value (text and parsed USD), location, department, license requirement, duration, liquidated damages, pre-bid meeting, Q&A cutoff, award date and notes, special notices.
  • Extras (optional, one request each): document metadata, addenda with attachments, line items, pre-bid meeting, awards (winning vendor and amount), bid results (all bidders and amounts), prospective bidders.
  • A bundled catalog of 272 PlanetBids portals in 12 states (250 in California), so you can scrape every catalog portal in a state without looking up IDs.
  • Run records that tell you whether the data is complete: RUN_SUMMARY (per-portal counts, failures, WAF challenges) and CONTRACT_DRIFT (any change in the PlanetBids API seen during the run).

Use cases

  • Find new bids to win: track open bids and RFPs by keyword, category code or bid type across the agencies you sell to, and run it on a schedule.
  • Competitive intelligence: with awards and bidResults, see who won each contract, for how much, and what every other bidder offered.
  • Sales and lead generation: list the public agencies that buy what you sell, with departments, locations and estimated contract values.

How to use it

  1. Pick agencies by name from the catalog, or pick whole states. For a portal that is not in the catalog, enter its ID such as 14319 or a portal URL such as https://vendors.planetbids.com/portal/14319/bo/bo-search.
  2. Choose filters: stages, bid types, keyword, category codes, due date range, posted-after date.
  3. Turn on Include bid details and pick extras if you need more than the list data.
  4. Set Max items (default 100, 0 = unlimited) and run.

The portal ID is the number after /portal/ in any PlanetBids vendor URL.

Input

FieldTypeDefaultNotes
portalslist of IDs or URLs[]Portals not in the catalog. Combined with the catalog selections.
catalogPortalslist of catalog portal IDs[]Shown as agency names in the input form.
catalogStateslist of US states[]Adds every catalog portal in these states.
allCatalogPortalsbooleanfalseAdds every catalog portal.
stagesplanning, bidding, closed, awardPending, awarded, canceled, rejected["bidding"]Empty = all. One stage is filtered by the API; several are filtered by the Actor after listing everything (slower).
bidTypesbid, rfi, rfp, rfq, rfqual, ipwb[]Empty = all. Same one-vs-several rule as stages.
keywordtext""Full-text search by the API.
categoryCodeslist[]Category (NIGP-like) codes, e.g. 91200. Any match.
dueDateFrom, dueDateToYYYY-MM-DDnoneSent to the API.
postedAfterYYYY-MM-DDnoneFiltered by the Actor; with the default sort (issue date, newest first) paging stops early.
sortByissueDate, title, invitationNumber, dueDate, stageissueDateMatters with maxItems.
sortOrderdesc, ascdesc
includeDetailsbooleanfalseOne extra request per bid.
includedocuments, addenda, lineItems, preBidMeeting, awards, bidResults, prospectiveBidders[]Needs includeDetails. One request per extra per bid.
includeContactsbooleanfalsePersonal data, see below.
maxItemsinteger100Total across portals. 0 = unlimited.
maxRequestsPerMinuteinteger50Keep at 60 or less without a rotating proxy.
maxWafChallengesinteger5Stop after this many WAF challenges in a row.
wafBackoffSecsinteger150Pause after a WAF challenge (60-280).
proxyConfigurationproxyno proxyNot needed at the default rate.

Example:

{
"portals": ["14319", "https://vendors.planetbids.com/portal/17950/bo/bo-search"],
"stages": ["awarded"],
"bidTypes": ["bid", "rfp"],
"includeDetails": true,
"include": ["awards"],
"maxItems": 50
}

Extras are only fetched when the agency publishes them

Each bid tells whether its agency publishes awards, bid results and a pre-bid meeting. The Actor requests an extra only when it is published. Otherwise extras.<name> is notAvailable and the field is null. Award amounts are null when the agency publishes the winner but not the amount. Statuses: ok, notAvailable, failed (the request or parsing failed, the item is still saved), skipped.

Output

One dataset item per bid. List fields are always present. Detail fields appear when includeDetails is on and detailStatus is ok. A real item from Kern High School District (portal 14319), shortened:

{
"portalId": 14319,
"portalName": "Kern High School District",
"portalState": "California",
"portalTimeZone": "America/Los_Angeles",
"bidId": 146762,
"url": "https://vendors.planetbids.com/portal/14319/bo/bo-detail/146762",
"title": "Vista Continuation High School Modernization: Trash Haul-Off",
"invitationNumber": "Bid No. 6948",
"stage": "bidding",
"stageCode": 3,
"bidType": "bid",
"bidTypeCode": 1,
"responseFormat": "paper",
"responseFormatCode": 2,
"issuedAt": "2026-09-30T10:19:57-07:00",
"dueAt": "2026-10-21T14:00:00-07:00",
"categories": [
{ "code": "11111", "name": "Builder's Exchange & Plan Rooms" },
{ "code": "91027", "name": "Garbage/Trash Removal, Disposal And/Or Treatment" }
],
"detailStatus": "ok",
"scrapedAt": "2026-10-08T14:15:02.252Z",
"scope": "<p>Provide dumpsters and dumpster haul-off. Dumpsters provided are for the use of all Prime Contractors on site.</p>",
"estimatedValueText": "$98,000.00",
"estimatedValueUsd": 98000,
"licenseRequirement": "B or C-21 or C-61 and D-63",
"address": {
"line1": "5801 Sundale Avenue",
"line2": null,
"city": "Bakersfield",
"county": "Kern",
"zip": "93309",
"state": "California"
},
"department": "Business Services Department",
"duration": "490 Calendar Days",
"liquidatedDamages": "$2,000.00 per calendar day",
"preBidMeetingAt": "2026-10-07T10:00:00-07:00",
"preBidMeetingMandatory": false,
"extras": { "documents": "ok", "awards": "notAvailable" },
"documents": [
{
"documentId": 646708,
"title": "Specifications",
"filename": "Specifications.pdf",
"sizeBytes": 6589621,
"uploadedAt": "2026-09-30T08:06:35-07:00",
"isRecalled": false,
"publiclyVisible": false,
"downloadUrl": "https://files-prod01.planetbids.com/KHSD/BMfiles/20260930080635007%20Specifications.pdf"
}
],
"awards": null
}

Notes on the data:

  • Dates are ISO 8601 with the agency's UTC offset (PlanetBids stores local time without a zone). Empty dates are null.
  • Codes: stage, bidType and responseFormat are enums. If PlanetBids adds a new code, the value is unknown, the raw number stays in stageCode / bidTypeCode / responseFormatCode, the item is still saved, and the code is listed in CONTRACT_DRIFT.
  • Stage comes from the bid list. The detail endpoint reports closed bids as stage 3 "Closed", so the list value is the reliable one.
  • Estimated value is free text at PlanetBids ("$150,000.00", "N/A"). estimatedValueUsd is set only when the text is a plain dollar amount.
  • Documents are metadata only. The file host is behind a CAPTCHA, so downloadUrl does not download with plain HTTP.
  • HTML fields (scope, detailsHtml, notesHtml) are returned as published. Escape or sanitise them before rendering.

Run records (key-value store)

  • RUN_SUMMARY: end reason (completed, maxItemsReached, chargeLimitReached, wafBlocked, aborted), items pushed, failed details, skipped records, failed requests, WAF challenges, failed extras, and per portal: status (ok, notFound, failed, or skipped when the run stopped before the portal finished listing, e.g. at Max items), name, totalBids reported by PlanetBids, listed and pushed counts.
  • CONTRACT_DRIFT: new keys, missing keys, type changes and unknown codes seen in API responses. Empty means the API matched the expected contract.

The run's status message sums it up, for example Done: 1475 bids, 0 details failed, 0 portals not ok, 0 contract drift warnings. When the run collects nothing (no bids pushed and every portal unknown or failing), it ends as failed with a Failed: … message. A run aborted gracefully (the aborting event, API abort?gracefully=true) saves both records and reports Stopped (aborted): …. An immediate abort, the platform default, kills the run at once, so neither the records nor the status message are written.

Personal data

By default the Actor outputs no personal data. With includeContacts on, it adds the bid contact (name, phone, email), bid result respondent names and phones, and the prospective bidders list (contact names, phones, masked emails). prospectiveBidders is ignored without includeContacts. Only enable it if you have a legitimate reason and handle the data according to the laws that apply to you.

Pricing

Pay per event, platform usage included:

  • bid-list-item: $0.003 per bid ($3 per 1,000) with list data. Also charged when a bid's detail request failed and its list data is saved instead.
  • bid-detail-item: $0.008 per bid ($8 per 1,000) with details and the requested extras.

Each bid is charged once, by one of the two events; extras (documents, addenda, awards…) are not charged separately. Example: 1,000 bids with details cost about $8. Paid Apify plans get lower per-event prices.

Rate limits and reliability

PlanetBids protects its API with an AWS WAF rate rule per IP. About 1 request per second runs clean; about 5 per second gets the IP challenged within half a minute, and the block lifts 1-2 minutes after traffic stops. The Actor:

  • spaces every request (including extras) by 60 / maxRequestsPerMinute seconds and runs one request at a time;
  • treats a WAF challenge (HTTP 202) as a soft block: pauses wafBackoffSecs, rotates the session, retries the same request, and stops cleanly after maxWafChallenges challenges in a row, keeping everything pushed so far (endReason: wafBlocked);
  • retries other failures 3 times; a bid whose detail keeps failing is saved with list data, detailStatus: failed and the error;
  • never stops on bad data: a record it cannot identify is skipped and counted, any other field degrades to null and is reported in CONTRACT_DRIFT.

Throughput at the default 50 requests per minute: a portal with 1,500 bids lists in about 1 minute; with details, about 30 minutes; each extra adds about the same again. For large jobs, raise maxRequestsPerMinute only together with a rotating proxy.

From expiring contract to new bid: when a cooperative contract is about to expire, agencies that bought through it often run their own solicitation. Find contracts ending soon with expiresWithinDays in the Sourcewell or OMNIA Actor, then catch the new bid here or on Bonfire with a keyword filter.

Limitations

  • Documents are listed, not downloaded (CAPTCHA on the file host).
  • The portal catalog holds the portals found in public web crawls, then verified against the PlanetBids API; it misses portals that were never crawled. Any portal works when given by ID or URL.
  • Some codes have no published labels (award type, bond formats, bid template type), so they are not output.
  • The API is undocumented and can change without notice; CONTRACT_DRIFT and a weekly API contract check exist for that reason.