What is resolution time, and how do you measure it in Metabase?
Resolution time is how long it takes to fully solve a ticket, from the moment it's created to the moment it's resolved. It's the throughput counterpart to first-response time: a fast first reply means little if tickets then sit for days. Measure it in Metabase from help desk data synced into a database (Zendesk, Intercom, Front, or Freshdesk).
How is resolution time calculated?
For each solved ticket, resolution time = resolved timestamp − created timestamp. Two decisions shape the number:
- Full vs. active time — full resolution time counts the whole clock; active resolution time subtracts periods where you were waiting on the customer (pending/on-hold).
- Which "resolved" counts — first solve, or final solve after any reopens. Reopens should extend the clock, not start a new ticket.
As with first response, aggregate with the median and p90 rather than the mean — a handful of long-running tickets will otherwise dominate.
What data does resolution time need?
- A tickets table with
created_atandresolved_at(orclosed_at) timestamps. - For active time, a status history table so you can subtract pending/on-hold periods.
- A reopen flag or status history so final resolution beats first solve.
SQL patterns
Percentiles over the created-to-resolved gap, by the week each ticket was solved.
-- Median and p90 resolution time in hours, by week the ticket was solved.
SELECT
date_trunc('week', t.resolved_at) AS week,
COUNT(*) AS resolved_tickets,
PERCENTILE_CONT(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (t.resolved_at - t.created_at)) / 3600.0
) AS median_hours,
PERCENTILE_CONT(0.9) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (t.resolved_at - t.created_at)) / 3600.0
) AS p90_hours
FROM tickets t
WHERE t.resolved_at IS NOT NULL
GROUP BY date_trunc('week', t.resolved_at)
ORDER BY week;Uses a status history table to remove time spent waiting on the customer.
-- Subtract time spent in a pending/on-hold state, using a status
-- history table (one row per status change).
WITH pending AS (
SELECT
h.ticket_id,
SUM(EXTRACT(EPOCH FROM (h.ended_at - h.started_at))) / 3600.0 AS pending_hours
FROM ticket_status_history h
WHERE h.status IN ('pending', 'on_hold')
GROUP BY h.ticket_id
)
SELECT
t.id,
EXTRACT(EPOCH FROM (t.resolved_at - t.created_at)) / 3600.0
- COALESCE(p.pending_hours, 0) AS active_resolution_hours
FROM tickets t
LEFT JOIN pending p ON p.ticket_id = t.id
WHERE t.resolved_at IS NOT NULL;Pitfalls
Where this metric applies
- Zendesk + Metabase — ticket
solved_atand status/audit history - Intercom + Metabase — conversation
stateand close events - Front + Metabase — conversation archive/close events
- Freshdesk + Metabase — ticket resolved/closed timestamps and status