# BioCatalystFeed: Biotech trials, FDA & EMA tracker (`biocatalystfeed/biocatalystfeed-clinicaltrials-monitor`) Actor

Watch ClinicalTrials.gov (API v2) by sponsor, condition, intervention, phase or status and get what changed since the last run: new trials, status, phase, enrollment and date changes. Free. Not investment or medical advice.

- **URL**: https://apify.com/biocatalystfeed/biocatalystfeed-clinicaltrials-monitor.md
- **Developed by:** [BioCatalystFeed](https://apify.com/biocatalystfeed) (community)
- **Categories:** Automation, Developer tools
- **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?

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

<p><img src="assets/brand/logo-icon.svg" alt="BioCatalystFeed logo" width="64" height="64"></p>

## BioCatalystFeed

Website: https://biocat.ai · Contact: contact@biocat.ai

**An open-source catalyst feed for biotech: see what changed across clinical trials, FDA and EMA actions, NIH grants,
papers/preprints and SEC filings for the companies and drugs you follow.** Use it as a CLI, as an MCP server for AI
agents (Claude, Cursor, …), or as an Apify actor.

> ⚠️ **Not investment, legal or medical advice.** Data may be incomplete, delayed or wrong; PDUFA dates are unverified
> candidates from SEC filings. Always check the linked primary source.

### What it does

| Source | Command | What you get |
|---|---|---|
| ClinicalTrials.gov API v2 (NLM) | `bcf trials` | search, sponsor pipelines, **diffs**: new trials, status/phase/enrollment/date, primary-endpoint, arm, intervention, site-count and results-posted changes, each labelled **critical / notable / minor** |
| openFDA (Drugs@FDA, SPL labels) | `bcf fda` | approvals (incl. novel NME/BLA flag), submissions, label revisions, diffs |
| NIH RePORTER | `bcf grants` | grants by org / PI (middle-initial aware) / keyword; new awards, amount changes |
| PubMed + **Europe PMC** + bioRxiv/medRxiv | `bcf papers` | papers & preprints, **deduplicated by DOI/PMID** across sources |
| SEC EDGAR | `bcf sec` | 8-K mentions of PDUFA dates (UNVERIFIED candidates, linked to the filing) |
| European Medicines Agency (EMA) | `bcf ema` | EU centrally authorised medicines: CHMP opinions, EC authorisations, refusals, withdrawals, suspensions; orphan/PRIME flags; diffs |
| Federal Register (FDA notices) | `bcf adcom` | FDA advisory committee meetings: committee, meeting date, NDA/BLA numbers and sponsors from the agenda; postponements/cancellations; diffs |
| All of the above | `bcf profile` | one merged company profile (name or ticker) |

Across tools: `--exclude TERM …` to drop noise, `--rank` for relevance ordering, and `--rss` / `--json-feed` digest
files on every `watch` (local files you can serve or feed into any reader; nothing is emailed).

### Quickstart

```bash
python3 -m venv .venv && source .venv/bin/activate   # macOS/Homebrew Python blocks global pip installs (PEP 668)
pip install biocatalystfeed
## no venv needed:  uvx --from biocatalystfeed bcf --help    or    pipx install biocatalystfeed

bcf trials search --sponsor "Viking Therapeutics" --phase PHASE3
bcf papers search --drug resmetirom --since 2026-09-01 --exclude mice rat --rank
bcf grants search --pi "Ioannou, George N" --since 2024-01-01 --no-future
bcf sec pdufa MDGL --since 2023-01-01
bcf profile Lilly MDGL "Viking Therapeutics" --md profiles.md
bcf ema search --status Opinion --since 2026-09-01          # latest CHMP opinions (EU)
bcf adcom upcoming --area drugs biologics                   # scheduled FDA advisory committee meetings

## watches: first run = baseline, later runs report what changed (cron it daily)
bcf trials --db bcf.db watch --name obesity --condition obesity --phase PHASE3 --rss obesity.rss
bcf trials --db bcf.db changes --name obesity --min-severity critical   # terminations, endpoint rewrites
bcf papers --db bcf.db watch --name mdgl --affiliation "Madrigal Pharmaceuticals" --json-feed mdgl.feed.json
```

Global flags such as `--db` go **after the tool name and before the subcommand**: `bcf trials --db bcf.db changes`, not `bcf --db bcf.db trials changes` or `bcf trials changes --db bcf.db`.
`bcf trials changes` prints a readable one-line-per-change summary; add `--json` for one JSON object per line.
PubMed `--since`/`--until` filter on the publication date shown in the output (Europe PMC uses first-publication date).

The old commands (`trialwatch`, `fdawatch`, `grantwatch`, `paperwatch`, `secwatch`, `trialwatch-mcp`) still work.

#### MCP server

```json
{"mcpServers": {"biocatalystfeed": {"command": "uvx", "args": ["biocatalystfeed", "mcp"],
  "env": {"BIOCATALYSTFEED_DB": "/path/to/bcf.db"}}}}
```

(or point `command` at an installed `biocatalystfeed-mcp`). Listed in the official MCP Registry as
`io.github.biocatalystfeed/biocatalystfeed`.
Tools include `search_trials`, `sponsor_pipeline`, `fda_approvals`, `company_profile`, `search_grants`,
`search_papers`, `sec_pdufa_mentions`, `ema_medicines`, `fda_adcom_meetings`, `snapshot_*` / `*_changes_since`, and `changes_feed` (RSS / JSON Feed).

#### Configuration

| Env var | Purpose |
|---|---|
| `BIOCATALYSTFEED_CONTACT` | contact email put in the SEC User-Agent (SEC fair-access policy). Default is the project contact (`contact@biocat.ai`); set it to your own contact for heavy SEC use |
| `SEC_USER_AGENT` | full SEC User-Agent override |
| `NCBI_EMAIL` | optional email sent to NCBI E-utilities |
| `OPENFDA_API_KEY` | optional openFDA API key (free at open.fda.gov/apis/authentication); raises daily/minute rate limits. Never logged |
| `NCBI_API_KEY` | optional NCBI E-utilities API key (free from your NCBI account settings); raises the PubMed limit from 3 to 10 req/s. Never logged |
| `BIOCATALYSTFEED_DB` (or `TRIALWATCH_DB`) | SQLite DB for the MCP server |
| `FDAWATCH_ALIASES` | JSON file extending the company alias table |

### How it compares

Facts about DataLookout are from datalookout.com, its /citeline-alternative and /clinical-trial-monitoring pages (checked 2026-10-21 PT). We have not tested
their product. Fuller, cited comparison: [`docs/COMPARISON.md`](docs/COMPARISON.md).

| | BioCatalystFeed (open source) | DataLookout |
|---|---|---|
| Price | Free (Apache-2.0); hosted tier planned | Free tier; Pro $49/month |
| Sources | ClinicalTrials.gov, openFDA, NIH RePORTER, PubMed, Europe PMC, bioRxiv/medRxiv, SEC EDGAR, EMA, Federal Register (FDA AdComs) | ClinicalTrials.gov |
| Change tracking | Diffs between your own runs (trials: status, phase, enrollment, dates, sponsor, title, why stopped, primary endpoints, arms, interventions, site counts, results posting; severity critical/notable/minor; plus FDA, EMA, AdCom, grant, paper and SEC changes) | Daily scan; 13 fields incl. status, enrollment, primary endpoints, interventions, results, site counts, completion dates; changes marked Stopped/Notable/Minor |
| Delivery | CLI, MCP server for AI agents, RSS/JSON Feed files, Apify actor | Morning email digest + dashboard inbox |
| Watch limits | None when self-hosted | Free: 1 sponsor + 1 disease watchlist + 1 saved search; Pro: 10 of each |
| Scheduling | You run it (cron, Apify schedule) | Hosted, daily |
| Setup | Python install | "2 minutes" (their claim) |

Pick DataLookout for a hosted, emailed, ClinicalTrials.gov-only digest. Pick BioCatalystFeed if you want several
sources per company or ticker, agent/MCP access, or to self-host.

#### Trial change severity (v0.3.0)

Every trial change carries `severity`, and date changes carry `shift_days`:

- **critical**: status moves to TERMINATED / SUSPENDED / WITHDRAWN, a why-stopped reason appears, or the primary
  endpoint(s) are rewritten.
- **notable**: other status or phase changes, new trials, lead-sponsor changes, results posted, arm or intervention
  changes, enrollment changes of 20% or more, start / primary completion / completion dates moved 30+ days.
- **minor**: everything else (small date or enrollment tweaks, site-count changes, title edits).

Filter with `--min-severity notable|critical` on `bcf trials watch` / `changes`, or `min_severity` in the MCP tool
`trial_changes_since`. Snapshots made by older versions start tracking the new fields on their next run, so upgrading
doesn't produce a burst of false changes.

#### Search filters (v0.2.1)

- `--exclude` takes words or phrases (space- or comma-separated); matching is whole-word and case-insensitive, and a
  trailing `*` is a prefix wildcard (`--exclude "murin*" rat`).
- `--rank` scores title hits 3 and other-field hits 1 (simple plurals tolerated), +1 for exact multi-word phrases in
  the title and +2 when every query term matches; ties break by newest date. The score is in `relevance`.

### Data sources, limits and etiquette

Built-in throttles follow each source's published policy (e.g. NIH RePORTER 1 req/s, NCBI ≤3 req/s without key, SEC
≤10 req/s with a declared User-Agent, openFDA 1,000 req/day per IP without key). We store **metadata and links only**
for papers/preprints, never abstracts. Change detection only covers your own runs; there's no historical backfill.
PDUFA dates are regex extractions from 8-K text, not a calendar. Attributions are in [`NOTICE`](NOTICE). Design notes
and per-source terms are in [`docs/DEVELOPER-NOTES.md`](docs/DEVELOPER-NOTES.md).

### Hosted tier

A paid hosted version (scheduled watches, persisted history, hosted MCP) is planned. Draft terms:
[`TERMS.md`](TERMS.md), [`PRIVACY.md`](PRIVACY.md) (drafts, not legal advice, not in effect).

### Contributing / Testing

```bash
git clone https://github.com/biocatalystfeed/biocatalystfeed && cd biocatalystfeed
python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
pytest                      # offline tests; live-API tests are skipped by default
TRIALWATCH_LIVE=1 pytest    # also run tests that call the real public APIs (needs network; slower)
```

### Contributing & licence

See [`CONTRIBUTING.md`](CONTRIBUTING.md), [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) and [`SECURITY.md`](SECURITY.md) (report vulnerabilities privately). Licensed under the [Apache License 2.0](LICENSE). BioCatalystFeed is
independent and not endorsed by NLM, NIH, FDA, SEC, EMA, the Office of the Federal Register, EMBL-EBI/Europe PMC, or bioRxiv/medRxiv.

# Actor input Schema

## `watchName` (type: `string`):

Key used to store snapshots between runs. Use a different name per query.

## `sponsor` (type: `string`):

Sponsor/collaborator search text, e.g. 'Viking Therapeutics'.

## `condition` (type: `string`):

Condition or disease, e.g. 'obesity'.

## `intervention` (type: `string`):

Drug or intervention, e.g. 'tirzepatide'. OR is allowed.

## `phases` (type: `array`):

Any of EARLY_PHASE1, PHASE1, PHASE2, PHASE3, PHASE4, NA.

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

Overall statuses, e.g. RECRUITING, TERMINATED.

## `changedSince` (type: `string`):

Only trials updated on or after this date (YYYY-MM-DD).

## `excludeTerms` (type: `array`):

Drop trials whose title, conditions or interventions contain any of these words or phrases.

## `maxRecords` (type: `integer`):

Maximum trials fetched per run.

## `outputMode` (type: `string`):

'changes' returns detected changes (the first run returns the baseline trials); 'trials' always returns the full trial list.

## Actor input object example

```json
{
  "watchName": "default",
  "sponsor": "Viking Therapeutics",
  "maxRecords": 500,
  "outputMode": "changes"
}
```

# Actor output Schema

## `results` (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 = {
    "sponsor": "Viking Therapeutics"
};

// Run the Actor and wait for it to finish
const run = await client.actor("biocatalystfeed/biocatalystfeed-clinicaltrials-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 = { "sponsor": "Viking Therapeutics" }

# Run the Actor and wait for it to finish
run = client.actor("biocatalystfeed/biocatalystfeed-clinicaltrials-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 '{
  "sponsor": "Viking Therapeutics"
}' |
apify call biocatalystfeed/biocatalystfeed-clinicaltrials-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,biocatalystfeed/biocatalystfeed-clinicaltrials-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/hYjtdzj3Qkp8GlnOY/builds/FnXreI7ttmoclA5xN/openapi.json
