# Growthbook Experiments Tracker (`katzino96.original/growthbook-experiments-tracker`) Actor

- **URL**: https://securitybyobscurity.apify.com/katzino96.original/growthbook-experiments-tracker.md
- **Developed by:** [Tomáš Katz](https://securitybyobscurity.apify.com/katzino96.original) (community)
- **Stats:** 1 total users, 0 monthly users, 0.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

## GrowthBook Experiments Tracker

Internal Apify Actor that fetches experiments from the [GrowthBook REST API](https://docs.growthbook.io/api/), runs a set of health checks on them, and posts a status digest to Slack. Built to keep the experiments used by `apify-core` and `apify-web` honest — following the practices from the "GrowthBook at Apify" wiki page.

### What it reports

Each run covers three groups (all filterable by tags, owner, and project):

- **Running experiments** — the core status list, with owner, days running, traffic coverage, and exposed users. Experiments whose rule is not enabled in the `production` environment are marked **staging only** and exempt from the running-too-long check. Because GrowthBook records no date for the production switch, the tracker remembers it itself (named key-value store `growthbook-experiments-state`): for experiments first seen as staging-only, "days running" starts the day the production rule turns on; for experiments already in production when first tracked, it falls back to the phase start.
- **Stale drafts** — drafts created long ago but never launched (optional).
- **Recently stopped** — experiments stopped within the lookback window (optional).

#### Health checks

| Check                        | Severity     | Meaning                                                                                                     |
| ---------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------- |
| `decided-but-running`        | 🔴 critical  | Result is documented (won/lost/inconclusive) but the experiment still runs — burning billed exposure events |
| `running-too-long`           | 🟠 warning   | Current phase exceeds `maxRunningDays` (escalated wording at 100% traffic)                                  |
| `high-exposure`              | 🟠 warning   | More users exposed than `maxExposedUsers`                                                                   |
| `sample-ratio-mismatch`      | 🟠 warning   | SRM p-value < 0.001 in the latest analysis — bucketing is likely broken (e.g. missing hash attribute)       |
| `overdue-status-update`      | 🟡 attention | The scheduled status update date has passed                                                                 |
| `stale-draft`                | 🟡 attention | Draft older than `staleDraftDays`, never launched                                                           |
| `stopped-without-conclusion` | 🟡 attention | Stopped recently with no documented winner/conclusion                                                       |
| `missing-hypothesis`         | 🔵 hygiene   | Running without a hypothesis                                                                                |
| `no-tags`                    | 🔵 hygiene   | Running without tags (convention: tag with team + surface)                                                  |
| `no-owner`                   | 🔵 hygiene   | No owner assigned                                                                                           |

### Input

See the Input tab / [`.actor/input_schema.json`](.actor/input_schema.json). The important ones:

- `growthbookToken` (**required**, secret) — GrowthBook REST API secret key (`secret_...`). Org-scoped, created under GrowthBook → Settings → API Keys.
- `tags`, `owner`, `projectId` — optional GrowthBook filters.
- `includeStagingOnly` — set `false` to hide running experiments not yet enabled in production (their production start is tracked either way).
- `maxRunningDays`, `staleDraftDays`, `recentlyStoppedDays`, `maxExposedUsers` — health-check thresholds.
- `slackToken` (secret) + `slackChannel` — when both set, the report is posted to Slack. Without them, the run just logs the report and fills the dataset. The bot needs `chat:write` (plus `users:read` and `users:read.email` to @mention experiment owners by their GrowthBook email) and must be a member of the channel.

### Output

- **Slack**: one channel message (summary counts, issues sorted by severity with owner mentions, running-experiments list) and per-experiment detail cards in its thread.
- **Dataset**: one record per experiment with status, phase, exposure, result, and detected `issues[]` — usable by other integrations.

### Development

```bash
npm install
npm test              # unit tests for the health checks
npm run lint
apify run             # local run; input from storage/key_value_stores/default/INPUT.json
apify push            # deploy
```

The local `INPUT.json` is gitignored-friendly — never commit real tokens.

# Actor input Schema

## `growthbookToken` (type: `string`):

Secret API key for the GrowthBook REST API (`secret_...`). Create one in GrowthBook under Settings → API Keys. The key is organization-scoped, so no org ID is needed.

## `tags` (type: `array`):

Only include experiments having at least one of these GrowthBook tags. Leave empty to include all experiments.

## `owner` (type: `string`):

Only include experiments belonging to this owner (GrowthBook user ID or name/email for legacy records).

## `projectId` (type: `string`):

Only include experiments from this GrowthBook project.

## `includeStaleDrafts` (type: `boolean`):

Include draft experiments that were created long ago but never launched (see "Stale draft age").

## `includeRecentlyStopped` (type: `boolean`):

Include experiments stopped within the lookback window (see "Recently stopped lookback"), flagging those stopped without a documented result.

## `includeStagingOnly` (type: `boolean`):

Include running experiments whose rule is not enabled in the production environment yet (still being tested on staging). Their production start date is tracked either way.

## `maxRunningDays` (type: `integer`):

Flag running experiments whose current phase started more than this many days ago.

## `staleDraftDays` (type: `integer`):

Flag draft experiments created more than this many days ago.

## `recentlyStoppedDays` (type: `integer`):

How far back to look for stopped experiments.

## `maxExposedUsers` (type: `integer`):

Flag running experiments that have exposed more users than this (every exposure is a billed analytics event).

## `slackToken` (type: `string`):

Slack bot token (`xoxb-...`) used to post the report.

## `slackChannel` (type: `string`):

Channel to post the report to — channel ID (`C0123456789`) or `#channel-name`. The bot must be a member of the channel.

## Actor input object example

```json
{
  "tags": [],
  "includeStaleDrafts": true,
  "includeRecentlyStopped": true,
  "includeStagingOnly": true,
  "maxRunningDays": 30,
  "staleDraftDays": 30,
  "recentlyStoppedDays": 14,
  "maxExposedUsers": 100000
}
```

# Actor output Schema

## `experiments` (type: `string`):

One item per tracked experiment: status, owner, days in production, traffic coverage, exposed users, documented result, and the list of detected health issues.

# 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("katzino96.original/growthbook-experiments-tracker").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("katzino96.original/growthbook-experiments-tracker").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 katzino96.original/growthbook-experiments-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,katzino96.original/growthbook-experiments-tracker"
        }
    }
}
```

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-securitybyobscurity.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api-securitybyobscurity.apify.com/v2/actors/h6qiaSpUvU5K2BTxO/builds/ZQbH9WzxWcyVPD5MZ/openapi.json
