---
name: redash-dashboard
description: Build complete Redash dashboards to measure feature adoption, OKRs, or custom metrics. Reads context from Notion if URL provided, designs SQL queries, generates an executable Python script, runs it, and leaves the script ready to commit. Use when a PM wants to build a dashboard, measure a feature, track OKRs, create Redash reports, or says "dashboard", "build metrics", "measure adoption".
disable-model-invocation: true
---

# Redash Dashboard Builder

Build complete Redash dashboards from what the PM wants to measure. The output is an **executable Python script** that creates everything via API and is ready to commit to the repo.

## Prerequisites

- Skill `redash-connect` configured (config.json with credentials)
- Python 3 + `requests`
- Builder library: `scripts/redash_builder.py` (alongside this SKILL.md)

## Workflow

### Step 1 — Understand what to measure

Ask the PM:

1. **What do you want to measure?** Launched feature, OKR, product metric, or something custom.
2. **Do you have a Notion URL?** If yes, read the page with the Notion MCP to extract name, success metrics, KRs, release date.
3. **Reference date?** Release date, quarter start, or custom date. Will be the default for the `since` filter.
4. **Which tables to measure against?** If unknown, check skill `redash-schema` to identify the correct tables.

### Step 2 — Propose the dashboard

**BEFORE generating the script**, propose the list of queries and visualizations to the PM. Example:

> **Dashboard: Adoption · [Feature X]**
>
> 1. General KPIs (3 counters: total, adoption %, active clients)
> 2. Weekly trend (combo: volume + adoption %)
> 3. Distribution by [category] (pie chart)
> 4. Top 10 clients by usage (table)
> 5. Clients with volume that did NOT adopt (table)
> 6. Weekly new client cohort (combo: new + cumulative)

Wait for PM feedback before proceeding.

### Step 3 — Generate the script

Generate a Python script using `redash_builder.py` and save it to:

```
dashboards/[feature-name]/build_dashboard.py
```

**Builder path**: copy `redash_builder.py` to `dashboards/redash_builder.py` if it doesn't exist.

**Final directory structure** (what goes into the repo):

```
dashboards/
├── redash_builder.py          # shared library (copy from skill)
├── config.json.example        # template without credentials
├── [feature-a]/
│   └── build_dashboard.py     # generated script
└── [feature-b]/
    └── build_dashboard.py
```

#### Generated script template

```python
#!/usr/bin/env python3
"""
Dashboard: [NAME] — [brief description]
Created: [date]

Creates queries, visualizations and dashboard in Redash.
Usage: python3 build_dashboard.py
"""

import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from redash_builder import RedashBuilder

CONFIG_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "config.json")
DATA_SOURCE_ID = 1  # Humand Prod | Read replica
DASHBOARD_NAME = "[Dashboard name]"
SINCE_DEFAULT = "[release-date]"

QUERIES = [
    {
        "key": "[unique_key]",
        "name": "[Prefix] · [Query name]",
        "description": "[What it measures]",
        "sql": """[SQL with parameter '{{ since }}'::date]""",
    },
    # ... more queries
]


def main():
    b = RedashBuilder(config_path=CONFIG_PATH)
    pm = b.since_param_mapping(SINCE_DEFAULT)

    # 1. Create queries and execute them
    qids = {}
    default_tables = {}
    for spec in QUERIES:
        qid, table_viz = b.create_query(
            spec["name"], spec["sql"],
            data_source_id=DATA_SOURCE_ID,
            description=spec["description"],
            since_default=SINCE_DEFAULT,
        )
        qids[spec["key"]] = qid
        default_tables[spec["key"]] = table_viz
        b.execute_query(qid, params={"since": SINCE_DEFAULT})
        print(f"  Query: {spec['name']} → {qid}")

    # 2. Create visualizations
    # [counters, pies, charts per design]

    # 3. Create dashboard
    dash_id, slug = b.create_dashboard(DASHBOARD_NAME)

    # 4. Layout (6-column grid)
    b.add_text_widget(dash_id, "# [Title]\\n\\n[Description]", row=0, col=0)
    # [add_widget for each visualization]

    # 5. Publish
    b.publish(dash_id)
    print(f"\\nDashboard: {b.dashboard_url(dash_id, slug)}")


if __name__ == "__main__":
    main()
```

### Step 4 — Execute

```bash
python3 dashboards/[feature]/build_dashboard.py
```

Each execution creates a new dashboard (does not overwrite).

### Step 5 — Save for the repo

1. Verify `dashboards/redash_builder.py` exists (if not, copy it)
2. Verify `dashboards/config.json.example` exists (if not, create it)
3. The PM commits `dashboards/` to their repo

## Dashboard types

### Feature adoption (most common)

| Query | Visualization | Purpose |
|-------|--------------|---------|
| General KPIs | 3-4 counters | Headline numbers: total, adoption %, clients |
| Weekly trend | Combo chart (bars + line) | Temporal evolution |
| Distribution by category | Pie chart | Breakdown of how it's used |
| Top clients by usage | Table | Who are the power users |
| Clients that did NOT adopt | Table | Outreach opportunity |
| Weekly cohort | Combo chart (bars + line) | New client traction |

### OKR / KR tracking

| Query | Visualization | Purpose |
|-------|--------------|---------|
| Current KR vs target | Counter with target | Current state |
| Progress per week | Line chart | Trend towards target |
| Breakdown by segment | Bar chart / table | Where the progress is |

### Custom metric

Design according to what the PM needs. For reusable CTEs and SQL patterns, read skill `redash-schema` → [sql-patterns.md](../redash-schema/reference/sql-patterns.md).

## Dashboard layout

Redash uses a **6-column** grid. Typical heights:

| Element | size_x | size_y | Notes |
|---------|--------|--------|-------|
| Header (text) | 6 | 2 | Full width |
| Counter | 2 | 4 | 3 counters = full row |
| Pie chart | 3 | 8 | Half width |
| Combo/line chart | 6 | 8 | Full width |
| Table | 6 | 10-12 | Full width |

Start with `row=0` and increment based on each row's `size_y`.

## Rules

- **NEVER expose credentials** in generated scripts, messages, or commits. `config.json` goes in `.gitignore`.
- **ALWAYS propose before generating.** Do not create the script without PM validation of the design.
- **Name queries with consistent prefix.** E.g.: `Deactivation reason · KPIs`, `OKR Q2 · KR1 Progress`.
- **Global `since` parameter.** Every adoption dashboard must have a dashboard-level `since` filter.
- **Execute each query** after creating it so the dashboard has data when opened.
