# Grants.gov Opportunity Scraper (`publicmoney/grants-gov-scraper`) Actor

Extract US federal grant opportunities from Grants.gov: opportunity number, title, agency, open and close dates, status, Assistance Listings, award ceiling and floor, estimated funding, eligibility, contacts and the full opportunity record.

- **URL**: https://apify.com/publicmoney/grants-gov-scraper.md
- **Developed by:** [Public Money](https://apify.com/publicmoney) (Apify)
- **Categories:** Business
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 grants

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

This Actor reads US federal grant opportunities from Grants.gov through its public REST API. It returns one record per opportunity — forecasted, posted, closed or archived — with the search row, the main detail fields flattened into columns, and the full opportunity record as Grants.gov publishes it. No API key is needed.

### Source

- Search: `POST https://api.grants.gov/v1/api/search2` (JSON body).
- Detail: `POST https://api.grants.gov/v1/api/fetchOpportunity` with `{"opportunityId": <id>}`, one call per opportunity when **Fetch opportunity details** is on.
- Size on 2026-10-04: 859 posted, 610 forecasted, 8,697 closed, 73,354 archived (83,520 in all).

### Input

Every filter is applied by Grants.gov itself. Each one was checked on 2026-10-04 to change the result, and a nonsense value to return nothing.

| Field | Type | Default | What it controls |
| --- | --- | --- | --- |
| `oppStatuses` | array | `["forecasted", "posted"]` | forecasted, posted, closed, archived |
| `keyword` | string | empty | Full-text search (`cancer` → 98 posted) |
| `agencies` | array | empty | Agency codes: a full code (`HHS-NIH11`, `NSF`) or a department wildcard (`DOD-*`) |
| `eligibilities` | array | empty | Eligible applicant type codes; several match any |
| `fundingInstruments` | array | empty | `G` grant, `CA` cooperative agreement, `PC` procurement contract, `O` other |
| `fundingCategories` | array | empty | Funding activity category codes (`ED`, `HL`, `ST`, …) |
| `cfda` | string | empty | One Assistance Listing number (`93.213`) |
| `oppNum` | string | empty | Exact opportunity number (`PAR-25-274`) |
| `postedWithinDays` | integer | empty | Posted within the last N days |
| `sortBy` | string | source default | Posted date, close date, opportunity number or agency, either direction |
| `fetchDetails` | boolean | `true` | One detail call per opportunity for description, money, eligibility, contacts and the full record |
| `maxItems` | integer | `100` | Cap on records written, and so on cost; `0` for everything matched |
| `schemaOrg` | boolean | `false` | Appends a schema.org `MonetaryGrant` block to each record |

```json
{
    "oppStatuses": ["posted"],
    "keyword": "cancer",
    "agencies": ["HHS-*"],
    "postedWithinDays": 56,
    "maxItems": 100
}
```

### Output

| Group | Fields |
| --- | --- |
| Search row | `id`, `number`, `title`, `agencyCode`, `agency`, `openDate`, `closeDate`, `openDateIso`, `closeDateIso`, `oppStatus`, `docType`, `cfdaList`, `opportunityUrl` |
| Description | `synopsisDesc` (posted, closed, archived), `forecastDesc` (forecasts), `opportunityCategory`, `topAgencyName` |
| Dates | `postingDate`, `responseDate`, `archiveDate`, `lastUpdatedDate`; forecasts also `estApplicationResponseDate`, `estAwardDate`, `estProjectStartDate`, `fiscalYear` |
| Money | `awardCeiling`, `awardFloor`, `estimatedFunding`, `numberOfAwards`, `costSharing` |
| Eligibility | `applicantTypes`, `applicantEligibilityDesc`, `fundingInstruments`, `fundingActivityCategories` |
| Contact | `agencyContactName`, `agencyContactEmail`, `agencyContactPhone`, `fundingDescLinkUrl` |
| Full record | `opportunityDetail` — every field `fetchOpportunity` returns, unchanged: synopsis or forecast, agency details, Assistance Listings, packages, attachments, revision history |

```json
{
    "id": "357305",
    "number": "PAR-25-274",
    "title": "Feasibility Clinical Trials of Mind and Body Interventions for NCCIH High Priority Research Topics (R34 Clinical Trial Required)",
    "agencyCode": "HHS-NIH11",
    "agency": "National Institutes of Health",
    "openDate": "11/21/2024",
    "closeDate": "11/17/2026",
    "oppStatus": "posted",
    "docType": "synopsis",
    "cfdaList": ["93.213"],
    "opportunityUrl": "https://www.grants.gov/search-results-detail/357305",
    "awardCeiling": "none",
    "awardFloor": "none",
    "costSharing": false,
    "fundingInstruments": ["Grant"],
    "agencyContactEmail": "grantsinfo@nih.gov"
}
```

### Gotchas

- With no status selected Grants.gov returns forecasted and posted only. Closed and archived have to be asked for.
- A bare department code such as `DOD` or `HHS` in `agencies` matches nothing; use `DOD-*` or a full agency code.
- `cfda` takes one number; a pipe-joined list matches nothing at source.
- Money fields are the strings Grants.gov publishes, including `"none"` and `"0"`; they are not converted.
- Forecasts carry a `forecast` object and no close date in the search row; their date and money fields come from the forecast.
- `opportunityUrl` is composed from the opportunity id: Grants.gov's own site routes `/search-results-detail/<id>` to that opportunity, and the API publishes no page link of its own.
- With `fetchDetails` off, only the search-row fields are populated.

# Actor input Schema

## `oppStatuses` (type: `array`):

Which opportunity statuses to return. Forecasted and posted are open or upcoming; closed and archived are past. Default is forecasted and posted.

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

Full-text search run by Grants.gov itself. Examples: 'cancer', 'broadband'. Leave empty to keep every opportunity.

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

Grants.gov agency codes. Use a full code such as 'HHS-NIH11' or 'NSF', or a department prefix with a wildcard such as 'DOD-*' or 'HHS-*'. A bare department code such as 'DOD' matches nothing at source. Leave empty for all agencies.

## `eligibilities` (type: `array`):

Applicant types the opportunity is open to. Several values match any of them. Leave empty for all.

## `fundingInstruments` (type: `array`):

Grant, cooperative agreement, procurement contract or other. Leave empty for all.

## `fundingCategories` (type: `array`):

Category of funding activity. Several values match any of them. Leave empty for all.

## `cfda` (type: `string`):

One Assistance Listing number. Examples: '93.213', '93.855'. The source accepts a single number only. Leave empty for all.

## `oppNum` (type: `string`):

Exact funding opportunity number. Example: 'PAR-25-274'. Leave empty for all.

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

Only opportunities posted in the last N days. Examples: 7, 30, 365. Leave empty or 0 for any date.

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

Order of results. Leave empty for the source's default order.

## `fetchDetails` (type: `boolean`):

Call the detail endpoint for every opportunity to get the description, award ceiling and floor, estimated funding, eligibility, contacts and the full opportunity record. One extra request per opportunity. Default is true.

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

Caps how many opportunities are written to the dataset, and so caps the cost. Examples: 10, 100, 5000. Set to 0 for everything matched. Default is 100.

## `schemaOrg` (type: `boolean`):

Appends a `schemaOrg` object to the end of every record, mapping it to schema.org (Demand for tenders, MonetaryGrant for grants, Invoice for payments). The record's own fields are not changed. Off by default. Charged once per run, not per record.

## Actor input object example

```json
{
  "oppStatuses": [
    "forecasted",
    "posted"
  ],
  "fetchDetails": true,
  "maxItems": 100,
  "schemaOrg": false
}
```

# Actor output Schema

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

Grant opportunities matched by the run, one item per record, in the default dataset.

# 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 = {
    "oppStatuses": [
        "forecasted",
        "posted"
    ],
    "fetchDetails": true,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicmoney/grants-gov-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 = {
    "oppStatuses": [
        "forecasted",
        "posted",
    ],
    "fetchDetails": True,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("publicmoney/grants-gov-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 '{
  "oppStatuses": [
    "forecasted",
    "posted"
  ],
  "fetchDetails": true,
  "maxItems": 100
}' |
apify call publicmoney/grants-gov-scraper --silent --output-dataset

```

## MCP server setup

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