# Grant Opportunities Search Scraper (`caffein.dev/grants-actor`) Actor

Search grant opportunities by keyword across NIH RePORTER, Grants.gov, and Duke Research Funding. Returns a unified dataset with titles, sponsors, deadlines, amounts, eligibility, and source URLs. Great for grant discovery, dashboards, and automation.

- **URL**: https://apify.com/caffein.dev/grants-actor.md
- **Developed by:** [Caffein Dev](https://apify.com/caffein.dev) (community)
- **Categories:** Automation, Lead generation, Other
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 basic results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Grants Scraper API (Duke + NIH + Grants.gov)

Search and extract **grant opportunities and funding announcements** from multiple sources and return them in a **single unified JSON output schema**.

Sources currently supported:

- **Duke Research Funding**
- **NIH RePORTER**
- **Grants.gov**

Built for **grant discovery**, internal dashboards, automation workflows, and downstream ranking/LLM pipelines.

***

### 🔎 What This Actor Provides

For every run, this Actor searches by keyword and outputs normalized records with consistent fields across sources:

- Title
- Sponsor / agency
- Posted date / deadlines (when available)
- Funding amount (when available)
- Eligibility / tags / topics (when available)
- Source URL + stable source id

✅ Unified schema across all sources
✅ Supports selecting which sources to run
✅ Best-effort enrichment (some fields are source-specific)

***

### ⚙️ Input Parameters

#### Example Input

```json
{
  "keyword": "cancer",
  "sources": ["duke", "nih", "grants.gov"],
  "maxCountPerSource": 50
}
```

#### Input Fields

| Field               |     Type | Required | Default | Description                                                 |
| ------------------- | -------: | :------: | ------: | ----------------------------------------------------------- |
| `keyword`           |   string |   Yes    |       - | Keyword to search across selected sources                   |
| `sources`           | string\[] |    No    |     all | Which sources to scrape: `duke`, `nih`, `grants.gov`        |
| `maxCountPerSource` |   number |    No    |      50 | Maximum number of records to return **per selected source** |

#### Important: output size

If you select multiple sources, the Actor may return up to:

`(# of selected sources) × maxCountPerSource`

Example: if `sources=["duke","nih","grants.gov"]` and `maxCountPerSource=50`, you may receive **up to 150 records**.

***

### 💵 Pricing (Pay per event)

This Actor uses **Pay per event** and charges **per dataset item pushed**.

- **NIH + Grants.gov** records use event: `basic_result` (cheaper)
- **Duke** records use event: `duke_result` (more expensive)

Notes:

- You will be charged based on the **number of records saved to the dataset**, not just the number of pages visited.
- If your **max charge** is reached, the Actor exits early.
- Increasing `maxCountPerSource` increases the *potential* number of charged results.

***

### 📤 Output Schema (Unified)

Each dataset item is a unified record (fields may be `null` if not available from that source).

#### Example Output Record

```json
{
  "source": "grants.gov",
  "sourceId": "PAR-26-107",
  "url": "https://simpler.grants.gov/opportunity/dd8d7a29-5191-4919-95ce-f7ac57922cff",
  "scrapedAt": "2026-03-03T22:42:37.165Z",

  "title": "Title Discovery of the Genetic Basis of Childhood Cancers...",
  "description": "As part of the Gabriella Miller Kids First...",

  "sponsorName": "National Institutes of Health",

  "amount": null,
  "amountMin": null,
  "amountMax": null,
  "amountCurrency": "USD",

  "status": "Forecasted",

  "postedDate": "May 19, 2026",
  "deadlineSponsor": "July 19, 2026",
  "startDate": "August 15, 2026",

  "topics": null,
  "eligibility": ["Nonprofit", "Government", "Business"],
  "fundingType": ["Other"],

  "nih": null,
  "grants_gov": {
    "opportunityNumber": "PAR-26-107",
    "closeDate": "TBD",
    "detail": { "fiscalYear": 2026, "contactEmails": ["kidsfirst@od.nih.gov"] }
  }
}
```

#### Key fields

| Field                                                   | Description                                                    |
| ------------------------------------------------------- | -------------------------------------------------------------- |
| `source`                                                | `duke` | `nih` | `grants.gov`                                |
| `sourceId`                                              | Best-effort stable id per source                               |
| `url`                                                   | Canonical detail URL                                           |
| `title`                                                 | Opportunity title                                              |
| `description`                                           | Plain-text description/abstract (when available)               |
| `sponsorName`                                           | Sponsor / agency                                               |
| `amount`, `amountMin`, `amountMax`                      | Funding amounts (when available)                               |
| `status`                                                | e.g. Open / Forecasted (when available)                        |
| `postedDate`, `deadlineSponsor`, `startDate`, `endDate` | Dates (best-effort; may be null)                               |
| `eligibility`, `topics`, `fundingType`, `disciplines`   | Tags/classification (when available)                           |
| `nih`                                                   | NIH-only structured fields (when source = `nih`)               |
| `grants_gov`                                            | Grants.gov-only structured fields (when source = `grants.gov`) |

***

### 🚀 How It Works

1. You provide a `keyword`
2. The Actor runs the selected sources
3. Each source returns up to `maxCountPerSource` normalized records
4. Results are saved to the default dataset

### 👥 Who This Actor Is For

- Research ops / grant offices
- Founders and teams building grant discovery tools
- Analysts tracking funding programs
- Automation pipelines that need structured grant data

***

### 📞 Support & Feedback

For issues or feature requests, contact the Actor author via Apify.

# Actor input Schema

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

Search keyword.

## `sources` (type: `array`):

Select which sources to scrape. If empty, all sources will be scraped.

## `maxCountPerSource` (type: `integer`):

Stop after this many results per selected source have been saved.

## Actor input object example

```json
{
  "keyword": "cancer",
  "sources": [
    "duke",
    "nih",
    "grants.gov"
  ],
  "maxCountPerSource": 50
}
```

# Actor output Schema

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

No description

## `run` (type: `string`):

No description

# 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 = {
    "keyword": "cancer",
    "sources": [
        "duke",
        "nih",
        "grants.gov"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("caffein.dev/grants-actor").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 = {
    "keyword": "cancer",
    "sources": [
        "duke",
        "nih",
        "grants.gov",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("caffein.dev/grants-actor").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 '{
  "keyword": "cancer",
  "sources": [
    "duke",
    "nih",
    "grants.gov"
  ]
}' |
apify call caffein.dev/grants-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,caffein.dev/grants-actor"
        }
    }
}

```

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/6PPepHmYMZdhuEiKD/builds/Lvk6ekwWKopCgcbfL/openapi.json
