What is first-response time, and how do you measure it in Metabase?
First-response time (FRT) is how long a customer waits from opening a ticket to the first human reply. It's the clearest early signal of responsiveness, and it moves CSAT more than almost any other support metric. Measure it in Metabase from help desk data synced into a database (Zendesk, Intercom, Front, or Freshdesk).
How is first-response time calculated?
For each ticket, FRT = timestamp of the first agent reply − ticket created timestamp. Then aggregate across tickets with a percentile, not a mean:
- Median FRT — the typical wait; half of customers waited less, half more.
- p90 FRT — the tail; what your slowest 10% of customers experience.
If you promise response SLAs in business hours, subtract nights, weekends, and holidays from the elapsed time before you aggregate — otherwise a ticket opened Friday evening looks like a failure on Monday.
What data does first-response time need?
- A tickets/conversations table with a
created_attimestamp. - The first agent reply timestamp — either stored on the ticket, or derived from a
messagestable (first non-automated agent message). - An author type or role so you can exclude bots, autoresponders, and the requester's own follow-ups.
- Optionally, a business-hours calendar or SLA policy for business-time FRT.
SQL patterns
Percentiles over the response gap, aggregated weekly.
-- Median first-response time in hours, by week.
-- Assumes a modeled tickets table with the first human reply timestamp.
SELECT
date_trunc('week', t.created_at) AS week,
PERCENTILE_CONT(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (t.first_response_at - t.created_at)) / 3600.0
) AS median_frt_hours,
PERCENTILE_CONT(0.9) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (t.first_response_at - t.created_at)) / 3600.0
) AS p90_frt_hours
FROM tickets t
WHERE t.first_response_at IS NOT NULL
GROUP BY date_trunc('week', t.created_at)
ORDER BY week;When the first reply isn't stored on the ticket, take the earliest human agent message.
-- Derive first response from a messages table when it isn't
-- stored on the ticket. First non-automated agent message wins.
WITH first_reply AS (
SELECT
m.ticket_id,
MIN(m.created_at) AS first_response_at
FROM messages m
WHERE m.author_type = 'agent'
AND m.is_automated = false
GROUP BY m.ticket_id
)
SELECT
t.id,
t.created_at,
fr.first_response_at,
EXTRACT(EPOCH FROM (fr.first_response_at - t.created_at)) / 3600.0 AS frt_hours
FROM tickets t
JOIN first_reply fr ON fr.ticket_id = t.id;Pitfalls
Where this metric applies
- Zendesk + Metabase — ticket
created_atand first public agent comment - Intercom + Metabase — conversation created and first admin reply part
- Front + Metabase — conversation and first outbound teammate message
- Freshdesk + Metabase — ticket and first agent response event