# USAspending Scraper - Federal Contracts and Grants (`s-r/usaspending-scraper`) Actor

Search US federal awards: contracts, grants, loans and direct payments. Returns recipient, obligated amount, awarding agency, description, dates and a derived annualised figure from the official USAspending API.

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

## Pricing

from $1.00 / 1,000 run start fees

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

## USAspending Scraper

Search **US federal awards**: contracts, grants, loans and direct payments.
Recipient, obligated amount, awarding agency, what the award is for, its dates,
and where the work happens.

Reads the official **USAspending.gov API**. No key, no login.

### The number everyone reads wrong

`amount` is the **obligated total across the award's whole life**, not annual
spend. This matters more than it sounds.

The largest 2024 contract is a Department of Defense award to Humana for
**$51.3 billion** — running from 2016 to 2025. Second is Lockheed Martin at
**$48.1 billion**. On the headline figures Humana wins comfortably.

Annualised, they are not close in the way you would guess:

| Recipient | Obligated total | Per year |
|---|---|---|
| Humana | $51.3bn | **$5.4bn** |
| Lockheed Martin | $48.1bn | **$2.0bn** |

The gap more than doubles, because the awards run for different lengths. Every
row therefore carries **`amount_per_year`**, the obligated total divided by the
award's actual duration, so awards of different lengths are comparable.

Awards shorter than a month get `null` there rather than an annualised figure,
because dividing a two-week award into a yearly rate invents a number nobody
should quote.

### Pick one award type

Contracts, grants, loans and direct payments are separate worlds with different
economics, and USAspending returns them from the same endpoint. Mixing them
produces a "top recipients" table where a research university's grant sits
beside a defence contractor's weapons programme as though they were the same
thing.

`award_group` picks one. It defaults to contracts.

### Fields

| Field | What it is |
|---|---|
| `recipient` | Company or organisation receiving the award |
| `amount` | Obligated total over the award's life |
| `amount_per_year` | That divided by duration |
| `awarding_agency`, `awarding_sub_agency` | Who awarded it |
| `funding_agency` | Whose budget pays |
| `description` | What it is for |
| `start_date`, `end_date`, `duration_days` | The period |
| `performance_state` | Where the work happens |
| `recipient_state` | Where the recipient is |
| `award_id`, `internal_id`, `url` | Identifiers and the award page |

`performance_state` and `recipient_state` are frequently different, and the gap
is the point when you are asking where federal money physically lands rather
than which state a headquarters sits in.

### Input reference

| Field | Type | Default |
|---|---|---|
| `award_group` | contracts, grants, loans, direct\_payments, idvs | `contracts` |
| `date_from`, `date_to` | YYYY-MM-DD | 2024 |
| `recipient` | company or organisation name | — |
| `agency` | top-tier awarding agency | — |
| `keyword` | free text across the award | — |
| `state` | two-letter place-of-performance state | — |
| `min_amount` | dollars | — |
| `sort` | amount, start date, end date, recipient | amount |
| `order` | desc, asc | desc |
| `limit` | 1-5000 | 100 |
| `retries` | 1-6 | 3 |

Filters combine. A time period is always sent, because the API requires one.

### Why this Actor connects directly

on every `.gov` host tested:

| Route | Result |
|---|---|
| Direct | **HTTP 200** |
| Through a residential proxy | `CONNECT tunnel failed, response 491` |

A 491 on the CONNECT is our proxy refusing to tunnel to the host, not the
government refusing us. USAspending publishes this data for public use, and the
Actor takes it directly at a polite pace.

### Two API details worth knowing

**It is a POST API.** Filters go in a JSON body, not the query string. That is
unusual enough that a GET attempt returns something plausible and wrong.

**The field list must be explicit.** Ask for nothing and you get a small default
set missing most of what is useful, with no indication that anything was
omitted. This Actor always names the fields it wants.

**Pagination is a `hasNext` flag, not a page count.** There is no total to loop
to; the response says whether another page exists.

### Typical uses

- **Government contract intelligence.** Who wins work from which agency, in what
  size, over what period. `amount_per_year` is what makes a league table honest.
- **Competitor tracking.** Filter by `recipient` and follow a company's federal
  business across agencies and years.
- **Market sizing.** Filter by `keyword` and agency to see what a category is
  worth: a 2024 grants search on "climate" surfaces Climate United Fund at
  $6.97 billion.
- **Partner and subcontractor research.** `performance_state` shows where work
  actually happens, which is where local partners are.
- **Budget analysis.** Group by `awarding_agency` and compare periods.

### Notes

An amount is what has been **obligated**, which is money committed. It is not
necessarily money already paid out, and for a long contract it usually is not.

`duration_days` is calculated from the award's own start and end dates. Awards
with missing dates return `null` for both duration and the annualised figure
rather than a guess.

Data covers US federal awards only. State and local procurement is published
elsewhere and is not in this dataset.

# Actor input Schema

## `award_group` (type: `string`):

Contracts, grants, loans, direct payments or IDVs. These are separate worlds and mixing them makes a top-recipients table meaningless, so pick one.

## `date_from` (type: `string`):

Start of the time period, as YYYY-MM-DD.

## `date_to` (type: `string`):

End of the time period, as YYYY-MM-DD.

## `recipient` (type: `string`):

Company or organisation name to search for, for example Lockheed.

## `agency` (type: `string`):

Top-tier agency name, for example Department of Defense.

## `keyword` (type: `string`):

Free-text keyword across the award record, for example climate or cybersecurity.

## `state` (type: `string`):

Two-letter state where the work is performed, for example VA.

## `min_amount` (type: `integer`):

Only awards at or above this obligated amount, in dollars.

## `sort` (type: `string`):

Which field orders the results.

## `order` (type: `string`):

Descending puts the largest or newest first.

## `limit` (type: `integer`):

How many awards to return.

## `retries` (type: `integer`):

Retries with backoff before a request is reported as an error.

## Actor input object example

```json
{
  "award_group": "contracts",
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "sort": "Award Amount",
  "order": "desc",
  "limit": 100,
  "retries": 3
}
```

# Actor output Schema

## `awards` (type: `string`):

One row per federal award.

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

Counts, total obligated amount and the top awarding agencies.

## `errors` (type: `string`):

Failures with a code and a redacted message.

# 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 = {
    "date_from": "2024-01-01",
    "date_to": "2024-12-31",
    "limit": 100,
    "retries": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/usaspending-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 = {
    "date_from": "2024-01-01",
    "date_to": "2024-12-31",
    "limit": 100,
    "retries": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/usaspending-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 '{
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "limit": 100,
  "retries": 3
}' |
apify call s-r/usaspending-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/usaspending-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/kVtfTQ7T2faOKaVfP/builds/ve4fpJIIeIxXklL0g/openapi.json
