What does a CDP sync health dashboard show in Metabase?
A CDP sync health dashboard shows whether customer data is actually flowing — event volume by source, sync success rates by destination, freshness against SLOs, and schema quality in one governed view. It's the observability layer for a stack built on Segment, RudderStack, Hightouch, or Customer.io, built from the run logs and metadata those tools already produce.
Which cards belong on a CDP sync health dashboard?
- Hours since last successful sync by destination, vs. SLO (table)
- Sync success rate by destination by week (line)
- Events by source by day (stacked area)
- Volume anomalies — today vs. trailing 28-day average (table)
- Schema violations and blocked events by source (table)
- Rows synced to activation tools by week (stacked bar)
- Failed runs by error category, trailing 30 days (bar)
- Identified vs. anonymous event share (line)
What data does the dashboard need?
cdp_sync_runs— one row per sync run: destination, started/finished timestamps, status, rows attempted and synced, error category.event_volume_daily— one row per source per day, with allowed and blocked counts where the tool reports them.- Schema/tracking-plan violation counts per source per day, if enforced.
- A small
sync_slostable (destination, freshness SLO hours) so breach cards stay declarative.
How do you build it?
- Land run logs from each link in the chain: Hightouch's native
hightouch_audittables, Segment's Public API metadata, RudderStack's monitoring surface. - Model them into one
cdp_sync_runstable with consistent status and error categories, plusevent_volume_dailyper source. - Add the SLO table, then build freshness, success-rate, and volume-anomaly cards with destination and source filters.
- Alert on SLO breaches and consecutive failures — not single transient errors.
Example card SQL
SELECT
destination,
date_trunc('week', run_started_at) AS week,
COUNT(*) AS runs,
ROUND(
100.0 * COUNT(*) FILTER (WHERE status = 'success')
/ NULLIF(COUNT(*), 0), 2
) AS success_rate_pct,
SUM(rows_synced) AS rows_synced,
ROUND(AVG(EXTRACT(EPOCH FROM (
run_finished_at - run_started_at
))), 0) AS avg_duration_seconds
FROM cdp_sync_runs
WHERE run_started_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
ORDER BY 1, 2;Related
Metrics
Integrations
Dashboards
FAQ
Why monitor the CDP from Metabase instead of its own UI?
What's the first card to build?
Where does the sync log data come from?
hightouch_audit.sync_runs), pipeline metadata APIs (Segment's Public API event-volume and sync endpoints), and the delivery/monitoring surfaces of the CDP itself (RudderStack). A small scheduled script landing each into one cdp_sync_runs model is usually a day's work.