Metric · Support

What is deflection rate, and how do you measure it in Metabase?

Deflection rate is the share of support demand resolved by self-service instead of a human: self-service resolutions ÷ (self-service resolutions + tickets created). It's the metric behind every help-center and support-bot investment — and the easiest support metric to flatter, because "resolution" is doing a lot of work in that definition. Measure it honestly in Metabase from help-center, bot, and ticket data synced into a database (Zendesk, Intercom, Freshdesk, or Front).

TL;DRself-service resolutions ÷ (self-service resolutions + tickets created), where a resolution requires an explicit signal (article feedback, bot confirmation) and no ticket within 72 hours. Views are not deflections, and the guardrail is the reopened-as-ticket rate.

What deflection rate measures

It measures how much demand your self-service layer absorbs before it becomes a ticket — the denominator is total demand (deflections plus tickets), not just tickets, so a rising rate genuinely means self-service is carrying more of the load. The honest version rests on stated assumptions:

  • Explicit signals only — an article feedback click of "solved my problem," a bot resolution the user confirms. A page view or a bot conversation that merely ended proves nothing.
  • A no-ticket window — the signal only counts if the same user opens no ticket within a fixed window (72 hours is a sane default). This requires a joinable user identity across help center, bot, and help desk.
  • A quality guardrail — the reopened-as-ticket rate: deflected users who file the same question as a ticket soon after. Deflection that defers contact instead of resolving it is just added friction.

Segmented by article or topic, it becomes a content roadmap: high-traffic topics with weak deflection are the articles to rewrite, and topics with high escalation rates and no self-service coverage are the ones to write next.

What data does it need?

  • A modeled self_service_events table: help-center article feedback, bot conversation outcomes, and (optionally, labeled as weaker) identified search sessions — each with a user key and timestamp.
  • The tickets table with requester_id and created_at, for both the denominator and the no-ticket window check.
  • A user identity that joins across systems — email or a resolved customer ID. Anonymous help-center traffic can't be windowed and belongs in a separate, clearly-labeled estimate.
  • Article and topic metadata, so the per-article ranking has names on it.

SQL patterns

Monthly deflection rate with a 72-hour windowPostgreSQL

Explicit success signals, minus anyone who opened a ticket within 72 hours.

-- Monthly deflection rate from an explicit-signal self-service model.
-- A self-service event counts as a resolution only if (a) it carries an
-- explicit success signal and (b) the same user opened no ticket within
-- 72 hours. Assumes user identity is joinable across both tables.
WITH deflected AS (
  SELECT
    date_trunc('month', s.occurred_at) AS month,
    COUNT(*)                           AS self_service_resolutions
  FROM self_service_events s
  WHERE s.event IN ('article_marked_helpful', 'bot_resolution_confirmed')
    -- Only count events whose 72-hour no-ticket window has fully closed.
    -- A brand-new event has no follow-up ticket YET, so counting it now
    -- would inflate today's deflection and quietly reverse tomorrow.
    AND s.occurred_at < NOW() - INTERVAL '72 hours'
    AND NOT EXISTS (
      SELECT 1
      FROM tickets t
      WHERE t.requester_id = s.user_id
        AND t.created_at BETWEEN s.occurred_at
                             AND s.occurred_at + INTERVAL '72 hours'
    )
  GROUP BY 1
),
created AS (
  SELECT
    date_trunc('month', t.created_at) AS month,
    COUNT(*)                          AS tickets_created
  FROM tickets t
  GROUP BY 1
)
SELECT
  d.month,
  d.self_service_resolutions,
  c.tickets_created,
  ROUND(100.0 * d.self_service_resolutions
        / NULLIF(d.self_service_resolutions + c.tickets_created, 0), 1)
    AS deflection_rate_pct
FROM deflected d
JOIN created c USING (month)
ORDER BY d.month;
Top deflecting articlesPostgreSQL

Ranks articles by confirmed deflections and shows how often users ticketed anyway.

-- Top deflecting articles, last 90 days: confirmed self-service
-- resolutions with no follow-up ticket within 72 hours, ranked.
SELECT
  s.article_id,
  s.article_title,
  COUNT(*) AS confirmed_resolutions,
  COUNT(*) FILTER (
    WHERE EXISTS (
      SELECT 1
      FROM tickets t
      WHERE t.requester_id = s.user_id
        AND t.created_at BETWEEN s.occurred_at
                             AND s.occurred_at + INTERVAL '72 hours'
    )
  )        AS ticket_anyway,
  COUNT(*) FILTER (
    WHERE NOT EXISTS (
      SELECT 1
      FROM tickets t
      WHERE t.requester_id = s.user_id
        AND t.created_at BETWEEN s.occurred_at
                             AND s.occurred_at + INTERVAL '72 hours'
    )
  )        AS deflections
FROM self_service_events s
WHERE s.event IN ('article_marked_helpful', 'bot_resolution_confirmed')
  AND s.occurred_at >= current_date - INTERVAL '90 days'
  -- Same 72-hour maturity guard as the monthly query: an event too recent
  -- to have accrued its follow-up ticket can't be scored as a deflection yet.
  AND s.occurred_at < NOW() - INTERVAL '72 hours'
GROUP BY s.article_id, s.article_title
ORDER BY deflections DESC
LIMIT 25;

Pitfalls

Counting page views as deflections.→ Views measure traffic, not resolution — this is the inflation that makes deflection numbers untrustworthy. Require an explicit success signal, and disclose the definition on the card.
Skipping the no-ticket window.→ A user can click "helpful" and file a ticket an hour later. Without the window you count both a deflection and a ticket for the same problem, flattering the rate while volume stays flat.
Ignoring deflection quality.→ A bot that wears users down until they give up scores as deflection and shows up later as churn. Watch the reopened-as-ticket rate and CSAT for users who touched self-service first.
Blending signal tiers into one number.→ Confirmed bot resolutions and mere no-ticket-after-search are different grades of evidence. Model them as separate tiers so the trustworthy core is visible when someone challenges the number.

Where this metric applies

Metrics

Analytics & dashboards

FAQ

Why can't I just count help-center page views as deflections?
Because a view proves interest, not resolution — the reader may have found nothing and opened a ticket anyway, or never intended to contact you at all. Counting views as deflections is how teams report 90% deflection while ticket volume keeps climbing. Use explicit success signals (article feedback, bot confirmations) combined with the absence of a follow-up ticket, and state the assumptions on the dashboard card.
What signals count as a self-service resolution?
The defensible ones are explicit: an article feedback click on "yes, this solved my problem," a bot resolution the user confirms, or — weaker, and worth labeling as such — a help-center search session from an identified user with no ticket within a set window. Each layer adds coverage and subtracts certainty, so keep the tiers separate in the model: a confirmed-signal deflection and a mere absence-of-ticket should never be summed into one undifferentiated count.
Why the no-ticket window, and why 72 hours?
The window catches the user who clicked "helpful" and then filed a ticket the next morning — a self-service attempt, not a self-service resolution. 72 hours is a pragmatic default: long enough to catch the delayed ticket, short enough that an unrelated later ticket doesn't erase a genuine deflection. The exact width matters less than keeping it fixed; widen it and the rate drops mechanically, so a changed window mid-series looks like a real regression.
How do you know deflected users were actually helped?
Track the guardrail: the reopened-as-ticket rate — the share of "deflected" sessions where the same user filed a ticket on the same topic shortly after the window. If it rises, your self-service content is absorbing contacts without resolving them, deferring tickets rather than deflecting them. Pair it with knowledge-base coverage to find topics where deflection fails because the article simply doesn't exist.
How do you track deflection rate in Metabase?
Get three datasets into one SQL database: help-center and article-feedback events, bot conversation outcomes, and tickets — synced with Airbyte, Fivetran, or exports from Zendesk, Intercom, Freshdesk, or Front. Model them into a self_service_events table with a shared user key, compute the monthly rate with the no-ticket window, rank articles by confirmed deflections, and pin both to the knowledge base health dashboard.