# USAspending API Scraper: Federal Contract Awards, Grant Monitor (`neverempty/usaspending-awards-monitor`) Actor

For government contractors and competitor research: federal spending from the USAspending API, contract awards and grants with recipient, obligated amount, agency, dates, NAICS and PSC, one row per award. Filter by keyword, recipient, agency, NAICS, state, amount; monitoring returns only new awards.

- **URL**: https://apify.com/neverempty/usaspending-awards-monitor.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 award returneds

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

## USAspending API Scraper: Federal Contract Awards, Grant Monitor

**Federal contract awards and grants from USAspending.gov, one row per award, with a monitoring mode that returns only the awards that were not there at your last run.** Use it to see which agency awarded what to a competitor, or to get the new contracts in your NAICS code, PSC code, state or keyword every morning.

This Actor reads the **official public USAspending API** (`api.usaspending.gov`, run by the U.S. Department of the Treasury). No API key. No proxy. No browser. One request at a time, at most one per second.

Each row holds the award ID, award type, recipient name and UEI, obligated amount, awarding and funding agency and sub-agency, award date, start and end date, NAICS and PSC code with their names (or the assistance listing for grants), the description, the place of performance, the recipient location and the link to the award page on USAspending.gov.

### What this Actor gets right (measured on 2026-10-05)

#### 1. "New award" means the award date, not the start date

The `Start Date` on USAspending is the start of the period of performance. It is often in the future: of the 1,560 Department of Homeland Security contracts first awarded from 2026-09-24 to 2026-09-30, 96 had a start date after 2026-09-30. Sorting or filtering by start date therefore mixes old and new awards.

This Actor filters with the API's "new awards only" date type (the date of the first transaction of the award), returns that date as `awardDate`, and sorts newest first. `startDate` and `endDate` are returned as separate columns.

#### 2. Monitoring compares award IDs, because awards arrive late

Awards do not reach USAspending on the day they are signed. Department of Defense contracts are published about 90 days late: on 2026-10-05 the API held 12 Department of Defense contracts first awarded in the previous 15 days, and 115,546 for 2026-06-20 to 2026-07-05. A monitor that only asks "what was awarded since yesterday" never sees them.

Monitoring mode reads every matching award first awarded in the last 120 days (you can change the window), compares the USAspending award IDs with the IDs it remembers, and returns only the awards that are new to the list, whenever their award date was.

#### 3. A mistyped agency does not come back as "no awards"

The API matches agency names exactly, including upper and lower case. `department of defense` returns 0 awards with HTTP 200, the same answer as an agency that awarded nothing. Unknown filter names are ignored silently and return everything.

This Actor checks each agency you enter against the official list of top-tier agencies, accepts the full name or the abbreviation (`DHS`, `dhs`, `Department of Homeland Security`) in any case, and stops with a row that names the entry it could not find. State codes, NAICS codes, dates and keywords are checked before anything is read. A search the API rejects is reported with the API's own reason, not as an empty result.

#### 4. The filters were compared with a local recount

All 1,560 Department of Homeland Security contracts first awarded from 2026-09-24 to 2026-09-30 were read without other filters (16 pages, no award twice, the same count as the API's count endpoint) and filtered locally. Then the same filters were sent to the API through this Actor's query builder: NAICS (6, 4 and 2 digits), PSC, place of performance state, recipient state, minimum, maximum and range of amount, and a combination. **12 filter cases, 0 differences** in the set of award IDs. Several keywords, and several recipient names, return the awards that match any one of them (checked against the single-entry answers). The check is in the repository as `test/live-query-check.mjs`.

Four rows were also compared with the award detail endpoint: recipient, amount, NAICS, PSC, state, agency and dates were the same, and `awardAmount` equals the detail's `total_obligation`.

### What one row looks like

A real row from 2026-10-05 (keyword `cybersecurity`, agencies `dhs` and `Department of Defense`, last 30 days):

| Field | Value |
|---|---|
| `awardId` | `70T05026F5900N033` |
| `awardType` | `DELIVERY ORDER` |
| `recipientName` / `recipientUei` | `CMA TECHNOLOGY INC` / `PG4AHPP8MDN6` |
| `awardAmount` | `958748.7` |
| `awardingAgency` / `awardingSubAgency` | `Department of Homeland Security` / `Transportation Security Administration` |
| `awardDate` / `startDate` / `endDate` | `2026-09-30` / `2026-09-30` / `2027-09-29` |
| `naicsCode` / `naicsDescription` | `541519` / `OTHER COMPUTER RELATED SERVICES` |
| `pscCode` | `7B22` |
| `placeOfPerformanceCity` / `placeOfPerformanceState` | `VIENNA` / `VA` |
| `usaspendingUrl` | `https://www.usaspending.gov/award/CONT_AWD_70T05026F5900N033_7013_NNG15SD71B_8000` |
| `searchedFor` | `type=contracts; new-awards 2026-09-05..2026-10-05; keywords=cybersecurity; agency=Department of Homeland Security \| Department of Defense` |

Other columns: `awardCategory`, `totalOutlays`, `fundingAgency`, `fundingSubAgency`, `lastDateToOrder` (IDVs), `lastModifiedAt`, `pscDescription`, `assistanceListing` and `assistanceListingTitle` (grants, direct payments, loans, other assistance), `subsidyCost` (loans), `description`, `placeOfPerformanceCountry`, `placeOfPerformanceZip`, `recipientCity`, `recipientState`, `recipientCountry`, `recipientZip`, `generatedInternalId`, `change`, `previousCheckedAt`, `status`, `scrapedAt`.

`awardAmount` is the amount obligated so far (for loans, the loan value). It is not the potential ceiling of the contract, and it can be 0 for a new order with no obligation yet. Recipients of some direct payments are published by USAspending as `REDACTED DUE TO PII`.

### Input

| Field | What it does |
|---|---|
| `keywords` | Words or phrases searched by USAspending in the award text. Any one entry may match. At least 3 characters each. |
| `awardType` | `contracts` (default), `idvs`, `grants`, `direct-payments`, `loans` or `other`. The API searches one group per request, so one run covers one group. |
| `recipientNames` | Text searched in the recipient name, UEI and DUNS. Any one entry may match. |
| `agencies` | Top-tier awarding agencies by full name or abbreviation. Checked against the official list. |
| `naicsCodes` | NAICS codes with 2, 4 or 6 digits. Contracts and IDVs. |
| `pscCodes` | Product or service codes. Contracts and IDVs. |
| `placeOfPerformanceStates` | Two-letter state or territory codes of the place of performance. |
| `recipientStates` | Two-letter state or territory codes of the recipient address. |
| `minAmount`, `maxAmount` | Range of the award amount in dollars. |
| `awardedInLastDays` | Awards dated in the last N days. Or use `dateFrom` and `dateTo`. With no date, every award since 2007-10-01 matches. |
| `dateType` | `new-awards` (default: the first transaction is in the range), `action-date` (the award had a transaction in the range, which includes modifications of older awards) or `last-modified`. |
| `maxAwards` | Most rows to return with monitoring off (default 200, up to 10,000). |
| `monitoringMode` | Return only awards that were not there at the last run with the same filters. |
| `monitorLookbackDays` | The window monitoring compares (default 120 days, 7 to 365). |
| `resetMonitoringState` | Forget what is remembered for these filters and start over. |

All filters that are set must match. Within one filter, any one entry may match.

Example: new IT services contracts performed in Virginia, DC or Maryland in the last 30 days, at least $100,000.

```json
{
    "awardType": "contracts",
    "naicsCodes": ["5415"],
    "placeOfPerformanceStates": ["VA", "DC", "MD"],
    "minAmount": 100000,
    "awardedInLastDays": 30,
    "maxAwards": 500
}
```

Example: watch what one competitor wins from the Department of Homeland Security, on a daily schedule.

```json
{
    "recipientNames": ["GUIDEHOUSE"],
    "agencies": ["DHS"],
    "monitoringMode": true
}
```

### Monitoring mode

1. **First run with a set of filters**: the matching awards first awarded in the lookback window are remembered. No award row is returned and nothing is charged. The run returns one row with `status: baseline-saved`. To get the awards that are published now, run once with monitoring off.
2. **Each later run with the same filters**: the window is read again and compared by USAspending award ID. Only awards that were not there before are returned, with `change: new-award` and `previousCheckedAt`.
3. **A run that finds nothing new** returns one row with `status: no-new-awards` and is charged one check instead of award rows.

What to know:

- Memory is kept per set of filters (award type, keywords, recipients, agencies, codes, states, amounts and lookback window). Changing any of them starts a new memory with a first run.
- The date inputs are not used in monitoring mode.
- A monitored search must match fewer than 10,000 awards in the window, because one USAspending search pages 10,000 awards deep. Each run first asks USAspending for the number of matching awards in one request; a broader search stops there with `status: search-too-broad` and nothing is charged or remembered. All contracts of all agencies is far too broad (about 164,000 new contracts were first awarded in the 30 days before 2026-10-05); one agency with a NAICS code, a recipient or a keyword is fine.
- Each monitoring run reads the whole window, 100 awards per request, about one second per request. A search matching 2,000 awards takes about 25 seconds.
- An award is remembered only after it was returned and charged. If a run stops at your maximum charge, the awards that were not returned still count as new at the next run.
- "New" means new to USAspending for your search. It includes awards signed weeks ago that were published late.
- USAspending loads new data about once a day, so a daily schedule is enough.
- Two runs with the same filters at the same moment can return the same award twice. Do not schedule them together.

### What is charged

- `award-returned`: each award row in the dataset.
- `search-checked`: one per monitoring run that compared the list and found no new award.

Not charged: the first monitoring run, rows that report a problem or a limit (`status` other than `ok`), invalid input, and runs where USAspending could not be read.

### When a run returns no award

The run always returns at least one row. When there is no award row, the row says why in `status` and `note`:

| `status` | Meaning |
|---|---|
| `no-awards` | USAspending was read and holds no award for the search. |
| `no-new-awards` | Monitoring: nothing new since the last run. |
| `baseline-saved` | Monitoring: first run, the current awards were remembered. |
| `invalid-input` | An input value could not be used (for example an agency that is not on the list). Nothing was read. |
| `request-rejected` | USAspending answered HTTP 400 or 422. The note holds its reason. |
| `source-unreadable` | USAspending did not answer, answered with an error, or the answer did not have the expected form. |
| `source-blocked` | USAspending answered HTTP 403 or 429. The Actor does not retry around it. |
| `search-too-broad` | Monitoring: the search matches 10,000 awards or more in the window. |
| `limit-reached` | More matching awards exist beyond `maxAwards`, or beyond the 10,000 the search pages through. |
| `budget-reached`, `not-read` | The maximum total charge set for the run left no room for more rows. |

### Limits

- Top-tier awarding agencies only. Sub-agencies are returned in each row but cannot be filtered on.
- One award group per run (the API's rule).
- Prime awards only. Sub-awards are not read.
- The search goes back to 2007-10-01 and 10,000 awards deep per search. Narrow the dates or filters to reach older awards.
- Keyword matching is done by USAspending. This Actor does not re-filter the text.
- Awards are published with a delay: about 90 days for Department of Defense contracts, a few days for most other agencies.
- The data is what agencies report to USAspending. This Actor does not correct it.
- The API publishes no request limit in the documents read for this Actor. It was never refused during testing at one request per second.

### Data source

USAspending.gov is the official open data source of federal spending, published by the U.S. Department of the Treasury under the DATA Act. This Actor is not affiliated with or endorsed by the U.S. government.

### Related Actors

- [SAM.gov Opportunities Monitor](https://apify.com/neverempty/sam-gov-opportunities-monitor): open federal contract opportunities before they are awarded, from the official SAM.gov daily file, with monitoring.
- [EU Tender Monitor](https://apify.com/neverempty/eu-tender-monitor): public tenders from the EU's TED, with monitoring.
- [UK Tenders Scraper](https://apify.com/neverempty/uk-tenders-scraper): Contracts Finder and Find a Tender in one table.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

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

Words or phrases searched by USAspending in the award text. An award matches if it matches any one of the entries. Each entry needs at least 3 characters. One per line. Leave empty for no keyword filter.

## `awardType` (type: `string`):

USAspending searches one award group per request, so one run covers one group. Run again with another group to cover more.

## `recipientNames` (type: `array`):

Text searched in the recipient name, UEI and DUNS (for example a competitor name). An award matches if it matches any one of the entries. One per line.

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

Top-tier awarding agencies, by full name ("Department of Homeland Security") or abbreviation ("DHS"). Upper and lower case do not matter. Names are checked against the USAspending agency list before the search; a name that is not on the list stops the run with a row that says so, instead of a silent empty result. One per line.

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

NAICS codes with 2, 4 or 6 digits (541512, or 5415 for the whole group). Contracts and IDVs only. One per line.

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

Product or service codes (for example DA01 or R425). Contracts and IDVs only. One per line.

## `placeOfPerformanceStates` (type: `array`):

Two-letter US state or territory codes of the place where the work is performed (VA, TX, DC ...). One per line.

## `recipientStates` (type: `array`):

Two-letter US state or territory codes of the recipient address. One per line.

## `minAmount` (type: `integer`):

Keep awards whose amount is at least this many dollars. The amount is the total obligated so far (for loans, the loan value), not the potential ceiling of the contract.

## `maxAmount` (type: `integer`):

Keep awards whose amount is at most this many dollars.

## `awardedInLastDays` (type: `integer`):

Keep awards whose date (see "Date to filter on") is within this many days before today (UTC). Use this or the two dates below, not both. Leave all three empty for every award since 2007-10-01. Not used in monitoring mode.

## `dateFrom` (type: `string`):

Start of the date range (YYYY-MM-DD), 2007-10-01 or later. Not used in monitoring mode.

## `dateTo` (type: `string`):

End of the date range (YYYY-MM-DD). Not used in monitoring mode.

## `dateType` (type: `string`):

Which date the range applies to. Only used when a date range is set. The start date of a contract is the start of performance and can be in the future; it is not used for filtering.

## `maxAwards` (type: `integer`):

With monitoring off, at most this many award rows are returned, newest award first. USAspending is read 100 awards per request, one request at a time, at most one per second, and one search pages 10,000 awards deep. Not applied in monitoring mode (every new award is returned).

## `monitoringMode` (type: `boolean`):

Remembers awards between runs, per set of filters. The first run with a set of filters only remembers the matching awards first awarded in the lookback window: nothing is returned and nothing is charged. Each later run reads the matching awards of the window again, compares their USAspending IDs with what it remembers and returns only the awards that were not there before (award-returned). A run that finds no new award is charged one check (search-checked) instead. Awards are compared by ID, not by date, because awards reach USAspending late: Department of Defense contracts appear about 90 days after signing. The date inputs are not used. A monitored search must match fewer than 10,000 awards in the window. Do not run two schedules with the same filters at the same moment.

## `monitorLookbackDays` (type: `integer`):

Monitoring compares the awards whose first transaction is within this many days before today. 120 covers the roughly 90-day delay of Department of Defense contracts. Changing it starts a new memory (a first run) for the filters.

## `resetMonitoringState` (type: `boolean`):

With monitoring on, clears what is remembered for this set of filters before the run, so the run is a first run again: matching awards are remembered and nothing is returned. Use it for one run and turn it off again.

## Actor input object example

```json
{
  "keywords": [
    "cybersecurity"
  ],
  "awardType": "contracts",
  "awardedInLastDays": 30,
  "dateType": "new-awards",
  "maxAwards": 200,
  "monitoringMode": false,
  "monitorLookbackDays": 120,
  "resetMonitoringState": false
}
```

# Actor output Schema

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

One row per federal award from USAspending.gov: award ID, award type, recipient name and UEI, obligated amount, awarding and funding agency, award date, start and end date, NAICS, PSC or assistance listing, description, place of performance, recipient location and the USAspending award page. Runs that could not read USAspending, found no award or no new award, or hit a limit return a row that says so and is 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"
    ],
    "awardedInLastDays": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/usaspending-awards-monitor").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"],
    "awardedInLastDays": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/usaspending-awards-monitor").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"
  ],
  "awardedInLastDays": 30
}' |
apify call neverempty/usaspending-awards-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/usaspending-awards-monitor"
        }
    }
}
```

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/jEanKWK9UG41CB0FF/builds/lvCUiwzxMbUW0RxQx/openapi.json
