Vertex Data

Business Health Dashboard Leaders Actually Open

A practitioner’s plan to build a business health dashboard that leadership actually uses—metrics, piping, dbt models, BI choices, weekly ritual, and failure modes.

Eric Provencio, Principal Analytics Engineer at Vertex Data Consulting
Eric Provencio
7 min read

Your leadership wants a single view of what matters, not another dashboard they’ll stop opening in two weeks. Here’s the playbook we use to ship a business health dashboard that sticks: choose 8–12 metrics, define them once, wire Stripe/QuickBooks/HubSpot/GA with reliable jobs, model with dbt so numbers reconcile, pick a BI that fits your team, and run a short weekly review so decisions actually change. You can build this in-house with the patterns below, or bring us in to accelerate the parts that bite in production.

The smallest useful dashboard: 8–12 metrics that answer “Are we on track?”

Pick fewer metrics than you think. If a dashboard requires a narrator, it won’t be used. Start with one page, one time range (last 7/28/90 days), and clear deltas vs target.

  • Revenue: MRR/ARR and recognized revenue. Track forecast vs actual to expose timing issues.
  • Gross margin: revenue less COGS as a %.
  • Retention: logo and dollar retention (D30/D90), plus churn reason mix.
  • Pipeline coverage: next 90 days pipeline ÷ target, by owner/segment.
  • Win rate and sales cycle length.
  • Activation or product adoption: a leading indicator tied to value (e.g., first value event).
  • Support health: first response time, backlog age, SLA breach rate.
  • Cash and burn runway if relevant to financial health.
  • Invoice collections: AR aging buckets; failed payment recovery.

Make every tile answer one question and show one decision. Add a note on “how to act.” Use small, consistent labels: “Revenue (MRR)”, “Retention D90”. Don’t bury the key metrics behind filters. If you must add more, split them into a secondary page later.

Define metrics once: a dictionary your BI and Slack can both use

Disagreement on definitions kills trust. Write a metrics dictionary before you write SQL. Keep one file in the repo with names, owners, grain, filters, and authoritative SQL references. Treat it as code: PRs, reviews, and change logs.

# metrics.yml (repo root)
version: 1
metrics:
  - name: revenue_mrr
    owner: finance
    grain: month
    definition_sql: ref('fct_billing_mrr')
    filters:
      - active_subscription = true
    freshness: 24h
    notes: Monthly recurring revenue from Stripe invoices; excludes refunds.
  - name: retention_d90
    owner: revops
    grain: day
    definition_sql: ref('fct_retention_cohort')
    calc: retained_users_90d / cohort_users
  - name: pipeline_coverage
    owner: sales_ops
    grain: week
    calc: sum(pipeline_next_90d) / sum(target_next_90d)
  - name: gross_margin_pct
    owner: finance
    grain: month
    calc: (revenue - cogs) / revenue

Reference models in the dictionary, not raw tables. Add a simple validator in CI that checks every metric resolves to a model and compiles. Use short canonical names in BI and in your weekly agenda. If you later add derived metrics (e.g., net dollar retention), append, don’t redefine.

# lightweight validation (Python)
import yaml, subprocess, sys
m = yaml.safe_load(open('metrics.yml'))
errors = []
for metric in m['metrics']:
    if 'definition_sql' in metric:
        try:
            subprocess.check_call(['dbt', 'compile', '--select', metric['definition_sql']])
        except subprocess.CalledProcessError:
            errors.append(metric['name'])
if errors:
    print('Broken metric refs:', errors)
    sys.exit(1)

If you want help templating this practice across teams, see our Business Health Reporting service.

Wire your systems: Stripe, QuickBooks, HubSpot, GA4—reliably

Connectors are easy to start, hard to keep clean. Choose managed pipelines (Fivetran, Airbyte Cloud) for speed, or run open-source where cost/control matter. Lean on webhooks for change events, not just nightly pulls. Document the data sources once, with owners and SLAs.

  • Stripe: fetch charges, invoices, subscriptions, and balance transactions. Reconcile fees and disputes. Beware timezone drift in created vs period_end.
  • QuickBooks: invoices and payments lag; set a cutoff hour so yesterday’s books don’t flip under you.
  • HubSpot: lifecycle stage history comes as denormalized JSON—flatten it consistently.
  • GA4: sampling and attribution windows change; store the export in Parquet so you can reprocess.
# example: incremental Stripe pull to S3 (Python)
import os, time, stripe, json, boto3
stripe.api_key = os.environ['STRIPE_API_KEY']
s3 = boto3.client('s3')
start = int(os.environ.get('SINCE_TS', 0))
for obj in stripe.Charge.list(created={"gte": start}, limit=100):
    key = f"stripe/charges/ts={obj.created}/{obj.id}.json"
    s3.put_object(Bucket=os.environ['BUCKET'], Key=key, Body=json.dumps(obj))
    time.sleep(0.05)  # Stripe rate limits aggressively

Partition storage by date and id to support idempotent loads. Land to bronze, normalize to silver, then model gold tables in dbt. Keep a small backfill script you can run per-table when a bug is fixed. Version your extractor container images so a library update doesn’t silently change payloads.

Standing up the warehouse or lakehouse? Our guide on the modern data stack for startups covers the minimum that works.

Model with dbt so the dashboard stays fast and trusted

Dashboards die when numbers change underfoot or loads run too slow. Model facts and dimensions with stable keys, then aggregate for the dashboard. Use incremental models and partition pruning. Document tests in schema YAML so breaks fail the build, not the meeting.

-- models/fct_billing_mrr.sql
{{ config(materialized='incremental', unique_key='invoice_id', on_schema_change='sync_all_columns') }}
with invoices as (
  select *
  from {{ source('stripe', 'invoices') }}
  {% if is_incremental() %}
    where updated_at > (select coalesce(max(updated_at), '1970-01-01') from {{ this }})
  {% endif %}
)
select
  invoice_id,
  customer_id,
  period_start::date as period_start,
  period_end::date as period_end,
  amount_due/100.0 as amount_due,
  refunded/100.0 as refunded,
  (amount_due - refunded)/100.0 as mrr_net,
  updated_at
from invoices
where status in ('paid','open');
# models/schema.yml (tests)
version: 2
models:
  - name: fct_billing_mrr
    columns:
      - name: invoice_id
        tests: [not_null, unique]
      - name: mrr_net
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: ":= mrr_net >= 0"

For a 40M-row orders table on an X-Small warehouse, push heavy joins into staging and pre-aggregate by day. Cache volatile metrics in a small aggregate table the dashboard hits directly. If your dbt runs creep, our dbt repo performance work and this primer on dbt materializations will save hours and credits. If you see slow tiles, profile queries first; it’s usually filters on non-partitioned columns.

Pick a BI that fits your team, not a demo

Choose the dashboard surface by who will own it six months from now. Evaluate governance, ad hoc speed, and how easy it is to keep the one-page view stable. A good dashboard provides clarity without needing 15 filters.

Team profileToolStrengthsWatch-outs
SQL-first, governed exploresLooker/Looker StudioModeled semantics; row-level securityModeling upfront; iterate slower
Self-serve ops; sheets power usersSigmaSpreadsheet UX on warehouseEasy to over-join; enforce semantic layer
Mixed PM/Eng; notebooks welcomeHexNotebooks + apps; rapid prototypingGovernance needs care
Microsoft stackPower BIDeep Office integrationDesktop authoring quirks
Lightweight teamsMetabaseFast to value; pulsesKeep SQL sources disciplined

Whatever you pick, keep the business intelligence layer thin. Lock the homepage to a single page with targets. Use labels from your metrics dictionary verbatim so governance is consistent. Add a “Source” link on each tile back to the dbt model or doc. Reserve separate spaces for experiments so the homepage stays clean. Include a small “key performance” legend explaining targets and colors.

Make it stick: the weekly review ritual

Great dashboards change behavior. Book a 30-minute slot. Agenda: 3-minute scan, 10-minute deep dive on misses, 10-minute owner updates, 5-minute decisions captured as tasks. No slide decks allowed—only the dashboard.

  • Assign owners per metric. If a tile is red two weeks running, it gets an action with a due date.
  • Send a Monday Slack digest with deltas and links. Keep it visible.
  • Let a Slack-native agent answer “why” by linking to the right drill view, not guessing.
# Slack digest (Python)
import os, requests
def post(msg):
  requests.post(os.environ['SLACK_WEBHOOK'], json={"text": msg})
msg = """
Business Health — W28
Revenue (MRR): $1.23M (+2.1% WoW)
Retention D90: 92.4% (-0.6pp) — owner @alex
Pipeline Coverage: 2.9x (target 3.5x) — review opp source mix
"""
post(msg)

Automate the digest from the warehouse so you aren’t hand-copying numbers. If a handful of metrics must be near real-time, isolate them and load them more often; the rest can stay daily. This keeps the workflow predictable and makes the meeting about decisions, not hunting numbers. If you want to uplevel facilitation and hands-on practice, our Training & Enablement programs cover runbooks and review habits that last.

Why dashboards get abandoned (and how to avoid it)

Common failure modes we see after week two:

  • Too many tiles. A dashboard turning into a catalog dilutes attention. Keep the homepage to 8–12 and spin up drill pages.
  • Names drift. Marketing “Revenue” vs Finance “Revenue.” The dictionary prevents this. Treat changes like code changes.
  • Stale or slow. Tiles timed out? Pre-aggregate hot paths. Load critical tables first. You don’t need everything to be real-time.
  • Unowned numbers. Assign owners and keep a changelog so an executive trusts what moved and why.
  • Unclear thresholds. Color means nothing without a target and timeframe.
  • Blind spots. Only outcome metrics, no leading indicator. Add one or two that predict movement.

Recover trust with alerts when a metric definition changes and a short “what changed” note in the dashboard description. Show lineage from raw data to tile so a stakeholder can trace issues. Improve operational efficiency by pushing root-cause links into tickets. When tradeoffs arise, ship the stable one-page view over fancy interactions—business dashboards earn attention by being boring and correct. If you need a second set of eyes on repo shape or slow queries, we wrote dbt run slow? Why it happens and 7 fixes that work.

Implementation details that save hours later

Small choices up front keep the dashboard fast and reliable.

  • Time zones: pick one warehouse timezone for modeling; convert in BI at render time only if necessary.
  • IDs: store Stripe, HubSpot, and QuickBooks IDs as strings; avoid lossy numeric casts.
  • Late-arriving data: design incremental models to re-scan the last N days; store a watermark per table.
  • Backfills: build a toggle per model to force a full-refresh by date, not table-wide.
  • Access: separate “dashboard” reader roles from “explorer” roles so edits don’t break tiles during meetings.
  • Targets: store targets in a small table by period/segment so the dashboard can chart deltas cleanly.
-- targets table
create table if not exists analytics.targets (
  metric_name varchar,
  period_date date,
  segment varchar,
  target_value numeric
);

Dashboards help when they’re predictable: same layout every week, same owners, same definitions. If you change anything, call it out on the page in a one-line changelog. Keep the homepage query set tiny and push deep dives to linked explores. When you add a new tile, delete an old one.

FAQ: types, healthcare context, and integrated views

What are the four types of dashboards? Strategic (board-level), operational dashboards (front-line cadence), analytical (exploratory), and tactical/KPI (owner-level execution). What is a health dashboard? In healthcare, it’s a governed view aggregating clinical, financial, and operational signals to guide health management. What does a KPI dashboard look like? One page with key performance indicators, owners, targets, and trend spark lines. What is the CMS dashboard? Typically Centers for Medicare & Medicaid Services reporting tiles tracking measures and compliance deadlines. How do integrated dashboards improve decision-making? They join systems so teams make informed decisions without reconciling exports.

What are healthcare dashboards used for? A healthcare organization monitors patient satisfaction, patient care, population health, and care quality across health systems. They often join the electronic health record with claims and staffing to improve patient outcomes. Who uses them? Healthcare professionals and healthcare executives for planning and daily ops. Want more dashboard examples? Start with your own data and sketch business dashboard examples you can actually maintain; copy only patterns you can explain in one sentence. What are the benefits of using healthcare dashboards? Visibility, compliance readiness, and faster coordination across electronic health data.

Key features of a business dashboard? Clear ownership, targets, filters that match language in sales/support, and fast tiles. Integrated feeds from CRM, billing, and product logs. A single glossary of performance indicators. Ready to see AI-augmented surfaces elevate decision-making? Our take on stickier agent patterns is here: AI for Data Teams: Workflows That Actually Stick.


If you want this built right the first time—or want a review before launch—start with a quick scoping call: Start a project with Vertex.

About the author

Eric Provencio Analytics engineer who has built and run production data platforms for Disney, Hulu, Nike, Peloton, Gopuff, and Kaplan. Founded Vertex Data Consulting to do the deep work most data teams never find time for: dbt Cloud migrations, repo performance, Airflow reliability, and AI agents that actually touch the stack.

Keep reading

Start a conversation

Tell us what's slowing your data team down.

We maintain a small client roster on purpose. If we're the wrong fit, we'll say so — and usually we know somebody who isn't.

  • Replies within 2 business days
  • NDA before specifics
  • Fixed-scope first engagement, retainer if it works
What do you want help with? *

We reply within 2 business days if there's a fit. No newsletters, ever.