SAM.gov Scraper – Government Bids & Federal Procurement avatar

SAM.gov Scraper – Government Bids & Federal Procurement

Pricing

$1.50 / 1,000 result items

Go to Apify Store
SAM.gov Scraper – Government Bids & Federal Procurement

SAM.gov Scraper – Government Bids & Federal Procurement

Scrape live US federal contracting opportunities from SAM.gov — solicitations, sources sought and awards — plus wage determinations, CFDA grant/loan programs and organization-only exclusion records, with no API key and no login. NAICS, set-aside, notice type and state filters, contacts, watch mode.

Pricing

$1.50 / 1,000 result items

Rating

0.0

(0)

Developer

Fetch Smith

Fetch Smith

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

28 minutes ago

Last modified

Share

SAM.gov Scraper – US Federal Procurement, Contracts, Bids, Wage Determinations & Grants

Scrape live US federal contracting opportunities from SAM.gov — presolicitations, solicitations, combined synopses, sources sought, special notices and award notices — with no API key, no login, no proxy and no browser. Filter by keyword, NAICS code, set-aside type, notice type, place-of-performance state and issuing organization, and optionally enrich every row with the contracting officer's contact details, NAICS codes, set-aside and place of performance.

In short: a federal RFP data API and an organization-only Excluded Parties List check in one keyless Actor — the same run lists open solicitations and tells you whether a firm is debarred.

What it does

  • Six public SAM.gov datasets, one Actor, no key. dataType picks which one: opportunities (default — solicitations, presolicitations, sources sought, awards), one of three Department of Labor wage-determination sets SAM.gov publishes — wage-determinations-dbra (Davis-Bacon Act, construction), wage-determinations-sca (Service Contract Act, services) and wage-determinations-cba (collective bargaining agreements) — assistance-listings, the Catalog of Federal Domestic Assistance (CFDA) grant/loan/direct-payment programs, or exclusions, the federal debarment/suspension list (organizations only — see below). All six come off the same keyless public search backend, so none of them needs a registered API key.

  • Calls the same backend that powers sam.gov's own public opportunity search page, so results match what you see on the site. SAM.gov's official developer API (api.sam.gov/opportunities/v2) requires a free registered API key — this Actor needs none. You do not have to register with GSA, wait for key approval, or rotate a key across a team.

  • enrichDetail joins each row with the per-opportunity record, which is where the fields a bidder actually qualifies on live: naicsCodes, setAside, placeOfPerformanceState/placeOfPerformanceCountry, and pointOfContact (the contracting officer's name, email and phone, primary and secondary). None of these are on the search row. Off by default because it costs one extra HTTP call per row; turn it on when you are qualifying, not just listing.

  • Multi-value filters really OR. naicsCodes: ["541511", "541512"] returns the union of both, not just the first. This is worth stating because SAM.gov's backend silently accepts a repeated query parameter and then honours only the first value — verified live: naics=541511 → 607 hits, naics=541512 → 312, repeated-key form → 607 (wrong, and no error), comma-joined form → exactly 919. This Actor sends the comma-joined form for every multi-value filter (naicsCodes, setAsideTypes, noticeTypes, states), so a two-code search does not quietly drop half your pipeline.

  • noticeTypes uses SAM's own notice-type codes — p presolicitation, o solicitation, k combined synopsis/solicitation, r sources sought, a award notice, s special notice, g sale of surplus, i intent to bundle, u justification. Every row also comes back with both the raw noticeTypeCode and the human-readable noticeType. Four more codes exist in SAM.gov's historical data but are no longer issued and don't appear in SAM's own current UI dropdown — m modification/amendment/cancel, f foreign government standard, j justification and approval (J&A), l fair opportunity/limited sources justification (all retired 2019-2020, ~97k rows fleet-wide, live-verified cycle 835). Useful for historical research; leave them out for a current-solicitations pipeline.

  • setAsideTypes takes SAM.gov's own set-aside codes, and this Actor fixes the case for you. The full vocabulary, each value live-verified non-zero against the opportunity index on 2026-09-30: SBA total small business, SBP partial small business, 8A 8(a) competed, 8AN 8(a) sole source, HZC HUBZone competed, HZS HUBZone sole source, SDVOSBC service-disabled veteran-owned competed, SDVOSBS SDVOSB sole source, WOSB women-owned, WOSBSS WOSB sole source, EDWOSB economically-disadvantaged WOSB, EDWOSBSS EDWOSB sole source, LAS local area set-aside, IEE Indian economic enterprise, ISBEE Indian small business economic enterprise, BICiv Buy Indian, VSA veteran-owned competed, VSS veteran-owned sole source. SAM.gov's backend matches these case-sensitively and fails closed, so before this was handled setAsideTypes: ["sba"] returned zero rows on the largest set-aside category in the index (1.2M opportunities) with no error to tell you why — measured live: SBA → 1,204,971 hits, sba → 0. This Actor now canonicalises the case, so sba, SBA and Sba are the same query. Note that upstream is not uniformly uppercase — BICiv really is mixed-case (BICiv → 4,498 hits, BICIV → 0), which is why this is a code lookup and not a blanket upper-casing. The umbrella names buyers actually say — 8(a), SDVOSB, HUBZone — are accepted too and expand to the real code(s) they cover (SDVOSB → SDVOSBC + SDVOSBS, since SAM.gov splits competed from sole-source and "SDVOSB" means either). Any value that is not a code or an alias is still sent as-is, which is safe — SAM.gov fails closed on it, so it matches zero rows rather than silently widening your search to the unfiltered index — and the run logs a warning naming the value and listing the valid codes.

    Re-audited both directions on 2026-10-10, which is how the list above got three values it was missing. Every prior pass only checked our codes against SAM.gov (all 18 still return rows, nothing dead, counts up only by natural growth: SBA 1,204,971 → 1,206,126). The reverse direction — what SAM.gov accepts that we never listed — had never been run, because SAM.gov publishes no set-aside reference endpoint to read (re-confirmed: no facets/aggregations on the search response, locationservices/v1/api/setasidetypes 500s, every other guessable path 404s). So it was derived empirically instead: 1,500 live opportunity rows sampled across the index for the set-aside code each row carries itself, plus a brute-force probe of the entire 1- and 2-character code space (1,332 values, of which only 8A is real — so that space is now closed). Three real, filterable codes turned up, all of them previously reported to you as typos:

    • setAsideTypes: ["NONE"] — SAM.gov's explicit unrestricted / no set-aside tag. 38,997 opportunities, 3,349 of them active, newest modified the day of the audit, so this one is live and useful. Note what it does and does not mean: it narrows your search to opportunities SAM.gov tagged NONE outright, and is not the same as leaving setAsideTypes empty — the millions of unrestricted opportunities that carry no set-aside field at all are not in it. The run logs that distinction when you use it.
    • setAsideTypes: ["SDB"] (Total Small Disadvantaged Business, 464 rows, newest modified 2019-06-27) and setAsideTypes: ["ESB"] (Emerging Small Business, 714 rows, newest 2020-01-20) — retired programs with zero active opportunities, the same historical-only class as the legacy m/f/j/l notice types below. Nothing has posted under either since 2020, so they are for research, not for a bid pipeline; they are supported because those rows are otherwise unreachable through this filter. The run logs a note when you use them.
  • states filters on place of performance, not the issuing office. SAM's official API calls this state; on this backend that parameter name is silently ignored and returns zero rows, a trap this Actor sidesteps by sending pop_state.

  • activeOnly (default on) restricts to opportunities still open for response. Turn it off for historical and award research.

  • Pay per result: charged only for rows actually returned, with no Actor-start fee — a search that matches nothing costs nothing.

  • watchLabel — only what's new since your last run. Name a saved search and every run after the first returns just the opportunities not already delivered under that label and filter combination. The first run for a label is a free baseline (0 results, 0 charged); it records what already matches in a key-value store on your own Apify account, keyed by the label plus a fingerprint of your other filters, so editing a filter starts a fresh baseline instead of dumping every previously-excluded opportunity as "new". Built for a daily/weekly scheduled run.

  • description is the full solicitation text, not a truncated snippet — the same original HTML SAM.gov itself stores, which can run to several thousand characters on a detailed notice.

  • includeAttachments lists each notice's files — drawings, full statements of work, forms — with a direct, no-login download URL for each. One extra HTTP call per row, off by default. Every link is SAM.gov's own stable file-download path, not a short-lived signed URL, so it works whenever you actually click it, not just at scrape time. Export-controlled and sign-in-required attachments are excluded from the list — this Actor never hands you a link that 403s or bounces to a SAM.gov login, so every URL you get back actually works with no account. A notice with genuinely no files returns attachments: []; a failed lookup returns null and is reported in RUN_SUMMARY, so the two are never confused.

  • watchChanges — also catch a deadline extension, a lifecycle transition, or an award landing. Add this to watchLabel and an opportunity you already have gets re-delivered (at the normal per-row price, tagged _watchChangeType/_watchPrevious) if its isActive flag, noticeTypeCode (a presolicitation turning into a solicitation, or a solicitation turning into an award), responseDate (deadline moved), modifiedDate, modificationsCount or awardeeName (an award landing) has changed since you last saw it — not just brand-new opportunities. Off by default so existing watches keep their current behaviour. Don't combine it with activeOnly (on by default!) or noticeTypes — see the FAQ "don't filter on the field you're watching".

Wage determinations

Set dataType to one of the three wage-determination options and the same filters you already know (keyword, states, activeOnly, maxResults, watchLabel, watchChanges, webhookUrl) apply to Department of Labor determinations instead of solicitations.

dataTypeWhat it returnsLive record count
wage-determinations-dbraDavis-Bacon Act determinations — construction, with constructionTypes (Building / Heavy / Highway / Residential)~85,400 (~4,200 active)
wage-determinations-scaService Contract Act determinations — services, with a services[] list of covered categories~2,700 (~1,500 active)
wage-determinations-cbaCollective bargaining agreement determinations~107,600 (~10,100 active)
  • Coverage is normalized across all three. SAM.gov returns the covered geography in three different shapes (DBRA nests a single location.state, CBA an array of location.states, SCA an array whose counties split into include/exclude lists). Every row here carries the same flat coverage array of { stateCode, stateName, isStateWide, counties, excludedCounties }, plus stateCodes and countyCount for filtering. SCA's excluded counties are kept in their own field rather than merged into the covered list — an excluded county is the opposite of a covered one.
  • Dates are normalized too. publishDate comes back as an ISO string on CBA rows but as epoch milliseconds on DBRA/SCA rows; this Actor emits ISO 8601 for every row so you are not parsing two formats.
  • states filters on the state the determination covers, and multiple states OR together the same way: measured live, AL → 3,509 and TX → 6,909 CBA determinations, ["AL","TX"] → 10,415 (the 3 determinations covering both states are returned once, not twice).
  • activeOnly means "currently in force" — a determination superseded by a later revision has isActive: false. Combine with watchLabel + watchChanges and a run tells you when a determination you track is revised (revisionNumber moves) or goes inactive.
  • keyword searches the reference number, not trades. On these indices q matches the determination's own number (e.g. AK20260001), so q=roofing returns zero against 85,000+ live Davis-Bacon records. Filter by state and construction/service type instead, and leave keyword empty to get the whole set.
  • What this does NOT include: per-occupation hourly wage rate tables. SAM.gov does not publish the rate schedule on any of the three search indices, so every row has wageRates: null. This Actor gives you the determination index — which determination applies to which state and counties, its revision number, its construction/service scope and whether it is current — which is what you need to pick the right determination; read the rates themselves from the determination's own page on sam.gov.
  • naicsCodes, setAsideTypes, noticeTypes, organizationId, enrichDetail and includeAttachments are opportunity-only. If you set one in a wage-determination run it is ignored and the run logs a warning saying so, rather than silently returning an unfiltered set that looks filtered.

Example wage-determination input

{
"dataType": "wage-determinations-dbra",
"states": ["TX", "NM"],
"activeOnly": true,
"maxResults": 500
}

Sample wage-determination output row

{
"wageDeterminationId": "AK20260001",
"referenceNumber": "AK20260001",
"shortReferenceNumber": "AK1",
"title": "AK20260001",
"actCode": "DBA",
"actName": "Davis-Bacon Act",
"recordType": "wdDBRA",
"isActive": true,
"isStandard": true,
"revisionNumber": 2,
"year": 2026,
"publishDate": "2026-09-17T04:00:00.000Z",
"modifiedDate": "2026-09-17T00:00:00-04:00",
"constructionTypes": ["Building", "Heavy"],
"services": null,
"coverage": [
{
"stateCode": "AK",
"stateName": "Alaska",
"isStateWide": null,
"counties": ["Anchorage", "Matanuska-Susitna", "Fairbanks North Star", "Juneau"],
"excludedCounties": []
}
],
"stateCodes": ["AK"],
"countyCount": 28,
"wageRates": null
}

Assistance listings (CFDA)

Set dataType to assistance-listings to pull the Catalog of Federal Domestic Assistance — ~7,400 federal grant/loan/direct-payment programs (~2,900 currently active), each with its objective, eligibility rules, funding-obligation history, related programs and the agency's own published program contact.

  • Supports keyword, organizationId, activeOnly, maxResults, watchLabel, watchChanges, webhookUrl. naicsCodes, setAsideTypes, noticeTypes and states are opportunity-only and are ignored (with a log warning) here — assistance-listing programs are nationwide, not filtered by place of performance. enrichDetail and includeAttachments are also ignored: the search row already carries the full record, and CFDA programs have no notice attachments.
  • keyword matches title, objective and program number (e.g. q=flood → 60 of 7,392 programs), not a reference-number-only match like the wage-determination indices.
  • programNumber (e.g. "12.103") is the CFDA number buyers actually search by — the natural reference for cross-checking against grants.gov or an agency's own NOFO.
  • obligations is shipped as SAM.gov's own raw per-assistance-type funding history ({ assistanceType, values: [{ year, flag }], additionalInfo }) rather than normalized into a single amount field — the sampled records carry only a flag (e.g. "ena" = estimate not available) per year, not a consistent numeric amount, so a normalized field would either be frequently null or silently wrong.
  • contacts is the agency's own published program contact (name/title/phone/address) from the public listing, the same disclosure class as opportunities' pointOfContact.
  • watchChanges on assistance listings re-delivers a program if its active or funded status, modified date, or historical-index entry count has changed since you last saw it — there is no revision number or response deadline on this dataset, so funded/active status is the closest signal to "this program moved."

Example assistance-listings input

{
"dataType": "assistance-listings",
"keyword": "broadband",
"activeOnly": true,
"maxResults": 100
}

Sample assistance-listings output row

{
"assistanceListingId": "8d745b5ad52a421dbf9483c7451adec1",
"programNumber": "12.002",
"title": "Procurement Technical Assistance For Business Firms",
"alternativeNames": ["APEX Accelerator Program/Procurement Technical Assistance Program (PTAP))"],
"objective": "Building a strong and sustainable U.S. supply chain and supporting a wide range of diverse businesses by providing procurement assistance to businesses...",
"isActive": true,
"isFunded": true,
"isLatest": true,
"publishDate": "2026-01-16T00:02:55-05:00",
"modifiedDate": "2026-01-16T00:02:55-05:00",
"department": "DEPT OF DEFENSE",
"agency": "WASHINGTON HEADQUARTERS SERVICES (WHS)",
"assistanceTypes": [["Financial", "Cooperative Agreement"]],
"eligibleApplicants": ["Nonprofit Organization", "Tribal", "..."],
"eligibleApplicantsNote": "Eligible applicants. Only those entities listed in this section are eligible to apply...",
"eligibleBeneficiaries": ["Anyone/general public", "State", "Local"],
"eligibleBeneficiariesNote": null,
"obligations": [{ "assistanceType": { "code": "F001", "value": "Grant" }, "values": [{ "flag": "ena", "year": 2025 }], "additionalInfo": null }],
"contacts": [{ "name": null, "title": null, "phone": null, "address": "Commander, U.S. Army Corps of Engineers, Attn: CECW-OE, Washington, DC 20314-1000." }],
"relatedPrograms": ["12.104", "12.105"],
"website": "http://www.usace.army.mil/business.html.",
"historicalIndexCount": 6,
"sourceUrl": "https://sam.gov/fal/8d745b5ad52a421dbf9483c7451adec1/view"
}

Exclusions

Set dataType to exclusions to pull SAM.gov's federal debarment/suspension list — entities barred from receiving federal contracts, grants or other assistance — restricted to organizations only (firms, vessels and special entity designations, ~35,200 records).

  • This Actor never returns the individual-person exclusion records SAM.gov also publishes. SAM.gov's exclusions index carries 168,673 records total, and 79% of them (133,478) name a private person with a home city, state and zip — not a company. Turning that into a bulk-downloadable dataset would be a people-search product, which this Actor deliberately does not offer: the classification filter that separates organizations from individuals is hard-coded into every request this Actor makes, with no input anywhere that can widen it. If you need to check whether a specific named individual is excluded, look them up one at a time on sam.gov/search directly — SAM.gov's own public exclusions checker is exactly built for that single-lookup use case.
  • Supports keyword (matches the excluded entity's name), organizationId, maxResults, watchLabel, watchChanges, webhookUrl. naicsCodes, setAsideTypes, noticeTypes and states are opportunity-only and are ignored (with a log warning) here. activeOnly has no effect on this dataset — SAM.gov's exclusions index does not support server-side active-status filtering, so every matching record is returned regardless of the setting; check each row's own isActive/terminationDate if you need to filter locally. enrichDetail and includeAttachments are also ignored: the search row already carries the full record, and exclusion records have no notice attachments.
  • Rows SAM.gov itself flags "do not display" are dropped before you ever see them, regardless of classification — a small number of exclusion records carry SAM.gov's own noPublicDisplayFlag, and this Actor honors it the same way sam.gov's own public search does.
  • watchChanges on exclusions re-delivers a record if its active status or termination date has changed since you last saw it — the two signals that mean a debarment was lifted.

Example exclusions input

{
"dataType": "exclusions",
"keyword": "construction",
"maxResults": 100
}

Sample exclusions output row

{
"exclusionId": "4550ad9c-4b01-4e3d-bc94-716ee807836e",
"title": "CHOSUN INTERNATIONAL CHEMICALS JOINT OPERATION COMPANY",
"classificationCode": "Special Entity Designation",
"ueiSam": "NTRNRHCG7L45",
"cageCode": null,
"samNumber": null,
"addressCity": null,
"addressState": null,
"addressCountry": "USA",
"addressZip": null,
"exclusionTypeCode": "PR",
"exclusionType": "Prohibition/Restriction",
"exclusionProgram": "Reciprocal",
"excludingAgency": "OFAC",
"excludingAgencyDesc": "OFFICE OF FOREIGN ASSETS CONTROL",
"department": "TREASURY, DEPARTMENT OF THE",
"agency": "DEPARTMENTAL OFFICES",
"office": "OFFICE OF FOREIGN ASSETS CONTROL",
"isActive": true,
"activationDate": null,
"terminationDate": null,
"isFascsaOrder": false,
"sourceUrl": "https://sam.gov/exclusion/4550ad9c-4b01-4e3d-bc94-716ee807836e/view"
}

Use cases

  • GovCon bid pipelines — pull every active solicitation in your NAICS codes and set-aside category (naicsCodes + setAsideTypes + noticeTypes: ["o", "k"]) into a CRM, already qualified by place of performance.
  • Small-business / 8(a) / SDVOSB capture — filter to the set-asides you actually hold and stop reading opportunities you are not eligible for: setAsideTypes: ["8(a)"], ["SDVOSB"] or ["HUBZone"] work as written, as do the underlying codes (8A, SDVOSBC, HZC, …).
  • Contracting-officer outreach on sources-sought notices — noticeTypes: ["r"] plus enrichDetail gives you the pre-RFP notices where a vendor can still shape the requirement, together with the officer's published contact details.
  • Competitive award research — activeOnly: false with noticeTypes: ["a"] returns award notices including awardeeName and awardeeUeiSAM, so you can see who is winning in your NAICS.
  • Agency- or state-specific monitoring — organizationId for one department/agency, or states for the geographies your team can actually staff.
  • Daily cron alerts — watchLabel on a narrow keyword/NAICS search on a schedule returns only the handful of new notices, instead of refreshing sam.gov by hand or re-paying for the whole result set every run.
  • Davis-Bacon compliance for construction bids — dataType: "wage-determinations-dbra" with the states you build in tells you which determination covers each county and whether it is the current revision, so a bid is priced against a determination that is actually in force.
  • Service Contract Act scoping — dataType: "wage-determinations-sca" returns the service categories each determination covers, so you can map a services solicitation to the right determination before pricing labour.
  • Wage-determination revision alerts — watchLabel + watchChanges on a state-filtered wage-determination search re-delivers a determination only when its revisionNumber, active status or modified date moves — the signal that an in-flight bid or a running contract needs repricing.
  • Deadline-extension / lifecycle alerts — watchLabel + watchChanges flags a presolicitation turning into a solicitation, a deadline extension, or an award landing on a solicitation you're already tracking.
  • Grant-eligibility screening — dataType: "assistance-listings" with a keyword returns each matching program's eligibleApplicants/eligibleBeneficiaries and objective, so a grant writer can shortlist which CFDA programs a client actually qualifies for before drafting anything.
  • New/defunded grant program alerts — watchLabel + watchChanges on assistance-listings flags a program going active, funded, or unfunded since your last check.

Example input

{
"keyword": "solar",
"naicsCodes": ["221122"],
"maxResults": 15,
"enrichDetail": true
}

Input

FieldTypeDescription
dataTypestringWhich SAM.gov dataset: opportunities (default), wage-determinations-dbra, wage-determinations-sca, wage-determinations-cba, assistance-listings
keywordstringFull-text search across the opportunity index (default contract). On wage-determination types it matches the determination's reference number; on assistance-listings it matches title/objective/program number — leave empty for all
naicsCodesarrayNAICS codes, e.g. ["541511", "541512"] — multiple codes are ORed. Opportunities only
setAsideTypesarraySet-aside codes, e.g. ["SBA"] — case-insensitive, multiple values are ORed. Opportunities only. Full code list below
noticeTypesarrayNotice-type codes p/o/k/r/a/s/g/i/u (current) plus m/f/j/l (legacy, retired 2019-2020) — multiple values are ORed. Opportunities only
statesarrayTwo-letter state codes, e.g. ["TX", "CA"] — ORed. Place of performance for opportunities; covered state for wage determinations; not supported for assistance-listings
organizationIdstringRestrict to one issuing department/agency/office by SAM organization id. Opportunities and assistance-listings only
activeOnlybooleanOnly opportunities still open for response — for wage determinations, only determinations currently in force; for assistance-listings, only currently-active programs (default true)
enrichDetailbooleanJoin each row with NAICS / set-aside / place of performance / contacts (default false). Opportunities only
includeAttachmentsbooleanList each notice's attachments — name, size, MIME type, direct no-login download URL (default false). Opportunities only
maxResultsintegerCap on rows returned (default 200)
watchLabelstringOptional. Name a saved search to get only records new since your last run under that label — see FAQ
watchChangesbooleanOptional, requires watchLabel. Also re-deliver an already-seen record if a watched field changed — for opportunities: isActive, noticeTypeCode, responseDate, modifiedDate, modificationsCount, awardeeName or description; for wage determinations: revisionNumber, isActive or modifiedDate; for assistance-listings: isActive, isFunded, modifiedDate or historicalIndexCount (default false) — see FAQ
webhookUrlstringOptional. POST a small JSON completion summary (opportunities pushed, rows scanned, dataset ID, watch new/changed/skipped counts) here when the run finishes — see FAQ

Sample output row

{
"opportunityId": "c8092b56b2c14be9bea3ac6081207963",
"title": "This is a sources sought to identify contractors who possess the capabilities to provide CFE and associated EACs produced using domestically-manufactured solar panel systems.",
"solicitationNumber": "47PA0723SS0001",
"noticeTypeCode": "r",
"noticeType": "Sources Sought",
"isActive": true,
"isCanceled": false,
"publishDate": "2023-07-12T19:23:54+00:00",
"modifiedDate": "2023-07-12T19:23:54+00:00",
"responseDate": "2023-06-27T20:00:00+00:00",
"responseDateActual": "2023-06-27T16:00:00-04:00",
"responseTimeZone": "America/New_York",
"department": "GENERAL SERVICES ADMINISTRATION",
"agency": "PUBLIC BUILDINGS SERVICE",
"office": "PBS R00 CPF CLEAN ENERGY",
"description": "<p><strong>THIS IS A SOURCES SOUGHT ANNOUNCEMENT ONLY - </strong>A solicitation is not available at this time...",
"awardeeName": null,
"awardeeUeiSAM": null,
"modificationsCount": 0,
"sourceUrl": "https://sam.gov/opp/c8092b56b2c14be9bea3ac6081207963/view",
"naicsCodes": ["221122"],
"setAside": null,
"placeOfPerformanceState": null,
"placeOfPerformanceCountry": "USA",
"pointOfContact": [
{ "name": "Bonnie Bueter", "email": "bonnie.bueter@gsa.gov", "phone": "202-227-1635", "type": "primary" }
],
"attachments": [
{
"name": "Domestic Solar Sources Sought.pdf",
"mimeType": ".pdf",
"sizeBytes": 66900,
"postedDate": "2023-05-23T17:41:41.033+00:00",
"downloadUrl": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/127fca9028ef46ebb6f4f57863fe12e7/download"
}
]
}

Pricing

One event, no Actor-start fee, same flat $0.0015 per row across all four dataTypes (opportunities, wage determinations, assistance listings/CFDA, exclusions).

Verified live 2026-10-01 against every live SAM.gov-niche listing on the Store with real traction — re-enumerated this cycle via a fresh Store search rather than re-checking only the rivals already named (the prior 2026-09-30 pass used a narrower search term and missed the niche's two biggest listings by user count). jungle_synthesizer/samgov-scraper (171 users) is the Store's actual user-count leader here, not scrapebench — and it ships the same four-dataset scope as this Actor (opportunities, exclusions, wage determinations, assistance listings), so the "unlike this Actor's 4-dataset scope" framing below applies only to the smaller rivals, not to it. It tiers $0.001/row (FREE/BRONZE) down to $0.0008 (GOLD+) plus a $0.0001 Actor-start fee — cheaper than our flat $0.0015 at every tier. scrapesage/sam-gov-scraper (43 users, 24 in the last 30 days — the niche's busiest by recent activity) is opportunities-only: $0.0025/row on FREE tapering to $0.00063 on DIAMOND, undercutting us above the SILVER tier, and it also ships a PSC-code filter we lack. Both rivals, like this Actor (includeAttachments, added cycle 1133), offer an attachment-download feature — no longer a gap here, though their exact implementation hasn't been diffed against ours field-for-field. fortuitous_pirate/sam-gov-scraper (116 users) is opportunities-only at a flat $0.003/row plus a $0.01 Actor-start fee — pricier than us at every tier. magicfingers/sam-gov-scraper (43 users) is genuinely FREE — no pricing record at all. Of the previously-named rivals: scrapebench/samgov-opportunity-alert (29 users) still charges a flat $0.0025/opportunity, no start fee; bovi/sam-gov-opportunities-scraper (verified live 2026-10-05) still tiers $0.0025 down to $0.002375 plus a $0.00005 start fee and still requires the buyer's own SAM.gov API key, which this Actor does not; publicmoney/sam-gov-opportunity-scraper still tapers to $0.0007/tender on DIAMOND (plus its own bizarre $0.5–$1 "schema.org block" event we don't charge at all); maydit/sam-gov-opportunities-scraper still tapers to $0.0012 on GOLD and above. agentready ($0.0019+start), practicalmodules ($0.0025 flat) and two more newly-priced listings, pink_comic/sam-gov-contract-opportunities (30 users, $0.002/row + $0.0001 start) and omarchydev/government-contract-monitor (33 users, a bundled AI-analysis product billing $0.02/contract plus per-feature add-on events, not a comparable per-row price), all price above us. We are not the cheapest in this niche — jungle_synthesizer and scrapesage both undercut us on volume, and publicmoney/maydit undercut us once a buyer reaches their top tier. Our case is covering all four datasets with no API key, no start fee, and the date-window/watch-mode features below — not being the single cheapest listing.

Verified live 2026-10-02, re-swept with the broader sam.gov term (the fleet's post-1124 lesson that a narrow search term silently caps a niche audit, applied here too) rather than re-checking only the rivals already named above — 18 listings with real traction, surfacing 6 rival Actors never priced in this file before. Three are genuine undercutters: automation-lab/samgov-government-contracts-scraper stacks a $0.005 Actor-start fee on a tiered per-row rate from $0.000115 (FREE) down to $0.000028 (DIAMOND) — the start fee amortizes by about row 4 at every tier, after which it undercuts our flat $0.0015/row for the rest of the run. automation-lab/sam-gov-entity-exclusions-scraper is the same $0.005-start-plus-tiered-item shape ($0.0000381 FREE down to $0.00001 DIAMOND), scoped to the exclusions dataset only — same ~row-4 crossover, but it covers one of our four dataTypes, not all four. alizarin_refrigerator-owner/sam-gov-contracts---federal-opportunities-search prices its dataset item at just $0.00001/row, but that sits behind a $0.10 Actor-start fee plus a $0.01 per-search-type event (one of six: opportunity/NAICS/agency/set-aside/award/solicitation search) — at least $0.11 charged before a single row is counted, so it only overtakes our flat rate above roughly 74 rows per run; we are cheaper on every smaller run, which covers the common keyword-filtered pull. Five more price above us at every volume and are named for completeness, not as a threat: taroyamada/procurement-intel-actor (20 users, $0.008/row), inexhaustible_glass/federal-contractor-intelligence ($0.01 start + $0.005/row), cblu/sam-gov-contract-opportunities-scraper ($0.004/row flat), signalcrawl/sam-gov-contract-monitor ($0.00005 start + $0.002/row) and shipsatnight/sam-gov-contract-scraper ($0.00005 start + $0.002/row). upward_enterprises/sam-gov-contract-radar ties us at its FREE tier ($0.002/row) and undercuts us from GOLD+ ($0.0012, then $0.0006 on its second tiered event) — a real rival rate, but a 3-user listing moves nothing yet. None of the 9 widens the "we are not the cheapest" admission above; jungle_synthesizer and scrapesage remain the two rivals that beat us on volume at every tier, and automation-lab's two listings now join them above row 4.

Verified live 2026-10-03, re-swept sam.gov with the Store search limit raised from the default 20 to 60 — 54 listings came back instead of 18, almost entirely 2-user micro-listings (relevance ranking had been cutting the sweep off before reaching them). All 13 previously-named rivals re-verified live straight from pricingInfos, zero price drift on any of them. One filed-but-not-yet-effective change found: fortuitous_pirate/sam-gov-scraper's Actor-start fee drops from $0.01 to $0.005 on 2026-10-13 (its per-row $0.003 is unchanged); even after the cut it stays pricier than us at every tier, so no competitive-position change — re-read on/after that date rather than treating it as new. Three genuine new undercutters disclosed from the widened sweep, all 2-user listings: yourwingman/usa-federal-contracts-scraper charges a flat $0.0005/row plus a $0.00005 start fee — a third of our rate at every volume, the largest undercut found in this niche after jungle_synthesizer/scrapesage. factpipe/sam-gov-contracts tiers $0.002 (FREE) down to $0.0014 (GOLD and above) with no start fee, undercutting us from GOLD+. bakos_bence/sam-gov-opportunities tiers its per-row rate lower still ($0.00249 down to $0.001245 GOLD+) but stacks a $0.02 (FREE/BRONZE) to $0.003 (GOLD+) Actor-start fee, so it only overtakes our flat rate past roughly 12 rows/run on GOLD and above — dearer below that and on lower tiers. Two more tie our rate exactly rather than undercutting it: adobeflex/sam-opportunities-lite ($0.0015/row primary event, plus a separate $0.001 "search run" event and a $0.00005 start fee that make it dearer in practice) and andrew_avina/federal-contracts-mcp (flat $0.0015/row, no other fees — a genuine exact tie). Deliberately left unpriced as out of this Actor's scope, not an oversight: wage-determination-only (wishbone_data/davis-bacon-wage-determinations), exclusions-only (nexgendata/sam-gov-federal-contractor-exclusions, maximedupre/sam-gov-exclusions), contractor lead-gen/registration monitoring (lead.gen.labs's three listings), a bundled amendment-detection product (blaidlink/sam-opportunity-fit-amendment-monitor, $0.02-$0.03/event), and multi-country tender aggregators that merely mention SAM.gov alongside EU TED/UK listings (practicalmodules, gazidev/global-tender-alerts, chorelet/government-tenders-scraper, snow_leo_data/government-tenders-scraper, apeye/government-tenders-api) — none read all four of this Actor's dataTypes as a SAM.gov-specific product. Updated bottom line: jungle_synthesizer, scrapesage and now yourwingman undercut us at every tier; publicmoney/maydit/upward_enterprises/factpipe/bakos_bence undercut us only from their upper tiers or past a row-count crossover. We remain not the cheapest in this niche at any realistic volume — the case is four-dataset coverage, no API key and no start fee, not price leadership.

Verified live 2026-10-03 (second pass, 15-term sweep instead of one search term) — the prior passes all searched the single phrase sam.gov, which caps the sweep at whatever that one query ranks. This pass swept 15 hand-curated terms covering SAM.gov's own names for the four domains this Actor's dataType reads (contract opportunities, wage determinations, assistance listings, entity exclusions), the portal's dead predecessor name (FBO.gov), and the buyer-side words (RFP, solicitation, set-aside/NAICS, bid alerts): 484 distinct listings seen, 137 mentioning SAM.gov or one of those four domains (97 if only names/titles are counted), against the 54 the one-term pass saw. 105 of the 137 were never priced in this file before — nearly all are 2-user micro-listings, and the 14 with the most traction or the most head-on scope were all priced live from pricingInfos.

  • One genuinely free rival, and it is the biggest listing this file had never named: martc03/gov-contracts-mcp has no pricing record at all — public, not deprecated, confirmed three times live. On Apify's free model that is $0/row, cheaper than anything anyone can charge, so it is the cheapest listing in this niche by definition. It is packaged as an MCP server for contracts and procurement rather than a dataset scraper, and its zero 30-day users suggest it is not actually being used, but on price alone there is nothing to beat.
  • One marginal undercutter: ahmed_jasarevic/sam-scraper advertises "Only $1.5/1K" in its own title and lives up to it — tiered $0.0015/row (FREE) to $0.00147 (GOLD and above), so it ties our flat rate on the lower tiers and undercuts it by 2% on the upper ones. It also charges a $0.0005 Actor-start fee, which we do not, so on GOLD+ it only actually costs less past roughly 17 rows per run; below that we are cheaper, and on FREE/BRONZE/SILVER we are cheaper at every volume.
  • Twelve more price above us, named for completeness: technicaldost/government-bid-tracker ($0.005/result + $0.00005 start), parseforge/government-contract-awards-scraper ($0.01599 → $0.01199 + $0.005 start, and award-scoped rather than opportunity-scoped), fascinating_lentil/global-government-contracts-aggregator ($0.002/contract + $0.00005 start, UK/EU/US bundle), parseforge/us-gov-contract-watch-scraper ($0.0075 → $0.006675/result plus a separate $0.005 → $0.00445 event for the SAM.gov attachment/detail lookup that our includeAttachments does not charge for), lowlanddata/us-rfp-monitor ($0.003 → $0.0024 per baseline row but $0.02 → $0.016 per new-RFP alert + $0.0005 start), kantolabs/sam-gov-contract-opportunities ($0.003/opportunity + $0.00005 start), labrat011/gov-contracts-scraper ($0.005/result + $0.00005 start today, start fee rising to $0.005 on 2026-10-10), georgy.malanichev/govtender-scraper ($0.003/result behind a $0.50 Actor-start fee, the largest start fee seen in this niche), mooseandraven/samgov-federal-contracting-suite ($0.004/opportunity + $0.003/exclusion + $0.005/batch-screen + $0.05/monitor-run — its "No Start Fee" title claim is true, but it is 2.7x our rate and covers two of our four datasets), splendorous_astrolabe_xs9/govcon-monitor ($0.003/record flat, no start fee), viralanalyzer/sam-gov-contracts-watcher ($0.01 FREE tapering to $0.003 DIAMOND — still 2x us at its cheapest tier) and thoob/sam-opportunities-feed ($0.01/opportunity flat).
  • A note on the watch-mode rivals specifically, since that is this Actor's main non-price feature: lowlanddata charges 6.7x its own baseline row rate for an alert row, and parseforge/us-gov-contract-watch-scraper bills attachments as a second event. This Actor charges the same $0.0015 for a watchChanges re-delivery as for a new row, and nothing extra for includeAttachments.
  • Bottom line unchanged in substance, with one addition: jungle_synthesizer, scrapesage and yourwingman still undercut us at every tier, publicmoney/maydit/upward_enterprises/factpipe/bakos_bence/ahmed_jasarevic only from their upper tiers or past a row-count crossover, and magicfingers/sam-gov-scraper plus now martc03/gov-contracts-mcp are free. We are not the cheapest listing in this niche and do not claim to be — the case is four-dataset coverage, no SAM.gov API key, no Actor-start fee, and the date-window/watch/attachment features above.

Verified live 2026-10-04 — every listing this file had never named, priced at any user count rather than above a user-count floor. 484 listings seen on the same 15-term sweep, 139 mentioning SAM.gov or one of the four dataType domains, 93 of them not named anywhere above. Only 3 of those 93 had 3+ users and all 3 were non-SAM.gov tender products (artificially/eu-tenders-scraper, fortuitous_pirate/canadabuys-scraper, logiover/global-public-tenders-scraper), so a user-count cut would have priced only non-substitutes; all 93 were live-priced from pricingInfos instead, reading each tiered block explicitly. Our own live price was re-read first: flat $0.0015/row, one result event, no start fee, no tiered block, zero drift against meta.json. Findings:

  • Three new undercutters that beat us at essentially every volume. acid-base/borg-sam-contract-opportunities charges a flat $0.0005/row with no start fee — one third of our rate at every volume, and it makes this Actor's exact pitch (SAM.gov's public Data Services, no login, no API key). It now ties yourwingman/usa-federal-contracts-scraper as the cheapest flat per-row rate found in this niche. bridged/sam-gov-opportunities-api charges a flat $0.001/opportunity with no start fee and no second event at all — the cleanest sub-our-rate listing here, scoped to solicitations/RFPs/sources-sought off SAM.gov's official Get Opportunities API. gochujang/gov-contract-tracker charges $0.001/row plus a $0.001 once-per-run start fee, so it is dearer only on a 1-row run and cheaper from about 3 rows up; it also ships keyword/NAICS/agency/set-aside/date filters comparable to ours.
  • Four more undercut us only from a tier or a row-count crossover. publicrecords/govcon-opportunity-feed tiers $0.002 (FREE) down to $0.0014 from GOLD — cheaper than us on GOLD and above only, dearer on FREE/BRONZE/SILVER, and its new-since-last-run delta-record ($0.02) and incumbent-record ($0.01) events cost far more than our flat $0.0015 for a watchChanges re-delivery. sigma-dev/usa-government-contract-scraper charges $0.001/row behind a $0.05 once-per-run start fee, so it only overtakes our flat rate past roughly 100 rows per run. oswaldocarabano/sam-gov-data-scraper is dearer on notices ($0.0025/notice, 1.67x us) but charges just $0.0005 per exclusion record and per attachment — a genuine 3x undercut on one of our four dataTypes, and the only rival found that prices exclusions separately below our flat rate. jungle_synthesizer/dol-oflc-prevailing-wage-determination-scraper (listed 2026-10-01 — a second listing from the niche's user-count leader) tiers $0.001 down to $0.0008 on wage determinations, under our flat rate at every tier; it reads DOL OFLC prevailing-wage determinations (the H-1B/PERM/H-2B wage floor), not the SCA/DBA wage determinations SAM.gov publishes, so it is a price anchor for wage-data buyers rather than a substitute for our dataType: wageDeterminations.
  • Correction, verified live 2026-10-05: leadharbor/sam-gov-vendor-screening is gone from the Store (404 on its own API record). The 2026-10-04 pass named it as a free exclusions-screening rival; it no longer exists, so it is not a live price comparison and should not be cited as a free alternative.
  • One near-parity rival worth naming: artificially/samgov-opportunities-scraper tiers $0.00225 (FREE) down to $0.001575 from GOLD — dearer than us at every tier, but only by 5% at the top, the closest same-scope price to ours in the niche. It also advertises contracting-officer emails/phones, attachments and a new-notices-only monitor, i.e. our feature set.
  • Ruled out by scope rather than by price, so a later audit does not re-price them: zentrafoundry/govcon-grants-bid-intelligence ($0.02/qualified tender, and its own description says SAM.gov still requires the buyer's API key — it is a TED/grants product), lead.gen.labs's three contractor-registration lead listings (the $0.00001 apify-default-dataset-item on them is vestigial; the real charge is $0.019/profile behind a $0.05 start fee), adobeflex/worldbank-procurement-lite, aicatraz/gov-rfp-aggregator-mcp and rl1987/samgov-mcp (MCP tool-call billing, not per-row), plus the EU/Canada/global tender aggregators above. The remaining ~70 priced listings are dearer than $0.0015/row at every tier and changed nothing.
  • Bottom line, updated: jungle_synthesizer/samgov-scraper, scrapesage, yourwingman, and now acid-base, bridged and gochujang undercut us at every realistic volume; publicmoney/maydit/upward_enterprises/factpipe/bakos_bence/ahmed_jasarevic/publicrecords/sigma-dev only from an upper tier or past a crossover; oswaldocarabano only on exclusions; magicfingers and martc03/gov-contracts-mcp are free (leadharbor, previously named free here, is gone from the Store as of 2026-10-05). We are not the cheapest listing in this niche, at any volume, and do not claim to be — the case is all four dataTypes in one Actor with no SAM.gov API key, no Actor-start fee, the two-sided date window, watch mode and attachment links at no extra charge.

Verified live 2026-10-05 — full-cohort re-sweep, one day after the 2026-10-04 pass above. bin/niche-unnamed found the niche had grown slightly (140 matched vs 139 the day before) with 80 still-unnamed listings; only 1 of the 80 (accountable_eel/sam-gov-opportunity-alerts, 3 users) cleared a 3-user cut, so — per the standing full-cohort rule — all 80 were live-priced from pricingInfos rather than just that one. Our own live price was re-read first and is unchanged: flat $0.0015/row, no start fee. Three genuine new findings, none named anywhere above:

  • One more free rival: artificially/business-data-mcp has no pricing record at all — $0/run. It is a bundled MCP server covering gov contracts, jobs, LinkedIn and leads together, not a SAM.gov-specific scraper, but on price alone nothing beats free.
  • One real per-row undercutter, but dormant: fetch_cat/sam-gov-contract-opportunities-monitor charges a $0.005 once-per-run start fee plus a tiered item price from $0.000115/row (FREE) down to lower tiers — about 13x cheaper than our flat rate once the start fee amortizes around row 4, but it has had no runs in 30 days.
  • One modest undercutter: vhsgreed/us-federal-contracts charges a $0.002 once-per-run start fee plus $0.00125/row (FREE tier, tapering to $0.00095 from GOLD) — about 17% cheaper per row than us, crossing over after roughly 2 rows.
  • The remaining 76 of the 80 confirmed dearer or out of scope — including second_coming/gov-contract-monitor, which bills a flat $0.02 per scan run rather than per row and is not a comparable substitute. No need to re-price them; this line is the record that they were checked at this cycle.
  • Bottom line unchanged in substance: jungle_synthesizer/samgov-scraper, scrapesage, yourwingman, acid-base, bridged and gochujang still undercut us at every realistic volume; the three new findings above join the "free" and "crossover" groups rather than displacing the leaders. We remain not the cheapest listing in this niche, at any volume, and do not claim to be.

Verified live 2026-10-06 — full-cohort re-sweep, one day after the 2026-10-05 pass above. bin/niche-unnamed found the niche had grown again (145 matched vs 140 the day before) with 80 still-unnamed listings (zero cleared a 3-user cut this time), so — per the standing full-cohort rule — all 80 were live-priced from pricingInfos. Our own live price was re-read first and is unchanged: flat $0.0015/row, one result event, no start fee. Result: clean, zero new findings — no free rivals, no undercutters among any of the 80 (every primary-event tier, where tiered, priced at or above $0.0015). Also spot-checked the six headline undercutters named above directly against their live pricingInfos rather than trusting yesterday's record: jungle_synthesizer ($0.001 FREE/BRONZE → $0.0008 GOLD+), scrapesage ($0.0025 FREE → $0.00063 DIAMOND), yourwingman ($0.0005/row + $0.00005 start), acid-base ($0.0005/row flat), bridged ($0.001/row flat) and gochujang ($0.001/row + $0.001 start) — all six unchanged, zero drift. Bottom line stands exactly as above.

Verified live 2026-10-07 — full-cohort re-sweep, one day after the 2026-10-06 pass above. bin/niche-unnamed found the niche flat at 145 matched (same as the day before) with 81 still-unnamed listings (one more than the 80 on 2026-10-06); zero cleared a 3-user cut, so — per the standing full-cohort rule — all 81 were live-priced from pricingInfos, this time via a tier-ladder-aware pricer (the cycle-1350/1356 method: score every tier, not just the FREE-tier headline, and separate one-time Actor-start events from the per-row rate in code). Our own live price was re-read first and is unchanged: flat $0.0015/row, one result event, no start fee.

  • One real undercutter, scoped differently: jtpalms/gov-tenders-monitor tiers $0.001/row (FREE/BRONZE) down to $0.0008 (GOLD+) plus a $0.00005 start fee — under our flat rate at every tier — but it is a four-country tender aggregator (CanadaBuys, UK Find a Tender, EU TED, plus SAM.gov) and its own description says the SAM.gov portion needs "your own key"; this Actor needs none. On price alone it beats us; on the no-key, SAM.gov-only case this Actor targets, it doesn't apply.
  • Two more reach or cross our rate only from an upper tier: steadydata/sam-gov-contract-opportunities tiers $0.002 (FREE) down to $0.0013 (GOLD and above), no start fee, no API key, reading the same GSA daily public extract this Actor does — undercutting us from GOLD+. optimistprime/federal-contract-opportunities-monitor ties our rate exactly on FREE ($0.0015, matching its own "$1.5/1k" headline), undercuts slightly on BRONZE ($0.0014), then drops to $0.0012 from SILVER up.
  • Three ruled out by scope, not price: tagadanar/usaspending-federal-awards reads USAspending.gov award/grant/loan/payment records, not SAM.gov's open-opportunity listings — a different dataset despite advertising "no SAM.gov login, no API key." automation-lab/grants-gov-funding-opportunities-scraper and soilair/grants-gov-api are both Grants.gov tools — this Actor's sibling grants-gov-scraper's niche, not this one.
  • Four more resolved by hand after the pricer flagged them AMBIGUOUS (each pairs an apify-actor-start event with exactly one other recurring event, but neither carries an isPrimaryEvent flag on this API record, so the tool refused to guess which one is the per-row rate rather than mis-pick): waags/sam-gov-contract-opportunities ($0.004 start + $0.00175/row), civic-data-tools/public-bid-search ($0.00005 start + $0.005/bid record), chimerical_quicklime/sam-gov-opportunity-monitor ($0.005 start + $0.01/opportunity, matching its own "$10 per 1,000 alerts" line) and ambolt/sam-gov-opportunities ($0.005 start + $0.002/notice, matching its own "$0.002/notice" title) — all four dearer than us at every volume once hand-read.
  • The remaining 71 of the 81 confirmed dearer or out of scope by the same pricer run; no need to re-price them individually, this line is the record that they were checked this cycle.
  • Bottom line unchanged in substance, with two additions: jungle_synthesizer/samgov-scraper, scrapesage, yourwingman, acid-base, bridged, gochujang and now jtpalms/gov-tenders-monitor (own-key, multi-country caveat above) undercut us at every realistic volume; publicmoney/maydit/upward_enterprises/factpipe/bakos_bence/ahmed_jasarevic/publicrecords/sigma-dev/steadydata/optimistprime undercut only from an upper tier or past a crossover; oswaldocarabano only on exclusions; magicfingers, martc03/gov-contracts-mcp and artificially/business-data-mcp are free. We remain not the cheapest listing in this niche, at any volume, and do not claim to be — the case is all four dataTypes in one Actor with no SAM.gov API key, no Actor-start fee, and the date-window/watch/attachment features above.

Verified live 2026-10-08 — full-cohort re-sweep, one day after the 2026-10-07 pass above. bin/niche-unnamed found the niche had grown again (151 matched vs 145 three days before) with 77 still-unnamed listings (76 of 77 at 2 users or fewer); only the same two 3-user listings already ruled out above (parseforge/sam-gov-wage-determinations-scraper, wage-determinations-only at $0.00445–$0.005/row; pink_comic/federal-grant-awards, USAspending grant-award data not SAM.gov opportunities) cleared a 3-user cut, so — per the standing full-cohort rule — all 77 were live-priced via a tier-ladder-aware pricer, 0 unresolvable, 0 ambiguous. Result: 0 of 77 undercuts us at any tier, 0 free-model rivals, 0 future-dated price changes. One new exact tie: kadi_bence/sam-gov-scraper (2 users) prices its single opportunity event at exactly our $0.0015/row, but stacks a $0.00005 Actor-start fee we don't charge, so it is dearer than us in practice at every volume — the same "ties on the headline rate, loses on the start fee" shape as adobeflex/sam-opportunities-lite and optimistprime/federal-contract-opportunities-monitor above. The other 75 of 77 price dearer or are out of scope (freelancer-jobs-scraper clones, Grants.gov/USAspending tools, OFAC sanctions screening, EU TED aggregators). Bottom line unchanged in substance.

Verified live 2026-10-09 — full-cohort re-sweep (150 matched, 73 unnamed, same thin cohort, max 2 users) plus, for the first time on this niche, an every-event-every-tier scan of every rival's secondary (non-selected) charge events, not just the one headline event each pricer run already picks. The per-row resweep is unchanged in substance: 0 of 73 undercuts us at any tier, 0 free-model rivals, 0 future-dated changes. The secondary-event scan raised 7 raw hits, all false positives or out of scope once read: cleanpull/public-tenders-tracker and neverempty/sam-gov-opportunities-monitor's cheap events are both a monitoring "nothing changed" check (notice-checked, search-checked) that bills once per poll, not once per row — their real primary events (notice-result $0.002, opportunity-returned $0.0025) are dearer than us; george.the.developer/federal-contract-opportunity-monitor's is an unflagged actor-start one-time fee by name, behind a $0.1/row primary event. piotrv1001/sam-gov-tenders-scraper's amendment-history ($0.001) is its own opt-in add-on for pulling a notice's full amendment trail, not the per-row rate (tender, $0.002, is). thisisb3/sam-gov-contracts-scraper's award event ($0.0012–$0.0015) bills USAspending contract-award records, not SAM.gov opportunity notices — the same different-dataset distinction this README already draws for tagadanar/usaspending-federal-awards above; its own opportunity event ($0.002–$0.0016) is the comparable unit and is dearer. lead.gen.labs/sam-gov-active-federal-contractor-leads's cheap event is the platform-default dataset-item charge beside its real named rate, and the Actor itself is GSA contractor-profile data, out of scope regardless. tagadanar/us-grants-monitor is a Grants.gov/NIH tool (this Actor's sibling niche), out of scope on title and description alone. 0 genuine undercutters found this way either.

FAQ

Do I need a SAM.gov API key? No. The official api.sam.gov developer API does require a free registered key, but this Actor uses the unauthenticated backend behind sam.gov's own public search page instead. Nothing to register, nothing to rotate.

Is there a posted-date range filter? Not on this backend — it exposes no postedFrom/postedTo equivalent. Use activeOnly to separate open from closed opportunities, and filter on the publishDate / modifiedDate fields on each row afterwards. (responseDate is the deadline.)

Is description the full notice text? Yes — the full solicitation description as SAM.gov itself stores it (original HTML markup preserved), not a truncated snippet; it can run to several thousand characters on a detailed notice. Attachments (drawings, full statements of work as separate documents) are not part of description — set includeAttachments: true to list them.

How deep can a search go? The backend caps paging at 10,000 rows per query, so a very broad keyword will stop there. Narrow with naicsCodes, noticeTypes or states rather than trying to page past it.

Is pointOfContact personal data? These are government contracting officers' official work contact details, published by the agency itself as a required part of the statutory public notice — the same disclosure class as the contacts on our NIH RePORTER and EU TED Actors. They are returned as SAM.gov publishes them; they are not aggregated across sources, cross-referenced with any other dataset, or resold as a people-lookup product.

How does the price compare? $0.0015 per returned row with no Actor-start fee. The comparable paid SAM.gov Actors on the Store range from about $0.0005 (two 1–2-user listings' flat rate, verified live 2026-10-04) to $0.003 per row — see Pricing above for the full live ranking, including the handful of free listings — and some add an Actor-start fee of $0.00005–$0.50 on top, charge extra for attachments or change alerts, or require your own SAM.gov API key, none of which this Actor does.

Can I download the bid attachments, not just get their links? Set includeAttachments: true — every row then carries an attachments array with each file's name, size, MIME type and a direct, no-login downloadUrl. This Actor does not fetch the file bytes into the dataset itself (a notice can attach a 10+ MB drawing set, and this is a 2 GB box); the URL is SAM.gov's own stable download path, so your own pipeline fetches the actual bytes only for the files it wants, when it wants them, without ever needing a SAM.gov login. Two comparable rivals (jungle_synthesizer/samgov-scraper, scrapesage/sam-gov-scraper) also offer an attachment-download feature; this closes that gap.

How does watchLabel know what's already new, and where is that baseline stored? In a key-value store on your own Apify account, keyed by the label plus a fingerprint of keyword/naicsCodes/setAsideTypes/noticeTypes/states/organizationId/activeOnly. The first run for a label just records every currently-matching opportunity id and returns zero rows (you pay nothing); every run after that returns only ids not already in that record. Changing any of those filters starts a fresh baseline under the same label instead of comparing against the old filter's results.

Does watchChanges cost extra? No extra fee — a changed opportunity is billed at the same $0.0015/row as a new one, so you only pay when there's actually something to see. Plain watchLabel never re-delivers an opportunity it has already sent you, even if the agency later extends the deadline or the notice moves from presolicitation to solicitation to award. Set watchChanges: true and each run also compares every already-delivered opportunity's isActive/noticeTypeCode/responseDate/modifiedDate/modificationsCount/awardeeName (plus an internal fingerprint of description) against what it looked like last time; if anything moved, the row is re-delivered tagged with _watchChangeType (which field(s) changed) and _watchPrevious (their prior values — description's previous value is a fixed note, since only a fingerprint of that text is stored, never the full text). Verified live: seeding a baseline, editing a delivered opportunity's recorded isActive flag and responseDate directly in the stored snapshot, then rerunning returned exactly those 2 rows with the correct change tags and nothing else — and a plain unchanged rerun after that returned 0 rows again.

Don't filter on the field you're watching. watchChanges compares each already-delivered row's watched fields against what they looked like last time — but two of this Actor's own filters are server-side narrowings on fields it also watches, so combining them with watchChanges makes exactly the change you're trying to catch structurally unreportable. activeOnly (on by default) sends SAM.gov is_active=true; isActive is the #1 watched field (the active → inactive/awarded transition, flagged as the single most valuable alert in this niche). The moment a row flips inactive, the filter stops it from matching the query at all — it is never fetched again, so watchChanges is never even asked about it, and the run just reports "nothing new." Live-verified cycle 1567 against a real sam.gov row (naics 221122): present with no filter, absent the instant is_active=true is added. Set activeOnly: false on any watch run where you need that transition — you'll get both active and inactive rows back and can filter on isActive yourself after delivery, or run two labels (one activeOnly: true for new rows, one activeOnly: false with watchChanges for the inactive transition). noticeTypes is the narrower second instance (opportunities only): it sends notice_type, and noticeTypeCode is watched for the presolicitation → solicitation → award lifecycle, so filtering to one type blinds the transition out of that type — leave it empty on a watch run that needs to see lifecycle moves. Both cases log an explicit warning (and, if the run also ends up with nothing new, a NOTE on that message) rather than silently reporting a clean, quiet watch.

How do I know a run returned everything, without reading the log? Every run writes a RUN_SUMMARY record to its own key-value store — fetch it with GET https://api.apify.com/v2/actor-runs/<runId>/key-value-store/records/RUN_SUMMARY (no webhook needed; it's also sent as summary on any webhookUrl POST). It carries declaredMatches (what SAM.gov itself says matches your filters — null, never 0, if the search never answered with a count), reachableMatches (those minus anything past SAM.gov's 10,000-row depth cap), scanned, delivered, pages, pagesFailed, duplicateRowsDropped, republishedRowsDropped (opportunities dataset only) and a boolean complete. When complete is false, incompleteReason is one of upstream-error (SAM.gov stopped answering mid-walk, after 4 retries), short-page (SAM.gov returned an empty page before its own declared total was reached), depth-cap (the query is deeper than the 10,000 rows this backend will serve), duplicate-rows (SAM.gov served its whole result set but repeated rows across pages, so there were fewer distinct opportunities than it declared), max-results (your maxResults is below the match count — the common, harmless one), charge-limit (the run's pay-per-event limit stopped it), enrich-failed (enrichDetail was on and some detail lookups failed, so their naicsCodes/setAside/pointOfContact are null for that reason rather than because SAM.gov has none), or attachments-failed (includeAttachments was on and some attachment lookups failed, reported separately as attachmentLookupsFailed — their attachments field is null for that reason, not because the notice has no files). incompleteDetail spells out the numbers and lastApiError gives the underlying HTTP cause. A short run still finishes as SUCCEEDED — the rows it did return are real — so this record, plus the run's status message, is how a pipeline tells "200 of 200 matches" apart from "200 of 12,297".

Can the same opportunity come back twice (and be charged twice)? No, in either of the two ways this can happen. First, SAM.gov's backend pages by offset over a live, relevance-sorted index, so rows genuinely do repeat across pages under the same opportunityId. Repeats are dropped inside the walk, before any Actor.charge() call, so you are only ever billed for distinct opportunityId values; RUN_SUMMARY.duplicateRowsDropped tells you how many there were. The repeat rate is not a fixed number — it varies run to run on the identical query. Walking the same active-opportunities query (52,374 matches) to the 10,000-row depth cap twice, seconds apart, returned 8,925 distinct ids one time and 8,370 the next (89.25% vs. 83.70% yield), with duplicates landing on different pages each run. A narrower query that stays under 10,000 total matches sees none of this (measured 0 repeats on a 604-match query). Don't budget around a single "~X% repeats" figure for a query near or past the cap — read RUN_SUMMARY.duplicateRowsDropped for the actual run, or narrow filters until declaredMatches sits under 10,000. Full measurement: SAM.gov's 10,000-row depth cap doesn't promise 10,000 rows. This is also why a very broad query can return fewer rows than declaredMatches even when nothing failed — that case reports incompleteReason: "duplicate-rows" rather than pretending the backend broke.

Second — and separate from paging repeats — SAM.gov itself sometimes posts the exact same solicitation twice under two brand-new opportunityIds, which an id-keyed dedup can never catch, since the id is exactly what differs between the copies. Measured live 2026-09-24 on a 400-row activeOnly opportunities sample: 2.2% of rows were byte-identical republications (same title/solicitationNumber/description/agency/office, only the id, sourceUrl and a timestamp seconds apart differed) — one VA asbestos-monitoring notice was posted 3 times in under a second. Every run now also dedupes on a content hash (solicitationNumber + noticeTypeCode + title + a fingerprint of description) within the opportunities dataset, dropping repeats before they are charged; RUN_SUMMARY.republishedRowsDropped reports how many. This guard is scoped to the opportunities dataset only — wage determinations, assistance listings and exclusions were not part of this measurement.

Could a SAM.gov change silently turn my filtered search into an unfiltered one — and bill me for it? Not without stopping the run first. SAM.gov's backend fails closed on a filter value it doesn't recognise (naics=999999 → 0 matches) but fails open on a filter name it doesn't recognise: the parameter is silently dropped and the same HTTP 200 comes back carrying the entire index. Measured live: naics=541511 → 604 matches, the one-letter typo naic=541511 → 52,460, an 86× widening with no error anywhere — and under per-result pricing every one of those rows would be a charged "match". So before it fetches a single billable page, every run sends one tiny probe per filter name it is about to use, with a value that cannot match anything. A filter SAM.gov still honours returns 0; a dropped one returns the whole index, and the run aborts with an explicit error naming the parameter instead of delivering and charging for unfiltered rows. The probes are size=1, deliver nothing and cost you nothing. This also guards the exclusions dataset's individual-person exclusion — the classification filter that keeps private people out of the output is a parameter name like any other, and it is probed on every exclusions run whether or not you set any filters of your own.

What happens if a watch baseline run doesn't finish? It is flagged rather than silently trusted. A baseline that stopped early would report everything past the stopping point as brand new — and charge for it — on your first incremental run, so an incomplete seed saves with lastRunStatus: "seeded-incomplete", logs a BASELINE INCOMPLETE warning naming the reason, and sets a run status message telling you to re-seed before scheduling. RUN_SUMMARY reports mode: "watch-seed", complete: false and baselineSize so you can check it from code. The same applies if a baseline ever outgrows the 60,000-entry record cap (baselineTruncated).

How is webhookUrl different from Apify's own platform webhooks? Apify's platform webhooks are configured separately per Task/Actor via the Console or the Webhooks API — useful if you already live in the Apify Console, but extra setup if you're calling this Actor's API directly and just want a completion ping. webhookUrl is a plain input field: set it on the run itself and it POSTs a JSON body (actorRunId, defaultDatasetId, finishedAt, pushed, rowsScanned, the full summary object described above, and — if watchLabel is set — watchSeeding/watchNewCount/watchChangedCount/watchSkippedCount) once the run finishes and every opportunity is already pushed and charged. Especially useful with watchLabel on a scheduled bid alert: your endpoint is told how many new solicitations landed without polling the dataset, and watchSeeding: true distinguishes "this was the free baseline run" from "your watch is live and quiet" — both report zero new rows otherwise. It's best-effort — a slow or failing webhook only logs a warning, it never fails the run, changes the result set, or affects billing.

Source code

https://github.com/Fetchsmith/fetchsmith/tree/main/actors/sam-gov-opportunities-scraper

More tools: fetchsmith.com/tools — 22 HTTP-only Actors for public data sources, no browser required.