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).
self-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_eventstable: 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_idandcreated_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
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;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
Where this metric applies
- Zendesk + Metabase — help center article feedback plus ticket creation
- Intercom + Metabase — bot resolution outcomes and conversation data
- Freshdesk + Metabase — knowledge base feedback and ticket records
- Front + Metabase — knowledge base activity alongside conversation volume
Related
Metrics
Analytics & dashboards
FAQ
Why can't I just count help-center page views as deflections?
What signals count as a self-service resolution?
Why the no-ticket window, and why 72 hours?
How do you know deflected users were actually helped?
How do you track deflection rate in Metabase?
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.