← Guides

How-to

How to run SAM.gov Federal Contract Opportunity Alert

Step-by-step: the exact input, what each field does, and the real rows that come back from SAM.gov.

If you bid federal work, you already have a search saved on SAM.gov: your NAICS codes, maybe an agency, maybe a set-aside. Someone re-runs it every morning, reads the hits, and copies the ones worth chasing into a spreadsheet or a CRM. That is fine at low volume and it is free. It stops being fine when it is three or four searches a day across several NAICS codes, when the person doing it is on holiday, or when you want the results to land somewhere other than a browser tab. This actor runs that search for you on a schedule and hands back structured rows.

Be clear about what it is: an on-demand search, not a subscription to a change feed. Every run asks SAM.gov the same question you would ask, and returns whatever currently matches inside your look-back window. There is no memory between runs — nothing is marked “new”, nothing is suppressed because you saw it yesterday. You pay per row returned, every run.

What you’ll need

Nothing but an Apify account. The actor talks to SAM.gov directly.

You don’t need a data.gov API key. The actor carries its own, so there is no signup, no key to rotate, and no proxy or CAPTCHA cost in the middle. If you’d rather not pay per row, note that a data.gov key is free and the same API is public — wiring it up yourself is a perfectly good option, and it’s covered under “What it costs” below.

Step 1 — Open the actor

Open SAM.gov Federal Contract Opportunity Alert on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.

The SAM.gov Federal Contract Opportunity Alert listing on the Apify Store
The listing on the Apify Store. Pricing and the nightly health record are both public.

Step 2 — Fill in the input

The input form for SAM.gov Federal Contract Opportunity Alert in the Apify Console
The input form, as it appears in the Apify Console.
FieldTypeRequiredWhat it does
naicsCodesarraynoIndustry codes to match (e.g. ‘541512’). Leave empty to match any industry.
keywordstringnoFree-text match on the opportunity title (e.g. ‘cybersecurity’).
agencystringnoBuying department name (e.g. ‘GENERAL SERVICES ADMINISTRATION’).
setAsidestringnoSet-aside code, e.g. SBA (small business), 8A, WOSB, SDVOSBC. Leave empty for all.
lookbackDaysintegernoFetch opportunities posted within this many days. Every run returns everything in the window that matches, so a wide window on a frequent schedule returns the same notices again. (default 1)
maxResultsintegernoCap on opportunities fetched per run. (default 100)

Two fields decide almost everything, and they are the two people get wrong.

lookbackDays is a window, not a bookmark. At 1 — the default — a run returns notices posted in the last day. At 30, it returns everything from the last 30 days, and it will return those same notices again on tomorrow’s run, because the actor has no memory of what it gave you before. Since you’re charged per row, a daily schedule with lookbackDays: 1 is the cheap combination and a daily schedule with lookbackDays: 30 is the expensive one that tells you almost nothing new. Widen the window when you’re doing a one-off sweep of what’s already open; keep it tight when you’re running on a timer.

maxResults is your ceiling on both rows and spend — it caps what a run can fetch, and therefore what a run can cost you. If your filters are broad (no NAICS, no agency, no set-aside), leave it low until you’ve seen what a run actually returns.

A working input:

{
  "naicsCodes": [
    "541512"
  ],
  "setAside": "SBA",
  "lookbackDays": 1,
  "maxResults": 100
}

Step 3 — Run it

Press Start. Rows are pushed to the dataset as they’re found, so the run log fills in as it works.

This is one public JSON API call per page of results — no browser, no rendering, no proxy — so a run is short and the row count is whatever SAM.gov currently has for your filters, up to maxResults.

An empty run is a normal result, not a failure. With lookbackDays: 1 and a narrow NAICS plus a set-aside, plenty of days simply have no new matching notices. Empty runs return nothing and cost nothing. If you want to check the filters themselves rather than wait, widen lookbackDays to 30 once and see whether anything at all comes back — if that’s still empty, the filter combination is too narrow, not the actor. The one genuine error you’ll see is an API failure from SAM.gov itself, which the run log reports verbatim (status code and message) rather than swallowing.

Step 4 — Read the output

Each run returns a labelled table, not raw JSON:

The output fields returned by SAM.gov Federal Contract Opportunity Alert
The output view — every field the actor returns, named and typed.

Every row looks like this — a real row from a real run:

{
  "notice_id": "abc123def456",
  "title": "IT Support Services",
  "solicitation_number": "W912-26-R-0001",
  "agency": "DEPT OF DEFENSE.DEPT OF THE ARMY.ACC",
  "notice_type": "Solicitation",
  "naics_code": "541512",
  "set_aside": "Total Small Business Set-Aside (FAR 19.5)",
  "posted_date": "2026-06-20",
  "response_deadline": "2026-07-05T17:00:00-04:00",
  "archive_date": "2026-07-20",
  "place_of_performance_state": "VA",
  "contact_name": "Jane Doe",
  "contact_email": "jane.doe@army.mil",
  "ui_link": "https://sam.gov/workspace/contract/opp/abc123def456/view",
  "source_url": "https://sam.gov/workspace/contract/opp/abc123def456/view"
}
FieldExample valueMeaning
notice_idabc123def456SAM.gov notice ID
titleIT Support ServicesOpportunity title
solicitation_numberW912-26-R-0001Solicitation number
agencyDEPT OF DEFENSE.DEPT OF THE ARMY.ACCBuying agency / department hierarchy
notice_typeSolicitationNotice type (Solicitation, Combined Synopsis, etc.)
naics_code541512NAICS industry code
set_asideTotal Small Business Set-Aside (FAR 19.5)Set-aside type (e.g. Total Small Business)
posted_date2026-06-20Date the notice was posted

The field people actually came for is response_deadline — the date that decides whether an opportunity is worth opening at all — closely followed by ui_link, which drops you straight onto the notice in SAM.gov so nobody has to re-find it.

Two things to watch. First, dates are not one shape: posted_date and archive_date come back as plain dates, while response_deadline is a full timestamp with a timezone offset (2026-07-05T17:00:00-04:00). If you’re sorting or filtering in a spreadsheet, normalise it. Second, any field can be null. SAM.gov doesn’t guarantee a point of contact, a set-aside, or even a solicitation number on every notice, and the actor passes through what the API gives rather than inventing a filler value — so treat contact_email, set_aside and place_of_performance_state as nice-to-have, not as columns you can key a workflow off. notice_id and ui_link are the reliable identifiers.

The actor asks SAM.gov for open-opportunity notice types — solicitations, combined synopsis/solicitations, presolicitations and sources-sought notices. Award notices are not part of what it returns.

Step 5 — Export it

Open the Dataset tab and export to CSV, JSON, or Excel — or pull the same rows from the API, which is what you want if this is going to run on a schedule.

What it costs

You pay $0.01 per opportunity returned, every run — there is no discount for a row you’ve seen before, because the actor doesn’t know you’ve seen it. A run that matches nothing returns nothing and costs nothing. Apify’s own platform usage is billed separately on top, and this actor is a plain JSON fetch, so that part is small.

So a realistic daily schedule on a narrow filter — one NAICS code, one set-aside, lookbackDays: 1 — is a handful of rows on the days something posts and $0 on the days nothing does. The way to make it expensive is a wide look-back on a frequent schedule: lookbackDays: 30 run daily re-charges you for the whole 30-day window every single morning. Set maxResults to a number you’re willing to pay for and it can’t surprise you.

And the honest comparison: SAM.gov’s search is free and public, and the GSA Get Opportunities API behind this actor is free too — you just need a data.gov key. If you’re happy running the search by hand, or happy writing and hosting the API client, the data costs you nothing. What you’re buying here is the wiring: no key, no client, no cron box, just structured rows on a schedule.

Where the data comes from

This reads SAM.gov directly. The target is Official SAM.gov JSON API. Every night a canary runs this actor against that live source and diffs the result against a frozen fixture — what “verified” means.

SAM.gov is the federal government’s own registry of contract opportunities, and the actor reads it through GSA’s public Get Opportunities API — not a scraped copy, not a resold aggregator. There is no anti-bot wall here and nothing to defeat; the annoyance is bureaucratic rather than technical. You need a data.gov key, the date parameters want MM/dd/yyyy, filters are opaque codes rather than labels (SBA, 8A, WOSB, SDVOSBC), the notice types you want have to be requested explicitly or you get award notices mixed in with live solicitations, and the interesting values — the set-aside description, the place of performance, the point of contact — sit nested inside the JSON rather than on the top level of each record. It is an afternoon of work to get right and then a thing you own forever. The actor is that afternoon, already done, plus a nightly check that it still parses.

See it used

If it’s the bidders rather than the bids you’re after, reach for the Multi-State Contractor License Lookup instead — that one verifies a contractor’s licence across several states, which is the check you run on a subcontractor before you put them on a proposal.

Last updated 2026-07-13