# SAM.gov Contract Opportunities Scraper: Federal RFPs & Bids (`infocomp/sam-gov-opportunities`) Actor

Scrape SAM.gov federal contract opportunities: RFPs, solicitations, sources sought & awards from GSA's official data, no API key. Filter by keyword, NAICS, PSC, set-aside, state & agency, with daily new-bid alerts. $2.40 per 1,000 notices.

- **URL**: https://apify.com/infocomp/sam-gov-opportunities.md
- **Developed by:** [InfoComp Data](https://apify.com/infocomp) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.40 / 1,000 contract notices

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SAM.gov Contract Opportunities Scraper: Federal RFPs & Bids

**Get US federal contract opportunities from SAM.gov as clean JSON, CSV or Excel**: RFPs, RFQs, solicitations, presolicitations, sources sought, special notices and award notices. **No SAM.gov account or API key needed.**

- 📥 Data comes from **GSA's official public Contract Opportunities extract**, the daily file SAM.gov publishes on its Data Services page, or from the **official Get Opportunities API** with your own free key. The Actor never scrapes sam.gov web pages, which SAM.gov's Terms of Use prohibit.
- 🎯 Filter by **keyword, NAICS, PSC, set-aside, notice type, state, agency, open deadline and award amount**.
- 🔔 **Only-new mode** + a daily schedule = a **federal bid alert** that never repeats a notice.
- 💲 **$2.40 per 1,000 notices**, no start fee, no monthly rental. Apify compute is included.

### What does this SAM.gov scraper do?

It reads every **active** notice on SAM.gov (about 70,000 at any time), applies your filters, and saves one normalized row per notice with title, solicitation number, notice type, agency path, NAICS and PSC codes, set-aside, response deadline, place of performance, award details, contracting-officer contacts, full description and a link to the notice page.

In a test run on the Apify platform on 2026-10-27, the default input (keywords `software` or `cybersecurity`, posted in the last 7 days) returned **50 notices in under 4 seconds**: 13 combined synopsis/solicitations, 11 sources sought, 11 special notices, 6 solicitations, 4 presolicitations, 3 justifications and 2 award notices.

### Why use it?

- ✅ **No API key and no 10-requests-a-day quota.** Personal SAM.gov API keys without an entity role are limited to 10 requests per day; the default mode reads GSA's public daily file instead.
- 📝 **Full description text included.** In the API, each description is a separate link that costs another request.
- ⚡ **Fast and cheap alerts.** The file is sorted newest first, so a "posted in the last N days" run stops reading early. The test run above read 6,189 of about 70,000 rows.
- 🔔 **Daily alerts with memory:** only notices not seen in previous runs, a separate memory per saved search, and optionally one alert per solicitation instead of one per amendment.
- 🎯 **Real procurement filters:** NAICS and PSC prefix match (`5415`, `D3`), set-aside codes (SBA, 8A, SDVOSBC, WOSB, HZC…), notice type, place-of-performance state, agency or office, open response deadline, minimum award amount.
- 🔑 **Optional API mode with your own key** for archived notices, attachment links and exact date windows, with a request budget that protects your daily quota.
- 🧾 **One normalized schema** for both sources, ready for Google Sheets, Slack, CRMs, Zapier, Make, n8n and AI agents (Apify MCP server).

### Use cases

- **GovCon bid alerts:** new solicitations in your NAICS codes and set-aside every morning, to Slack, email or a Google Sheet.
- **Capture and business-development teams:** track agencies, offices and recompetes; catch sources-sought notices before the RFP drops.
- **Small-business contractors** (8(a), SDVOSB, WOSB, HUBZone): see only set-aside opportunities you can bid on.
- **Market research:** what the government buys, from whom (award notices), where and when.
- **Lead lists** for GovCon consultants, proposal writers and newsletters.
- **Data feeds** for dashboards, CRMs or your own app.

### How to use it

1. Click **Try for free**.
2. Set filters, e.g. keywords `cybersecurity`, NAICS `5415`, set-aside `SBA`, posted within `3` days.
3. Click **Start**. Export JSON, CSV, Excel or XML, or read results through the Apify API.
4. **For alerts:** turn on **Only notices not seen in previous runs**, give the alert a name (state key), and create a daily **Schedule**. GSA refreshes the file once a day; in our checks it was last modified around 03:30 UTC.

#### Input example

```json
{
  "keywords": ["cybersecurity", "zero trust"],
  "naicsCodes": ["5415"],
  "setAsideCodes": ["SBA", "SDVOSBC"],
  "noticeTypes": ["solicitation", "combined", "sources_sought"],
  "postedWithinDays": 3,
  "onlyOpen": true,
  "onlyNewNotices": true,
  "stateKey": "cyber-small-business"
}
```

### Output example

A real record from the test run on 2026-10-27 (description shortened, secondary contact omitted):

```json
{
  "noticeId": "55d10c5390da4bd4836d484da769c456",
  "title": "FIBO machines/software and Adapters",
  "solicitationNumber": "SPMYM127Q0001",
  "noticeType": "Combined Synopsis/Solicitation",
  "baseType": "Combined Synopsis/Solicitation",
  "active": true,
  "postedDate": "2026-10-23T10:45:42",
  "responseDeadline": "2026-10-26T17:00:00-04:00",
  "archiveDate": "2026-11-10",
  "department": "DEPT OF DEFENSE",
  "subTier": "DEFENSE LOGISTICS AGENCY",
  "office": "DLA MARITIME - NORFOLK",
  "agencyPath": "DEPT OF DEFENSE > DEFENSE LOGISTICS AGENCY > DLA MARITIME - NORFOLK",
  "agencyCode": "SPMYM1",
  "naicsCode": "334519",
  "pscCode": "6695",
  "setAsideCode": "SBA",
  "setAside": "Small Business Set Aside - Total",
  "placeOfPerformance": {"street": null, "city": "Portsmouth", "state": "VA", "zip": "23709", "country": "USA"},
  "award": null,
  "primaryContact": {"title": null, "fullName": "DeShaura Adams", "email": "deshaura.adams@dla.mil", "phone": null, "fax": null},
  "description": "This is a Brand Name Only Total Small Business Set Aside requirement. …",
  "descriptionTruncated": false,
  "attachments": null,
  "url": "https://sam.gov/opp/55d10c5390da4bd4836d484da769c456/view",
  "source": "sam.gov-extract",
  "dataLastModified": "Tue, 27 Oct 2026 03:30:29 GMT",
  "retrievedAt": "2026-10-27T14:44:52.821968Z"
}
```

All fields: `noticeId`, `title`, `solicitationNumber`, `noticeType`, `baseType`, `active`, `postedDate`, `responseDeadline`, `archiveDate`, `archiveType`, `department`, `subTier`, `office`, `agencyPath`, `agencyCode`, `organizationType`, `naicsCode`, `pscCode`, `setAsideCode`, `setAside`, `placeOfPerformance`, `officeAddress`, `award`, `primaryContact`, `secondaryContact`, `description`, `descriptionTruncated`, `descriptionUrl`, `attachments`, `additionalInfoLink`, `url`, `source`, `dataLastModified`, `retrievedAt`.

`RUN_SUMMARY` in the key-value store records the source used, rows read, whether the download stopped early, the file's last-modified time and API requests used.

### Extract mode vs. API mode

| | Public daily extract (default) | SAM.gov API (your key) |
|---|---|---|
| Key or account | None | Free personal key from sam.gov → Profile → Account Details |
| Coverage | All **active** notices | Active **and archived/inactive** notices, last 364 days per run |
| Description | Full text, truncated by GSA at about 32,000 characters | Separate link; fetching it uses 1 request per notice |
| Attachments | No | `attachments` links (`resourceLinks`) |
| Quota | None (one file download per run) | 10 requests/day for personal keys without an entity role; 1,000/day with a role (1,000 notices per request) |

### How much does it cost?

**$2.40 per 1,000 notices saved** ($0.0024 per notice), with **no start fee and no monthly rental**. Apify platform compute is included in the price, so you pay only for results.

- Runs with no matches cost nothing, and notices removed by your filters aren't charged.
- Example: a daily alert that returns 25 new notices costs about **$0.06 a day**, under $2 a month.
- Set a **maximum cost per run** and the Actor stops cleanly when it reaches it.

The **Pricing** tab always shows the current price.

### How it compares

| | This Actor (default mode) | SAM.gov API with a personal key | Scraping sam.gov pages |
|---|---|---|---|
| Account or key | None | Free key, SAM.gov account | None |
| Daily quota | None | 10 requests/day without an entity role | n/a |
| Full description | Included | 1 extra request per notice | Varies |
| Archived notices, attachments | ❌ (✅ in API mode with your key) | ✅ | Varies |
| Allowed by SAM.gov terms | ✅ public data extract | ✅ | ❌ prohibited by SAM.gov Terms of Use |

### Data source, terms and attribution

- **Sources:**
  - SAM.gov Contract Opportunities public extract, U.S. General Services Administration (sam.gov/data-services);
  - SAM.gov Get Opportunities Public API (open.gsa.gov).
- **Copyright and attribution:** SAM.gov states that most material is free of copyright as US government work, and asks for a citation and a link back to GSA. Every record carries `source`, `url`, `dataLastModified` and `retrievedAt`.
- **Dun & Bradstreet data:** award notices with an award date before 4 April 2022 may contain D\&B data, which SAM.gov's terms restrict. For those records the Actor **omits the awardee** and says why in `award.awardeeWithheld`.
- **Contacts:** contracting-office contacts are the government points of contact published on each notice. Turn them off with **Include contracting-office contacts**.
- **Your API key:** SAM.gov's terms say not to share your personal key. Enter **your own** key; it is a secret input and is never logged.
- **No endorsement:** this Actor is independent and not affiliated with or endorsed by GSA or SAM.gov. The data is not an official copy; always confirm details on the notice page before you bid.

### FAQ

**Do I need a SAM.gov account?**
No. The default mode uses GSA's public file. A key is only needed for archived notices or attachment links.

**Why is a notice I saw yesterday missing?**
The extract holds **active** notices only. Notices that were archived, cancelled or deleted drop out. Use API mode to search archived ones.

**How fresh is the data?**
GSA regenerates the extract daily. Each record's `dataLastModified` shows the file's timestamp.

**Does it include amendments?**
Yes. Each amendment is its own notice on SAM.gov. To alert only once per solicitation number, turn off **Count amendments as new**.

**Can I get only small-business set-asides?**
Yes. Add set-aside codes such as `SBA`, `8A`, `SDVOSBC`, `WOSB` or `HZC`. Use `NONE` for full and open competition.

**Can I use it in Zapier, Make, n8n, Google Sheets or with an AI agent?**
Yes. Any Apify integration, webhook, the Apify API or the Apify MCP server works.

# Actor input Schema

## `keywords` (type: `array`):

Whole-word, case-insensitive. A notice matches if its title (or, if you choose, title and description) contains any of these, e.g. cybersecurity, janitorial, "software development". Leave empty for all notices.

## `keywordsIn` (type: `string`):

Where to look for keywords.

## `excludeKeywords` (type: `array`):

Drop notices whose title contains any of these words, e.g. construction, repair.

## `noticeTypes` (type: `array`):

Leave empty for all types.

## `naicsCodes` (type: `array`):

e.g. 541511 (custom programming) or 5415 to match every code that starts with 5415.

## `pscCodes` (type: `array`):

Product Service Codes, e.g. D3 (IT services) or R4 (professional support).

## `setAsideCodes` (type: `array`):

SAM.gov set-aside codes, e.g. SBA (total small business), 8A, SDVOSBC, WOSB, HZC. Use NONE for notices without a set-aside.

## `states` (type: `array`):

Two-letter codes, e.g. TX, VA, DC.

## `agencies` (type: `array`):

Case-insensitive match on department, sub-tier and office, e.g. "veterans affairs", "department of the army", NASA.

## `postedWithinDays` (type: `integer`):

Recommended for alerts (e.g. 1 or 2 on a daily schedule): the extract is sorted newest first, so the download stops early and runs are fast and cheap. Leave empty for every active notice. In API mode the default is 30 and the maximum 364.

## `onlyOpen` (type: `boolean`):

Drop notices whose response deadline has passed. Notices with no deadline (e.g. awards, special notices) are kept unless you filter them out by type.

## `minAwardAmount` (type: `integer`):

Keep only award notices with at least this amount.

## `onlyNewNotices` (type: `boolean`):

Remembers notices between runs (in a named key-value store in your account) and returns only new ones. Schedule daily for a federal bid alert.

## `treatAmendmentsAsNew` (type: `boolean`):

SAM.gov gives every amendment its own notice ID. On: alert on each new version. Off: alert once per solicitation number.

## `stateKey` (type: `string`):

Separate memory for each saved search, e.g. "cyber-va". Only used with "Only notices not seen".

## `includeDescription` (type: `boolean`):

Full notice description (the extract includes it; GSA truncates very long ones at about 32,000 characters).

## `includeContacts` (type: `boolean`):

Primary and secondary points of contact (government contracting officers' work name, email and phone) as published on the notice.

## `maxResults` (type: `integer`):

Stop after this many notices. Leave empty for no limit (your max cost per run still applies).

## `dataSource` (type: `string`):

Extract: GSA's official daily file of all active notices, no API key needed. API: SAM.gov Get Opportunities API with your own key, adds archived notices and attachment links. Auto uses the API when a key is given.

## `samApiKey` (type: `string`):

Free personal key from sam.gov > Profile > Account Details > Public API Key. Stored encrypted; never logged. Personal keys without an entity role allow 10 requests per day (1,000 per page).

## `maxApiRequests` (type: `integer`):

Protects your daily SAM.gov quota. Each request returns up to 1,000 notices.

## `fetchApiDescriptions` (type: `boolean`):

The API returns descriptions as a separate link; fetching each costs one request from your quota.

## Actor input object example

```json
{
  "keywords": [
    "software",
    "cybersecurity"
  ],
  "keywordsIn": "title",
  "postedWithinDays": 7,
  "onlyOpen": false,
  "onlyNewNotices": false,
  "treatAmendmentsAsNew": true,
  "stateKey": "default",
  "includeDescription": true,
  "includeContacts": true,
  "dataSource": "auto",
  "maxApiRequests": 10,
  "fetchApiDescriptions": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "software",
        "cybersecurity"
    ],
    "postedWithinDays": 7
};

// Run the Actor and wait for it to finish
const run = await client.actor("infocomp/sam-gov-opportunities").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": [
        "software",
        "cybersecurity",
    ],
    "postedWithinDays": 7,
}

# Run the Actor and wait for it to finish
run = client.actor("infocomp/sam-gov-opportunities").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "software",
    "cybersecurity"
  ],
  "postedWithinDays": 7
}' |
apify call infocomp/sam-gov-opportunities --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,infocomp/sam-gov-opportunities"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dYOiGFS8gNxiQOqvw/builds/uuuIZcfcUk2xZQucR/openapi.json
