Metric

What is sync success rate, and how do you track it in Metabase?

Sync success rate is the share of data-pipeline runs that complete successfully, per destination. It's the headline reliability metric for a customer data stack: when it slips, every downstream tool — email, ads, support, analytics — quietly works from stale or partial data. Measure it in Metabase from the run logs your CDP and reverse-ETL tools produce (Segment, RudderStack, Hightouch, and others).

TL;DR — Sync success rate = successful runs ÷ all runs, per destination per period. Track a row-weighted version next to it, because a "successful" run that rejects half its rows is a failure the run count can't see.

How is sync success rate defined?

The formula is successful runs ÷ total runs over a window, grouped by destination. The grouping is the point: a healthy global average routinely hides one destination failing continuously.

  • Run — one scheduled or triggered execution of a sync from a source to a destination.
  • Successful — the run finished without a fatal error. Count partial completions separately; they're their own signal.

Runs vs. rows

Run-level success rate catches hard failures: expired credentials, API version changes, destination outages. But activation tools often mark a run successful while rejecting individual rows — invalid emails, missing required fields, rate-limited batches. Track both:

  • Run success ratesuccessful_runs ÷ runs. The pager metric.
  • Row success raterows_synced ÷ rows_attempted. The data-quality metric; a slow decline here means a schema or hygiene problem growing in the source.

What data does sync success rate need?

  • A sync run log with one row per run: run_started_at,run_finished_at, status, source, destination.
  • Row counts per run (rows_attempted, rows_synced, rejected rows) where the tool reports them.
  • An error category or message for failed runs, for the triage table.
  • The expected schedule per sync, so missed runs count against the rate instead of disappearing from it.

SQL patterns

Run success rate by destination by weekPostgreSQL
SELECT
  destination,
  date_trunc('week', run_started_at) AS week,
  COUNT(*)                                      AS runs,
  COUNT(*) FILTER (WHERE status = 'success')    AS successful_runs,
  ROUND(
    100.0 * COUNT(*) FILTER (WHERE status = 'success')
      / NULLIF(COUNT(*), 0),
    2
  ) AS success_rate_pct
FROM cdp_sync_runs
WHERE run_started_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
ORDER BY 1, 2;
Row-weighted success rate by destinationPostgreSQL
SELECT
  destination,
  date_trunc('week', run_started_at) AS week,
  SUM(rows_attempted)                           AS rows_attempted,
  SUM(rows_synced)                              AS rows_synced,
  ROUND(
    100.0 * SUM(rows_synced) / NULLIF(SUM(rows_attempted), 0),
    2
  ) AS row_success_rate_pct
FROM cdp_sync_runs
WHERE run_started_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
ORDER BY 1, 2;
Failed runs by error category, trailing 30 daysPostgreSQL
SELECT
  destination,
  error_category,
  COUNT(*) AS failed_runs,
  MAX(run_started_at) AS most_recent_failure
FROM cdp_sync_runs
WHERE status <> 'success'
  AND run_started_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY 1, 2
ORDER BY failed_runs DESC;

Pitfalls

Averaging across destinations.→ A fleet-wide 99.5% can coexist with one destination at 0% for a week. Group by destination, and alert on the worst destination, not the mean.
Trusting run status alone.→ Runs that "succeed" while rejecting rows are the common failure mode of audience syncs. Put the row-weighted rate next to the run rate.
Missing the runs that never happened.→ A paused or unscheduled sync produces no failures — and no rows. Compare actual runs against the expected schedule, or pair this metric withdata freshness.
Alerting on single failures.→ Transient destination errors self-heal on retry. Alert on consecutive failures or a rate drop over a window, or the alert channel gets muted within a month.

Where this metric applies

Analytics

Dashboards & metrics

FAQ

What's a good sync success rate?
Healthy pipelines run well above 99% of runs succeeding — but the number that matters is the trend per destination, not a global average. One destination failing every run for a day is an incident even if the fleet-wide rate barely moves. Alert on per-destination drops and on any destination with zero successful runs in its expected schedule window.
Should I measure runs or rows?
Both. Run success rate catches hard failures (auth expiry, API changes, destination outages). Row-weighted success rate catches the quieter problem of partial syncs, where the run 'succeeds' but a growing share of rows is rejected — track it as rows_synced ÷ rows_attempted alongside the run rate.
Where does sync run data come from?
Reverse-ETL and activation tools usually write audit logs to your warehouse natively — Hightouch lands hightouch_audit tables, and warehouse-connected CDPs like Segment and RudderStack expose sync metadata through their APIs and monitoring exports. Land whatever run-level log the tool offers and model it into one cdp_sync_runs table.
How is sync success rate different from data freshness?
They fail differently. Success rate catches runs that error; data freshness catches runs that silently stop being scheduled, or succeed while moving nothing. A destination can show 100% success on one run a week when it should run hourly — freshness is the metric that notices.