# NIH RePORTER Grant Funding & Procurement Signals (`nintendo424/nih-grant-procurement-signal-monitor`) Actor

Monitor NIH RePORTER grants and research funding for new awards, award changes, and cautious procurement signals relevant to biomedical research vendors. Adds recurring change detection and evidence—not purchasing guarantees.

- **URL**: https://apify.com/nintendo424/nih-grant-procurement-signal-monitor.md
- **Developed by:** [Blake Panter](https://apify.com/nintendo424) (community)
- **Categories:** Business, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## NIH RePORTER Grant Funding & Procurement Signals

Monitor official **NIH RePORTER** data for NIH grants, research funding changes, new grant awards, and timing signals that may help prioritize vendor account research. This Actor compares normalized grant snapshots across runs, connects described research needs to an auditable biomedical vendor taxonomy, and emits only new or changed procurement signals by default.

### Built for

- biomedical research vendors and life-science suppliers
- laboratory equipment, reagent, imaging, logistics, and clinical-research providers
- business development, market intelligence, and sales operations teams
- grant consultants and research-funding analysts tracking NIH-funded organizations

### Why this instead of a raw NIH grant scraper?

A raw scraper gives you rows to repeatedly download and compare. This Actor turns NIH RePORTER grant data into a recurring monitoring workflow with persistent change detection, buyer filters, award and project-window context, matched evidence terms, stable deduplication keys, and explicit source coverage. The output is a cautious research-prioritization signal—not a claim that a grant award will become a purchase.

> **Important:** A grant, award change, or approaching budget/project end date does not guarantee purchasing. Reported dates are planning windows, **not mandatory spend deadlines**. Validate any opportunity with the award recipient and the official NIH record.

### What is a paid result?

Each dataset item is one `grant-procurement-signal` pay-per-event result:

- `new-award`
- `renewal-or-supplement`
- `award-increase` / `award-decrease`
- `budget-window-ending` / `project-window-ending`
- `metadata-change`
- `unchanged` (only when explicitly enabled)

The Actor does **not** sell raw grant rows. It adds stable state, change detection, timing interpretation, buyer filters, and an auditable vendor taxonomy.

### Official source and coverage

The Actor sends bounded POST requests to:

`https://api.reporter.nih.gov/v2/projects/search`

Requests are sorted by `award_notice_date` descending and use the selected `fiscalYears`. `maxSourceRecords` limits how many of the newest matching API records are examined. Every result includes `sourceCoverage` with the API total, examined count, requested limit, fiscal years, retrieval time, and whether coverage was truncated.

Because records are sorted newest first, a bounded run is not full historical coverage when `sourceCoverage.truncated` is `true`.

### Vendor taxonomy

Classification is deterministic. Evidence contains only configured terms actually matched in NIH title, abstract, terms, or preferred terms:

| Category | Example evidence terms |
|---|---|
| `lab-equipment` | laboratory equipment, centrifuge, microscope, flow cytometer, sequencer |
| `reagents-biospecimens` | reagent, antibody, assay kit, biospecimen, biobank, blood sample |
| `imaging` | MRI, PET scan, CT scan, ultrasound, microscopy, neuroimaging |
| `clinical-research` | clinical research, clinical trial, patient monitoring, site coordination |
| `recruitment-staffing` | participant recruitment, enrollment, recruiter, research personnel |
| `data-ai` | artificial intelligence, machine learning, bioinformatics, software, algorithm |
| `logistics` | cold chain, shipping, courier, specimen transport, supply chain |
| `general-research` | research support, research resources, laboratory supplies, core facility |

A category is evidence about the project description, not proof that a matching purchase will occur.

### Input example

```json
{
  "fiscalYears": [2026],
  "queryText": "biomarker",
  "states": ["CA", "MA"],
  "activityCodes": ["R01", "U19"],
  "agencyCodes": ["NCI", "NIA"],
  "minimumAwardAmount": 250000,
  "vendorCategories": ["imaging", "reagents-biospecimens"],
  "signalTypes": ["new-award", "renewal-or-supplement", "award-increase", "budget-window-ending"],
  "endingWithinDays": 90,
  "includeInitial": true,
  "emitUnchanged": false,
  "maxSourceRecords": 1000,
  "maxItems": 100,
  "pageSize": 100,
  "requestTimeoutSecs": 30,
  "baselineStoreName": "nih-grant-procurement-signals"
}
```

#### Input behavior

- `organizationNames` uses case-insensitive substring matching.
- `states`, `activityCodes`, and `agencyCodes` are case-insensitive. Administering-IC abbreviations such as `NCI` are normalized as the output `agencyCode`; source aliases such as `CA` also match.
- `queryText` is matched locally across title, abstract, raw NIH `terms` and `pref_terms`, organization, project number, and taxonomy evidence.
- `minimumAwardAmount` excludes missing amounts when set; blank source values stay `null`, never `0`.
- `vendorCategories` and `signalTypes` allow any selected value to match. Signal-type selection is applied before `unchanged` is decided, so an enabled `unchanged` signal can represent that no selected change type applied.
- `includeInitial: false` seeds a fresh baseline without emitting first-seen award signals. Eligible ending-window signals can still be emitted.
- `emitUnchanged: false` suppresses unchanged snapshots. Window signals are emitted once per stored identity/date state.
- `maxItems` is checked before every paid output. The Actor also stops immediately when Apify reports `eventChargeLimitReached`.
- The named `baselineStoreName` must be reused across scheduled runs. Use a fresh name when intentionally creating a new monitoring baseline.

### Output

Each item includes:

- stable application/project identity and `dedupeKey`
- old/current award amounts and dates, plus `awardAmountDelta`
- organization, state, principal investigators, administering agency, activity/award codes
- vendor categories and matched `vendorCategoryEvidence`
- a cautious, signal-specific `reason`
- official NIH detail URL
- explicit `sourceCoverage`
- `detectedAt`

Example shape (illustrative values):

```json
{
  "signalType": "award-increase",
  "dedupeKey": "nih-appl-123-award-increase",
  "applicationId": 123,
  "organizationName": "EXAMPLE UNIVERSITY",
  "oldAwardAmount": 500000,
  "currentAwardAmount": 550000,
  "awardAmountDelta": 50000,
  "vendorCategories": ["imaging", "data-ai"],
  "vendorCategoryEvidence": { "imaging": ["magnetic resonance imaging"], "data-ai": ["machine learning"] },
  "reason": "The reported award amount increased ...; this is a planning signal, not a purchasing commitment.",
  "officialDetailUrl": "https://reporter.nih.gov/project-details/123"
}
```

### Baseline semantics

The key-value store is keyed by stable NIH application identity (`appl_id`, with project-number fallback). For every filtered current project, the Actor durably stages the normalized baseline and pending signals **before** pay-per-event output. After each successful sink write/charge, it removes that signal from the pending outbox and persists the acknowledgement before moving to the next signal.

Delivery is **at least once**, not exactly once. If the process fails after the output sink accepts and charges a signal but before the acknowledgement is persisted, the next run can deliver and charge that signal again. Other partial failures leave unacknowledged signals pending for retry; they do not guarantee that charges cannot repeat. Consumers should make processing idempotent and deduplicate repeated deliveries by the stable `dedupeKey` included in every item.

Changing filters or baseline names changes the monitored population; choose store names deliberately.

Application type `2`, `3`, or `5`, or a project-number supplement suffix, is labeled `renewal-or-supplement`. Other first-seen applications are labeled `new-award`. This is a transparent NIH-code interpretation, not a purchasing prediction.

### Local development

```bash
bun install --frozen-lockfile
bun run test
bun run typecheck
npx --yes apify-cli validate-schema
```

Run locally with Apify storage by placing input in `storage/key_value_stores/default/INPUT.json`, then:

```bash
APIFY_LOCAL_STORAGE_DIR=./storage bun run start
```

For a stateful smoke test, run twice with the same `baselineStoreName`; the second unchanged run should emit no new items when `emitUnchanged` is false. Use a fresh dataset/storage directory if you need a clean output count.

### Responsible use

Use signals to prioritize account research, not to assert intent, availability, procurement method, timing, or vendor eligibility. Follow applicable solicitation, grant, institutional purchasing, privacy, and outreach rules. The NIH RePORTER record and recipient organization remain authoritative.

# Actor input Schema

## `fiscalYears` (type: `array`):

NIH fiscal years to query.

## `queryText` (type: `string`):

Case-insensitive local match across project title, abstract, raw NIH terms and preferred terms, organization, and project number.

## `organizationNames` (type: `array`):

Case-insensitive organization substring filters; any value may match.

## `states` (type: `array`):

Two-letter organization-state filters.

## `activityCodes` (type: `array`):

NIH activity codes such as R01, U19, or P30.

## `agencyCodes` (type: `array`):

Matches normalized administering IC abbreviations and source code aliases, such as NCI, CA, or AG.

## `minimumAwardAmount` (type: `number`):

Exclude awards below this current amount. Missing amounts remain null and are excluded when this filter is set.

## `vendorCategories` (type: `array`):

Only projects with at least one selected transparent taxonomy category.

## `signalTypes` (type: `array`):

Only emit selected signal types.

## `endingWithinDays` (type: `integer`):

Emit planning signals when reported budget/project end dates fall within this many days. Dates are not labeled mandatory spend deadlines.

## `includeInitial` (type: `boolean`):

Emit new-award or renewal-or-supplement when an identity is first added to a fresh baseline.

## `emitUnchanged` (type: `boolean`):

Emit unchanged snapshots when no other selected signal applies; disabled by default.

## `maxSourceRecords` (type: `integer`):

Hard cap on NIH records retrieved and examined per run.

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

Hard cap checked before every paid output event.

## `pageSize` (type: `integer`):

Records requested per API call.

## `requestTimeoutSecs` (type: `integer`):

Timeout covering each API response and body read.

## `baselineStoreName` (type: `string`):

Persistent Apify key-value store used across recurring runs.

## Actor input object example

```json
{
  "fiscalYears": [
    2026
  ],
  "minimumAwardAmount": 0,
  "endingWithinDays": 90,
  "includeInitial": true,
  "emitUnchanged": false,
  "maxSourceRecords": 1000,
  "maxItems": 100,
  "pageSize": 100,
  "requestTimeoutSecs": 30,
  "baselineStoreName": "nih-grant-procurement-signals"
}
```

# Actor output Schema

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

Dataset items emitted by this run.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nintendo424/nih-grant-procurement-signal-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("nintendo424/nih-grant-procurement-signal-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 '{}' |
apify call nintendo424/nih-grant-procurement-signal-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nintendo424/nih-grant-procurement-signal-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/mDYclXaqglQDUrDYQ/builds/tCQvdAi29LoJmdSc5/openapi.json
