# SAM.gov Contract Opportunities Scraper (`artificially/samgov-opportunities-scraper`) Actor

Scrape US federal contract opportunities from SAM.gov with full descriptions, contracting officer emails and phones, attachments, NAICS/PSC, set-asides, deadlines and award details. No API key needed. Monitor only new notices on a schedule.

- **URL**: https://apify.com/artificially/samgov-opportunities-scraper.md
- **Developed by:** [Artificially](https://apify.com/artificially) (community)
- **Categories:** Lead generation, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.58 / 1,000 opportunities

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Get US federal contract opportunities from [SAM.gov](https://sam.gov/search/?index=opp) as clean, ready-to-use data: open solicitations, RFQs, RFPs, sources sought / RFIs, presolicitations, special notices and award notices.

Each result includes the **full description as plain text**, **contracting officer names, emails and phones**, **attachment download links** (RFP, SOW, PWS, pricing templates), NAICS and PSC codes, set-aside, response deadline, place of performance, the full agency path and, for award notices, the **awardee, UEI and award amount**.

**No API key and no SAM.gov account needed.** Turn on **Only new since last run** and add a Schedule to get a daily feed of fresh opportunities that match your capabilities.

Looking for contracts that were already awarded and paid out? Use our companion [US Government Contracts Scraper](https://apify.com/artificially/us-contracts-scraper) (USAspending.gov).

#### Use with AI agents (MCP)

This Actor works as a tool for Claude, ChatGPT, Cursor and other AI agents through [Apify's MCP server](https://mcp.apify.com). Ask for opportunities in plain language and the agent fills in the filters. Set `compactOutput: true` and a small `maxResults` (e.g. 10) so results fit easily in the agent's context.

**Quick setup** (sign in with your Apify account when asked):

- **Claude** (claude.ai or Claude Desktop): Settings → Connectors → Add custom connector, and paste `https://mcp.apify.com?tools=artificially/samgov-opportunities-scraper`
- **Claude Code or Cursor** via the Apify CLI (latest version, `apify upgrade`): `apify mcp install claude-code --tools artificially/samgov-opportunities-scraper` (use `cursor` instead of `claude-code` for Cursor)
- **Any MCP client** (Cursor, VS Code, Windsurf):

```json
{
  "mcpServers": {
    "apify": { "url": "https://mcp.apify.com?tools=artificially/samgov-opportunities-scraper" }
  }
}
```

**Try asking:**

- "Find open SAM.gov solicitations for NAICS 541512 posted in the last 14 days, with contracting officer emails."
- "Show small-business set-aside cybersecurity opportunities on SAM.gov with deadlines this month."

### What you can use it for

- **Business development and capture teams**: a daily list of new solicitations in your NAICS codes, with the contracting officer's email to reach out before the deadline.
- **Small businesses**: find notices reserved for your program (8(a), HUBZone, SDVOSB, WOSB, Total Small Business).
- **Bid/no-bid triage**: filter by response deadline so you only see opportunities you still have time to bid on, with the days left already calculated.
- **Market research**: track which agencies buy what, where the work is performed and who wins (award notices with awardee name, UEI and amount).
- **Feeding your CRM, Slack or AI agent**: send results to Google Sheets, HubSpot, Slack, Zapier or Make through Apify integrations, or use the data in an LLM to score fit and draft responses.

### How it works

1. You pick filters: keywords, notice types, NAICS, PSC, set-asides, agencies, states, dates and deadlines.
2. The Actor searches SAM.gov's public contract opportunities data, the same data you see on sam.gov.
3. For each notice it collects the full details, contacts and the list of attachments and links (files are not downloaded, you get direct download URLs).
4. Only complete notices with a valid notice ID, title and SAM.gov link are saved. Duplicates are removed.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | string | | Words to search for in the title, description and solicitation number (all words must match) |
| `noticeTypes` | array | all | `o` Solicitation, `k` Combined Synopsis/Solicitation, `p` Presolicitation, `r` Sources Sought, `s` Special Notice, `a` Award Notice, `u` Justification (J\&A), `i` Intent to Bundle, `g` Sale of Surplus Property |
| `naicsCodes` | array | | NAICS codes, e.g. `541512`. A prefix like `5415` matches every code under it |
| `pscCodes` | array | | Product Service Codes, e.g. `R425`, `DA01` |
| `setAsideTypes` | array | | `SBA`, `SBP`, `8A`, `8AN`, `HZC`, `HZS`, `SDVOSBC`, `SDVOSBS`, `WOSB`, `WOSBSS`, `EDWOSB`, `EDWOSBSS`, `VSA`, `VSS`, `LAS`, `IEE`, `ISBEE`, `BICiv` |
| `agencies` | array | | Agency names like `Department of Veterans Affairs`, `Army`, `NASA`, or SAM.gov organization IDs |
| `states` | array | | Place of performance state codes, e.g. `VA`, `MD` |
| `postedWithinDays` | integer | | Only notices posted in the last N days |
| `postedFrom` / `postedTo` | date | | Posted date range (YYYY-MM-DD) |
| `responseDeadlineFrom` / `responseDeadlineTo` | date | | Response deadline range (YYYY-MM-DD) |
| `openForResponsesOnly` | boolean | `false` | Only notices whose response deadline is today or later |
| `activeOnly` | boolean | `true` | Skip archived and inactive notices |
| `sortBy` | string | `-relevance` | `-relevance` (best keyword match) or `-modifiedDate` (most recently updated) |
| `includeDescription` | boolean | `true` | Add the full description as plain text |
| `includeAttachments` | boolean | `true` | Add attachment names, sizes and download URLs, plus external links |
| `compactOutput` | boolean | `false` | Slim items with only the key fields (ID, link, title, type, dates, agency, NAICS, set-aside, state, first contact, attachment count, award). Best for AI agents |
| `maxResults` | integer | `100` | Maximum notices to save in one run (up to 10,000) |
| `onlyNewSinceLastRun` | boolean | `false` | Skip notices returned by earlier runs with the same filters |
| `apiKey` | string | | Optional SAM.gov public API key. Not required |
| `proxyConfiguration` | object | off | Not needed in most cases |

#### Example input

```json
{
    "keywords": "cybersecurity",
    "noticeTypes": ["o", "k", "p", "r"],
    "naicsCodes": ["541512", "541519"],
    "setAsideTypes": ["SBA", "SDVOSBC"],
    "postedWithinDays": 14,
    "openForResponsesOnly": true,
    "maxResults": 200
}
```

### Output

One item per notice. This is a real item from a run with `naicsCodes: ["541512"]`, `setAsideTypes: ["SBA"]` and `openForResponsesOnly: true`:

```json
{
    "noticeId": "ee15f287bd3049349277a9bd31c206df",
    "samUrl": "https://sam.gov/opp/ee15f287bd3049349277a9bd31c206df/view",
    "title": "RFI: Air Force Enterprise Rapid Operations Support (AEROS)",
    "solicitationNumber": "AEROS",
    "noticeType": "Sources Sought",
    "noticeTypeCode": "r",
    "active": true,
    "cancelled": false,
    "postedDate": "2026-09-01T15:29:02.256+00:00",
    "modifiedDate": "2026-09-01T15:29:02.265+00:00",
    "responseDeadline": "2026-09-30T17:00:00-04:00",
    "responseTimeZone": "America/New_York",
    "daysUntilDeadline": 7,
    "archiveDate": "2026-10-15",
    "department": "DEPT OF DEFENSE",
    "subTier": "DEPT OF THE AIR FORCE",
    "office": "FA2318 AFLCMC HBMK",
    "organizationPath": "DEPT OF DEFENSE > DEPT OF THE AIR FORCE > FA2318 AFLCMC HBMK",
    "officeAddress": {
        "streetAddress": "CP 817 888 1879, 236 CITATION DR",
        "city": "HANSCOM AFB",
        "state": "TX",
        "zip": "76106-2759",
        "country": "USA"
    },
    "naicsCode": "541512",
    "naicsCodes": ["541512"],
    "pscCode": "DA01",
    "setAsideCode": "SBA",
    "setAside": "Total Small Business Set-Aside (FAR 19.5)",
    "placeOfPerformance": {
        "streetAddress": null,
        "city": "Scott AFB",
        "state": "IL",
        "zip": "62225",
        "country": "USA"
    },
    "pointsOfContact": [
        {
            "name": "Mikayla Sequeira",
            "title": null,
            "email": "mikayla.sequeira@us.af.mil",
            "phone": null,
            "fax": null,
            "type": "primary"
        },
        {
            "name": "Venezia Delgadillo",
            "title": null,
            "email": "venezia.delgadillo@us.af.mil",
            "phone": null,
            "fax": null,
            "type": "secondary"
        }
    ],
    "description": "AFLCMC C3M OL-2 intends to solicit a contract for non-personal commercial services to support the requirements for the AFTRANS enterprise functional help desk services and technical operations help desk services for the existing legacy system portfolio applications and the Next Generation modernized system portfolio applications. The support includes providing comprehensive functional and technical operations support of critical command and control (C2) capabilities within a government-provided environment.",
    "attachments": [
        {
            "name": "AEROS RFI.pdf",
            "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/fa83f9be70404aad8fc4cb846f2990e2/download",
            "type": "file",
            "size": 231223,
            "mimeType": "pdf",
            "postedDate": "2026-08-31T19:17:05.664+00:00"
        },
        {
            "name": "AEROS PWS Excerpt.pdf",
            "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/d29cc44563484c7e9f866ec9f7102f5b/download",
            "type": "file",
            "size": 233778,
            "mimeType": "pdf",
            "postedDate": "2026-09-01T15:29:02.256+00:00"
        }
    ],
    "award": null,
    "parentNoticeId": "f4ea200723f2483ca0d32d5ae73325e5",
    "relatedNoticeId": null,
    "scrapedAt": "2026-09-23T09:01:27.415Z"
}
```

Award notices also fill the `award` object, for example:

```json
"award": {
    "date": "2026-09-22",
    "amount": 8761.49,
    "number": "140FS126P0287",
    "awardeeName": "ALASKA MINE SERVICES, LLC",
    "awardeeUei": "ZAWDUZF7NHF1",
    "awardeeCageCode": "171R4",
    "awardeeLocation": { "streetAddress": "HC 66 BOX 28012", "city": "Nenana", "state": "AK", "zip": "99760", "country": "USA" }
}
```

The dataset has three ready-made views: **Opportunities**, **Contacts** and **Awards**. You can export any of them as JSON, CSV, Excel or HTML.

Each run also saves two records in its key-value store:

- `SUMMARY`: how many notices matched, were saved, were skipped as already seen, and failed.
- `FAILED_NOTICES`: notices that could not be fetched after several retries, with the reason. These are not saved and not charged.

### Pricing

This Actor uses pay-per-event pricing. See the **Pricing** tab for the current prices.

- You only pay for results saved to the dataset. Failed or invalid notices are free.
- In monitoring mode, notices you already received in earlier runs are skipped for free.
- Set a **maximum cost per run** in the run options and the Actor will stop cleanly when it is reached.

### Monitoring new opportunities every day

1. Set your filters, for example NAICS `541512`, notice types Solicitation and Sources Sought, `postedWithinDays: 7`.
2. Turn on **Only new since last run**.
3. Save it as a Task and add a [Schedule](https://docs.apify.com/platform/schedules) (for example every weekday at 7:00).
4. Connect an integration (email, Slack, Google Sheets, webhook) to receive each new batch.

The first run returns everything that currently matches. Every run after that returns only notices you have not seen yet. The list of seen notice IDs is kept per filter combination in the named key-value store `samgov-opportunities-monitor` in your account, so different Tasks with different filters track their own history. Delete that store (or change a filter) to start over.

### FAQ

**Do I need a SAM.gov API key?**
No. The Actor reads the same public data the sam.gov website shows without logging in. If you already have a free SAM.gov public API key you can add it in `apiKey` and the search step will use the official Get Opportunities API. If the key is rejected or its daily limit is used up, the Actor automatically falls back to the public search.

**Are attachment files downloaded?**
No. You get each file's name, size, type and a direct download URL on sam.gov, plus external links (for example PIEE or NECO solicitation links). Only public attachments are listed. Controlled (CUI) or export-controlled documents that require a SAM.gov login are not included.

**Why do I see the same solicitation number twice?**
When an agency amends a notice, SAM.gov publishes a new version with a new notice ID. The `parentNoticeId` field points to the previous version. In monitoring mode, amendments therefore show up as new items so you do not miss changes.

**How many results can I get?**
SAM.gov lets a single search reach up to 10,000 notices. If your filters match more, narrow them (for example by date range or NAICS) and run several Tasks.

**Why does a keyword match notices that do not mention it in the title?**
Keywords are searched in the full notice text, including clauses. Use more specific phrases, NAICS/PSC codes or notice types to narrow results.

**What does "active" mean?**
Active notices are not yet archived on SAM.gov. A notice can still be active after its response deadline has passed. Use `openForResponsesOnly` or `responseDeadlineFrom` to keep only notices you can still respond to.

**Is this data accurate?**
It comes straight from SAM.gov, the official US government source for contract opportunities. Always check the notice on SAM.gov before submitting a bid.

### Support

Found a problem or need another field? Open an issue on the Issues tab and we will look at it quickly.

### Related actors

- [US Government Contracts Scraper](https://apify.com/artificially/us-contracts-scraper): contracts that were already awarded, with amounts, recipients and agencies from USAspending.gov.
- [EU Tenders Scraper](https://apify.com/artificially/eu-tenders-scraper): public tenders and contract notices from the EU's Tenders Electronic Daily (TED).

# Actor input Schema

## `keywords` (type: `string`):

Free-text search in the notice title, description and solicitation number. All words must match. Example: "cybersecurity" or "janitorial services". Leave empty to return everything that matches the other filters.

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

Notice type codes to include. Allowed values: o = Solicitation, k = Combined Synopsis/Solicitation, p = Presolicitation, r = Sources Sought, s = Special Notice, a = Award Notice, u = Justification (J\&A), i = Intent to Bundle, g = Sale of Surplus Property. Example: \["o", "k"] for open solicitations, \["a"] for award notices. Leave empty for all types.

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

NAICS industry codes (digits only). A shorter prefix matches every code under it. Example: \["541512", "5415"] (541512 = Computer Systems Design Services). Leave empty for all industries.

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

Product Service Codes (4 characters) or prefixes. Example: \["R425", "DA01"] (R425 = Engineering and Technical Support). Leave empty for all.

## `setAsideTypes` (type: `array`):

Only notices reserved for these small business programs. Use the codes from the allowed values, e.g. \["SBA"] (Total Small Business), \["8A"], \["SDVOSBC"], \["WOSB"], \["HZC"] (HUBZone). Leave empty for all notices, set-aside or not.

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

Federal departments, agencies or offices by name or numeric SAM.gov organization ID. Each name is matched to the closest SAM.gov organization. Example: \["Department of Veterans Affairs", "NASA"] or \["Army"]. Leave empty for all agencies.

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

Two-letter US state codes where the work is performed. Example: \["VA", "MD", "TX"]. Invalid codes are ignored. Leave empty for any location.

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

Only notices published in the last N days, as an integer from 1 to 3650. Example: 7. Ignored when postedFrom is set. Leave empty for no posted-date limit.

## `postedFrom` (type: `string`):

Only notices published on or after this date. Format YYYY-MM-DD, e.g. "2026-01-31". Overrides postedWithinDays.

## `postedTo` (type: `string`):

Only notices published on or before this date. Format YYYY-MM-DD, e.g. "2026-03-31".

## `responseDeadlineFrom` (type: `string`):

Only notices whose response/offer due date is on or after this date. Format YYYY-MM-DD, e.g. "2026-02-01". Handy to skip opportunities you no longer have time to bid on. Notices without a deadline (e.g. award notices) are excluded when this is set.

## `responseDeadlineTo` (type: `string`):

Only notices whose response due date is on or before this date. Format YYYY-MM-DD, e.g. "2026-04-30".

## `openForResponsesOnly` (type: `boolean`):

Set to true to get only notices whose response deadline is today or later, so you never get a solicitation you can no longer bid on. Notices without a deadline (e.g. award notices) are excluded when this is on. Ignored when responseDeadlineFrom is set.

## `activeOnly` (type: `boolean`):

true skips archived and inactive notices. Set to false to include them (e.g. for historical research).

## `sortBy` (type: `string`):

Order of results. "-relevance" = best keyword match first (only applies when keywords are set). "-modifiedDate" = most recently updated first. Without keywords, and always in monitoring mode, the most recently updated notices come first.

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

Add the full notice description as plain text (HTML removed) in the description field. Set to false for smaller output. Ignored when compactOutput is on.

## `includeAttachments` (type: `boolean`):

Add the name, size and download URL of every public attachment and external link. Files are not downloaded. With compactOutput on, only the attachmentsCount is returned.

## `compactOutput` (type: `boolean`):

Set to true to save a slim item per notice with only the key fields: noticeId, samUrl, title, solicitationNumber, noticeType, postedDate, responseDeadline, daysUntilDeadline, department, subTier, office, naicsCode, setAsideCode, setAside, placeOfPerformance.state, the first point of contact (name, email), attachmentsCount and award (amount, awardeeName). The full description, attachment list, addresses and other fields are dropped. Recommended when an AI agent or LLM reads the results. Leave false for the full item.

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

Maximum number of notices to save in this run, from 1 to 10000. Each saved notice is one result. Example: 10 for a quick look, 500 for a full export.

## `onlyNewSinceLastRun` (type: `boolean`):

Set to true to skip notices already returned by earlier runs with the same filters. Use it with a Schedule to get only fresh opportunities each day. Seen notice IDs are kept in the named key-value store "samgov-opportunities-monitor".

## `apiKey` (type: `string`):

Not required, leave empty. If you have a free SAM.gov public API key, the search runs through the official Get Opportunities API v2 (subject to its daily limits). If the key fails or the daily limit is used up, the Actor falls back to the public SAM.gov search.

## `proxyConfiguration` (type: `object`):

Not needed for SAM.gov in most cases. Leave as is; enable only if you see repeated network errors.

## Actor input object example

```json
{
  "keywords": "cybersecurity",
  "noticeTypes": [
    "o",
    "k",
    "p",
    "r"
  ],
  "naicsCodes": [
    "541512",
    "541511"
  ],
  "pscCodes": [
    "R425"
  ],
  "agencies": [
    "Department of Veterans Affairs"
  ],
  "states": [
    "VA",
    "MD"
  ],
  "postedWithinDays": 30,
  "openForResponsesOnly": false,
  "activeOnly": true,
  "sortBy": "-relevance",
  "includeDescription": true,
  "includeAttachments": true,
  "compactOutput": false,
  "maxResults": 10,
  "onlyNewSinceLastRun": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `opportunities` (type: `string`):

One item per SAM.gov notice

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

Counts of saved, skipped and failed notices

## `failed` (type: `string`):

Notices that could not be fetched (not charged)

# 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": "cybersecurity",
    "noticeTypes": [
        "o",
        "k",
        "p",
        "r"
    ],
    "postedWithinDays": 30,
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("artificially/samgov-opportunities-scraper").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": "cybersecurity",
    "noticeTypes": [
        "o",
        "k",
        "p",
        "r",
    ],
    "postedWithinDays": 30,
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("artificially/samgov-opportunities-scraper").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": "cybersecurity",
  "noticeTypes": [
    "o",
    "k",
    "p",
    "r"
  ],
  "postedWithinDays": 30,
  "maxResults": 10
}' |
apify call artificially/samgov-opportunities-scraper --silent --output-dataset

```

## MCP server setup

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

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/7lcA7vUNatOCPoPZx/builds/V9cQ4JvSnf8ZluzwO/openapi.json
