# Grants.gov Opportunity Monitor — New Funding Alerts, No Login (`flamboyant_liner/grants-opportunity-monitor`) Actor

Watch Grants.gov by keyword, agency, eligibility and category and get only NEW or changed federal funding opportunities: deadline, award ceiling, expected awards, eligible applicants, contact. Daily schedule. No login. MCP-ready. $10 per 1,000 alerts.

- **URL**: https://apify.com/flamboyant\_liner/grants-opportunity-monitor.md
- **Developed by:** [Khrystyna Skotte](https://apify.com/flamboyant_liner) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 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.

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

## Grants.gov Opportunity Monitor

Schedule this actor daily and get **only the new or changed federal funding opportunities** that match your watch list: keywords, agencies, applicant eligibility, funding category and status. Every alert carries the deadline, days left, award ceiling and floor, estimated total funding, expected number of awards, eligible applicant types, cost-sharing flag, description, program contact email and the Grants.gov link.

It uses the public Grants.gov API. No login, no API key, no proxy.

Built for nonprofit development teams, grant writers, university research offices and consultants who need a feed, not a dump.

### What it does on each run

1. Searches Grants.gov for every keyword you list (newest first, limited to the last `postedSinceDays` days).
2. Keeps only opportunities matching your agency, eligibility, category and status filters.
3. Compares each hit with what it remembered from earlier runs:
   - **new** – never seen by this monitor before
   - **updated** – status changed (a forecast became posted) or the close date changed
4. Fetches the full synopsis for each alert (`includeDetails`), pushes it to the dataset and remembers it.
5. Optionally POSTs the run summary plus the alerts to your webhook.

Unchanged opportunities are never emitted again, so a daily schedule produces a clean stream of alerts.

### Scheduling

Create a Schedule in the Apify console that runs this actor once a day with your filters. The default `postedSinceDays` of 7 gives a safety margin: if a run is skipped, the next run still picks up everything that arrived in between.

If more opportunities match than `maxNewPerKeyword` or `maxItems` allow, the remainder is emitted on the following runs (nothing is lost). Raise the caps if you expect bursts.

### First run: emit all or baseline

- `firstRunMode = emitAll` (default): the first run emits everything currently matching your filters, up to the caps.
- `firstRunMode = baseline`: the first run only records what exists today and emits nothing. From the second run on you get only what is genuinely new. Use this when you already track the existing opportunities elsewhere.

Each `monitorId` has its own memory (stored in a named key-value store `grants-monitor-<hash>`), so you can run several independent watch lists on one account, for example one per program area. Rename the `monitorId` to start over from scratch.

### Webhook

Set `webhookUrl` and the actor sends one JSON POST per run:

```json
{
  "monitorId": "default",
  "runAt": "2026-09-28T20:19:33.651Z",
  "newCount": 3,
  "updatedCount": 1,
  "scanned": 42,
  "seenTotal": 118,
  "baseline": false,
  "opportunities": [ { "...": "up to 50 emitted records" } ]
}
```

Point it at Slack (via an incoming webhook adapter), Zapier, Make, n8n or your own endpoint. The full list of alerts is always in the run's dataset.

### Input

| Field | Default | Notes |
|---|---|---|
| `keywords` | `["youth", "STEM education"]` | Searched one at a time. Multi-word keywords are matched as an exact phrase. To match any of several words, list them as separate keywords. Empty list = all opportunities passing the other filters. |
| `agencies` | `[]` | Agency code prefixes, e.g. `HHS`, `NSF`, `ED`, `USDOJ`, or sub-agencies such as `HHS-ACF`, `USDOJ-OJP-OJJDP`. |
| `eligibilities` | `[]` | Applicant type codes (list below). Several codes are OR-ed. |
| `fundingCategories` | `[]` | Funding activity category codes (list below). Several codes are OR-ed. |
| `statuses` | `["posted", "forecasted"]` | `posted`, `forecasted`, `closed`, `archived`. |
| `postedSinceDays` | `7` | Only opportunities posted within this many days are scanned. |
| `includeDetails` | `true` | Fetch synopsis details for each alert (award amounts, eligibility, description, contact). |
| `maxNewPerKeyword` | `5` | Alerts per keyword per run. |
| `maxItems` | `10` | Alerts per run in total. |
| `firstRunMode` | `emitAll` | `emitAll` or `baseline`. |
| `webhookUrl` | `""` | Optional JSON POST target. |
| `monitorId` | `default` | Name of the watch list; separate memory per id. |

### Output

One record per new or updated opportunity:

```json
{
  "opportunityId": "363961",
  "opportunityNumber": "O-OJJDP-2026-172751",
  "title": "OJJDP FY 2026 Second Chance Act Youth Reentry Program",
  "agencyCode": "USDOJ-OJP-OJJDP",
  "agencyName": "Office of Juvenile Justice Delinquency Prevention",
  "status": "posted",
  "postedDate": "2026-09-25",
  "closeDate": "2026-11-02",
  "daysUntilClose": 35,
  "cfdaNumbers": ["16.812"],
  "fundingInstrument": "Grant",
  "fundingCategory": "Law, Justice and Legal Services",
  "eligibleApplicants": ["Nonprofits having a 501(c)(3) status with the IRS, other than institutions of higher education", "City or township governments", "County governments", "State governments"],
  "awardCeiling": 750000,
  "awardFloor": 0,
  "expectedAwards": 16,
  "estimatedTotalFunding": 12440720,
  "costSharing": false,
  "description": "This is a notice of funding opportunity (NOFO) for the OJJDP FY 2026 Second Chance Act Youth Reentry Program...",
  "contactEmail": "OJP.ResponseCenter@usdoj.gov",
  "grantsUrl": "https://www.grants.gov/search-results-detail/363961",
  "matchedKeyword": "youth",
  "changeType": "new",
  "firstSeenAt": "2026-09-28T20:19:33.651Z",
  "monitorId": "default"
}
```

Forecasted opportunities have no firm close date yet; `closeDate` then holds the agency's estimated application deadline when one is published, otherwise `null`. Award ceiling and floor are `null` when the agency did not publish them (common for NIH notices) and `0` when the agency entered zero.

The run's key-value store also holds a `SUMMARY` record with the counts shown in the webhook payload.

### Code lists

#### Applicant eligibility codes (`eligibilities`)

| Code | Applicant type |
|---|---|
| `00` | State governments |
| `01` | County governments |
| `02` | City or township governments |
| `04` | Special district governments |
| `05` | Independent school districts |
| `06` | Public and State controlled institutions of higher education |
| `07` | Native American tribal governments (Federally recognized) |
| `08` | Public housing authorities / Indian housing authorities |
| `11` | Native American tribal organizations (other than Federally recognized tribal governments) |
| `12` | Nonprofits having a 501(c)(3) status with the IRS, other than institutions of higher education |
| `13` | Nonprofits that do not have a 501(c)(3) status with the IRS, other than institutions of higher education |
| `20` | Private institutions of higher education |
| `21` | Individuals |
| `22` | For profit organizations other than small businesses |
| `23` | Small businesses |
| `25` | Others (see "Additional Information on Eligibility" in the notice) |
| `99` | Unrestricted (open to any type of entity above) |

#### Funding activity category codes (`fundingCategories`)

| Code | Category |
|---|---|
| `AG` | Agriculture |
| `AR` | Arts |
| `BC` | Business and Commerce |
| `CD` | Community Development |
| `CP` | Consumer Protection |
| `DPR` | Disaster Prevention and Relief |
| `ED` | Education |
| `ELT` | Employment, Labor and Training |
| `EN` | Energy |
| `ENV` | Environment |
| `FN` | Food and Nutrition |
| `HL` | Health |
| `HO` | Housing |
| `HU` | Humanities |
| `ISS` | Income Security and Social Services |
| `IS` | Information and Statistics |
| `IIJ` | Infrastructure Investment and Jobs Act (IIJA) |
| `LJL` | Law, Justice and Legal Services |
| `NR` | Natural Resources |
| `OZ` | Opportunity Zone Benefits |
| `O` | Other |
| `RT` | Recreation and Tourism |
| `RD` | Regional Development |
| `ST` | Science and Technology and other Research and Development |
| `T` | Transportation |

#### Top-level agency codes (`agencies`)

`AC` AmeriCorps · `USDA` Agriculture · `DOC` Commerce · `DOD` Defense · `ED` Education · `DOE` Energy · `PAMS` Energy Office of Science · `HHS` Health and Human Services · `DHS` Homeland Security · `HUD` Housing and Urban Development · `USDOJ` Justice · `DOL` Labor · `DOS` State · `DOI` Interior · `USDOT` Treasury · `DOT` Transportation · `VA` Veterans Affairs · `EPA` Environmental Protection Agency · `IMLS` Institute of Museum and Library Services · `LOC` Library of Congress · `MCC` Millennium Challenge Corporation · `NASA` · `NEA` National Endowment for the Arts · `NEH` National Endowment for the Humanities · `NSF` National Science Foundation

Sub-agency codes are the prefix plus a suffix, for example `HHS-ACF` (Administration for Children and Families), `HHS-NIH11` (NIH), `HHS-CDC-NCCDPHP`, `USDOJ-OJP-OJJDP`, `USDA-NIFA`, `DOD-ONR`. The agency code of every alert is in `agencyCode`, so you can refine after a first run.

### Pricing

Pay per event: $0.005 per run start plus $0.01 per alert emitted. A daily monitor with a handful of new matches per day costs well under $1 per month. Runs that find nothing new cost only the start fee.

### Typical setups

- **Youth-serving 501(c)(3)**: `keywords` `["youth", "mentoring", "after school"]`, `eligibilities` `["12"]`, daily.
- **University research office**: `keywords` `[]`, `agencies` `["NSF", "HHS-NIH11", "DOE"]`, `eligibilities` `["06"]`, `maxItems` `200`, daily.
- **Community health center**: `keywords` `["community health", "behavioral health"]`, `fundingCategories` `["HL"]`, `agencies` `["HHS"]`, daily with a Slack webhook.

# Actor input Schema

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

Search terms run one at a time against Grants.gov (title, description, number). Each emitted row carries the keyword that matched it. Leave empty to monitor every opportunity that passes the other filters.

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

Agency code prefixes to keep, e.g. HHS, NSF, ED, USDOJ, USDA, DOD, or a sub-agency like HHS-ACF or USDOJ-OJP-OJJDP. Matched against the opportunity's agency code. Empty = all agencies.

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

Grants.gov eligibility codes, e.g. 12 (501(c)(3) nonprofits), 13 (other nonprofits), 00 (state governments), 01 (county), 02 (city), 05 (school districts), 06 (public universities), 20 (private universities), 07 (federally recognized tribes), 23 (small businesses), 99 (unrestricted). Full list in the README. Empty = any.

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

Category codes, e.g. ED (Education), HL (Health), ST (Science & Technology), CD (Community Development), ISS (Income Security & Social Services), AR (Arts), ENV (Environment), LJL (Law & Justice). Full list in the README. Empty = any.

## `statuses` (type: `array`):

Which statuses to watch: posted (open for applications), forecasted (announced, not yet open), closed, archived. A forecast that becomes posted is emitted again as an update.

## `postedSinceDays` (type: `integer`):

Only scan opportunities posted in the last N days. Keep a little longer than your schedule interval (daily schedule → 7 days) so nothing slips through.

## `includeDetails` (type: `boolean`):

Fetch the full synopsis for every emitted row: award ceiling/floor, estimated funding, number of awards, eligible applicant types, cost sharing, description and contact email. One extra request per row.

## `maxNewPerKeyword` (type: `integer`):

Cap on new/updated opportunities emitted per keyword per run. Newest posted first.

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

Overall cap on rows emitted per run across all keywords.

## `firstRunMode` (type: `string`):

emitAll: the first run emits everything currently matching (up to the caps). baseline: the first run only records what exists so later runs emit only what is genuinely new.

## `webhookUrl` (type: `string`):

Optional. After each run a single JSON POST is sent here with the run summary and up to 50 emitted opportunities (Slack/Zapier/Make/your API).

## `monitorId` (type: `string`):

Name of this watch list. Each monitorId keeps its own memory of seen opportunities, so you can run several independent monitors on one account.

## Actor input object example

```json
{
  "keywords": [
    "youth",
    "STEM education"
  ],
  "agencies": [],
  "eligibilities": [],
  "fundingCategories": [],
  "statuses": [
    "posted",
    "forecasted"
  ],
  "postedSinceDays": 7,
  "includeDetails": true,
  "maxNewPerKeyword": 5,
  "maxItems": 10,
  "firstRunMode": "emitAll",
  "webhookUrl": "",
  "monitorId": "default"
}
```

# Actor output Schema

## `records` (type: `string`):

Dataset of new or updated Grants.gov funding opportunities found in this run (JSON).

# 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": [
        "youth",
        "STEM education"
    ],
    "agencies": [],
    "eligibilities": [],
    "fundingCategories": [],
    "statuses": [
        "posted",
        "forecasted"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("flamboyant_liner/grants-opportunity-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": [
        "youth",
        "STEM education",
    ],
    "agencies": [],
    "eligibilities": [],
    "fundingCategories": [],
    "statuses": [
        "posted",
        "forecasted",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("flamboyant_liner/grants-opportunity-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": [
    "youth",
    "STEM education"
  ],
  "agencies": [],
  "eligibilities": [],
  "fundingCategories": [],
  "statuses": [
    "posted",
    "forecasted"
  ]
}' |
apify call flamboyant_liner/grants-opportunity-monitor --silent --output-dataset

```

## MCP server setup

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