# SAM.gov Scraper: Federal Contract Opportunities, RFPs & Awards (`jdepablos/sam-gov-opportunities-scraper`) Actor

Every active US federal contract opportunity from the official SAM.gov daily data file: RFPs, solicitations, sources sought and award notices with winner and amount. Filter by NAICS, PSC, set-aside, agency, state and dates. No API key. Scheduled runs can return only new notices.

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

## Pricing

$2.00 / 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 Scraper: Federal Contract Opportunities, RFPs & Awards

Pull US federal contract opportunities out of SAM.gov as clean JSON: solicitations, RFPs, sources sought, presolicitations, special notices and award notices with the winning company and the amount. Filter by NAICS, PSC, set-aside, agency, state and dates, and put it on a schedule to get only the notices that are new since your last run.

It reads the official Contract Opportunities data file that SAM.gov publishes every day for download. You don't need a SAM.gov account or an API key, and there is no 10-requests-a-day quota to work around.

### What you get

One record per notice, newest first:

```json
{
  "noticeId": "100a46c843554098a99dc8f47e4fec3b",
  "solicitationNumber": "75150PR260000082",
  "title": "PACAREA Battle Watch Command Center Display System (CCDS)",
  "type": "Award Notice",
  "baseType": "Combined Synopsis/Solicitation",
  "postedDate": "2026-09-25T22:11:27",
  "firstPostedDate": "2026-09-25T22:11:27",
  "versionCount": 1,
  "responseDeadline": null,
  "archiveDate": "2026-10-10",
  "naicsCode": "541512",
  "pscCode": "5895",
  "setAsideCode": "SBA",
  "setAside": "Small Business Set Aside - Total",
  "department": "HOMELAND SECURITY, DEPARTMENT OF",
  "subTier": "US COAST GUARD",
  "office": "LOG-9",
  "placeOfPerformance": { "street": null, "city": "Alameda", "state": "CA", "zip": "94501", "country": "USA" },
  "award": {
    "number": "70Z08426PDL940061",
    "date": "2026-09-25",
    "amount": 242941.62,
    "awardee": "CREATION NETWORKS, INC. Concord CA 94518 USA"
  },
  "url": "https://sam.gov/opp/100a46c843554098a99dc8f47e4fec3b/view",
  "source": "SAM.gov Contract Opportunities public data extract, U.S. General Services Administration (https://sam.gov/data-services). Reformatted by this Actor; the notice on SAM.gov is the authoritative version.",
  "extractUpdatedAt": "2026-09-27T03:30:52.000Z"
}
```

Records also carry the office address, the CGAC, FPDS and AAC codes, the archive type and the additional info link when SAM.gov has them. Turn on **Include the description** to get the full notice text.

### Examples

**New IT work in the last week**

```json
{ "naicsCodes": ["541512", "541519"], "postedWithinDays": 7 }
```

**Cybersecurity notices you can still answer**

```json
{ "keywords": ["cybersecurity", "zero trust"], "openForBidsOnly": true }
```

Keywords are matched in the title by default. Set **Search keywords in** to title and description to search the notice text as well; you get many more notices, but a lot of them only mention the word in standard contract clauses.

**Who won Navy construction contracts**

```json
{ "noticeTypes": ["Award Notice"], "agencies": ["NAVY"], "naicsCodes": ["2362"] }
```

**Small business set-asides in Texas, daily, only what is new**

```json
{ "setAsides": ["SBA", "SDVOSBC", "WOSB"], "states": ["TX"], "onlyNew": true }
```

### Only new notices on a schedule

Turn on **Only notices new since the last run** and schedule the Actor (daily is enough, the file changes once a day). The first run returns what matches today and remembers all of it. After that, each run returns only notices that were not there before, so you pay once per notice. If a run finds more new notices than **Max notices**, the rest come in the next run instead of being skipped.

The memory is kept per set of filters in a key-value store in your own Apify account. Changing any filter starts a fresh search with its own first run. Max notices and the description switch are not part of the search, so you can change them freely.

### Amendments

SAM.gov publishes every amendment as a new notice with its own ID. In the file of 27 September 2026, 36% of the rows were older versions of a notice still in the file. By default you get one row per notice, the newest version, with `versionCount` and `firstPostedDate` so you can see it was amended. A notice is the same notice when the department, the solicitation number and the notice type match. Award notices are never merged, because a single solicitation can have thousands of separate awards (the GSA Multiple Award Schedule has more than 6,800). Turn off **Latest version only** to get every version as its own row.

With **Only notices new since the last run**, an amendment of a notice you already have is not new. A presolicitation that becomes a solicitation, or a solicitation that gets its award notice, is.

### Contact details are not included

SAM.gov notices list the name, email and phone number of the contracting officers. This Actor does not return those fields. If you turn on the description, email addresses and phone numbers are removed from the text, but a name written inside a sentence can still appear. Every notice has a link to its page on SAM.gov, where the contacts are published.

### How fresh is it

SAM.gov rebuilds the file once a day, around 03:30 UTC, weekends included. Each record says which file it came from in `extractUpdatedAt`. A notice posted after that time shows up the next day. On weekdays SAM.gov gets roughly 1,000 to 1,700 new solicitations, presolicitations and sources sought a day.

The file only holds notices that are still active, about 80,000 of them. For archived notices from past years, use SAM.gov's own search or the historical files in Data Services.

### Pricing

You pay per notice delivered, $2 per 1,000 notices. A run that finds nothing costs nothing, and with only new notices on you never pay twice for the same one. Downloading and reading the whole file takes between 10 seconds and 2 minutes.

### Data source

The data comes from the Contract Opportunities extract at [sam.gov/data-services](https://sam.gov/data-services), published by the U.S. General Services Administration. SAM.gov's terms of use say its data is made available through its APIs and data extracts, and they prohibit automated scraping of the website. This Actor uses the extract and nothing else. It is not affiliated with or endorsed by GSA or SAM.gov.

# Actor input Schema

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

Words or phrases to find in the notice. A notice matches if it contains ANY of them, as a whole word or phrase and ignoring case, so "cloud" does not match "Cloudflare". Example: "cybersecurity", "janitorial", "body armor".

## `keywordScope` (type: `string`):

Title only is precise. Title and description finds far more (for "software" on 27 September 2026: 266 notices by title, 2,030 with the description), but many of the extra ones only mention the word in standard clauses.

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

Industry codes, matched as a prefix: "5415" covers 541511, 541512, 541519 and the rest of that family. Example: "541512" (computer systems design), "236220" (commercial building construction).

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

Federal product and service codes, matched as a prefix: "D3" covers every IT and telecom service code that starts with D3.

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

Leave empty for every type. Award notices carry the winning company, the amount and the award date.

## `setAsides` (type: `array`):

Small business programs. Leave empty for all, including notices without a set-aside.

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

Part of the department, sub-tier or office name, ignoring case. Example: "VETERANS AFFAIRS", "NAVY", "US COAST GUARD".

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

Two-letter state codes where the work is done: VA, TX, CA. Most notices do not state a place of performance, so this filter drops them.

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

Only notices posted in the last N days. Handy for scheduled runs because it moves with the calendar. Empty means any date.

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

Only notices posted on or after this date.

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

Only notices posted on or before this date.

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

Only notices whose response deadline is on or after this date. Notices without a deadline are left out.

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

Only notices whose response deadline is on or before this date. Notices without a deadline are left out.

## `openForBidsOnly` (type: `boolean`):

Only notices whose response deadline has not passed yet. Notices without a deadline, such as most award notices, are left out.

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

Skip notices whose archive date has already passed. The daily file keeps some of them for a few days.

## `latestVersionOnly` (type: `boolean`):

SAM.gov publishes every amendment as a separate notice: about a third of the daily file are older versions. On, you get one row per notice (the newest version) with versionCount and firstPostedDate. Off, you get every version. Award notices are never merged.

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

Adds the full notice text. Email addresses and phone numbers in it are removed.

## `onlyNew` (type: `boolean`):

For scheduled runs. The first run returns what matches today and remembers it; later runs with the same filters return only notices that were not there before, so you only pay for new ones. Changing any filter starts a new search.

## `maxItems` (type: `integer`):

Upper limit of notices returned in one run, newest first.

## Actor input object example

```json
{
  "keywordScope": "title",
  "naicsCodes": [
    "541512"
  ],
  "postedWithinDays": 7,
  "openForBidsOnly": false,
  "activeOnly": true,
  "latestVersionOnly": true,
  "includeDescription": false,
  "onlyNew": false,
  "maxItems": 100
}
```

# Actor output Schema

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

One record per notice, newest first.

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

Date of the SAM.gov file used, rows scanned, notices matched, delivered and charged, and for only-new runs how many were new.

# 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 = {
    "naicsCodes": [
        "541512"
    ],
    "postedWithinDays": 7,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("jdepablos/sam-gov-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 = {
    "naicsCodes": ["541512"],
    "postedWithinDays": 7,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("jdepablos/sam-gov-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 '{
  "naicsCodes": [
    "541512"
  ],
  "postedWithinDays": 7,
  "maxItems": 100
}' |
apify call jdepablos/sam-gov-opportunities-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jdepablos/sam-gov-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/yE12KIabfe90y8rUI/builds/yinznRhrl5UkpcsGi/openapi.json
