← Blog

·

WhatsApp customer service metrics: response time, handling time, CSAT and how to measure them

Updated on October 25, 2026

The core WhatsApp customer service metrics are first response time, average response time, average handling time and CSAT (customer satisfaction). With the official WhatsApp Business API, all of them can be calculated from the timestamps in your webhooks: the time of each customer message and the time each reply was sent. The WhatsApp Business app does not give you this level of detail per agent; with the API, the data sits in your database and you measure it the way your operation needs.

In Brazil these metrics often go by their Portuguese acronyms, TMR (tempo médio de resposta, average response time) and TMA (tempo médio de atendimento, average handling time), so you may see them in Brazilian dashboards and tools.

The metrics that matter

Names vary from company to company. What matters is fixing one definition and always using it:

MetricQuestion it answersCalculation
First response time (FRT)How long does the customer wait for the first reply?First business reply − first customer message in the conversation
Average response time (TMR)How long does the customer wait on each message?Average gap between a customer message and the next reply
Average wait timeHow long does the chat sit in the queue?Assignment to an agent − entering the queue
Average handling time (TMA)How long does a conversation last?Closing − start of the conversation
CSATWas the customer satisfied?Positive ratings ÷ total ratings
First contact resolutionDid we solve it without the customer coming back?Chats closed with no reopening within X days ÷ chats closed
Chats unanswered for 24 hDid we miss the window?Chats where the customer waited 24 h with no reply ÷ total

The last one is specific to WhatsApp. Under the 24-hour customer service window rule, if the business does not reply within that period, it can only resume with an approved template. A chat that misses the window is an unhappy customer and an extra cost.

Where the timestamps come from

On the official API, two kinds of event feed your metrics:

Incoming message. The webhook includes messages[].timestamp, in Unix seconds (UTC), with the time the customer sent it:

{
  "from": "5511999999999",
  "id": "wamid.HBgLNTUx...",
  "timestamp": "1792929600",
  "type": "text",
  "text": { "body": "My order hasn't arrived" }
}

Status of a sent message. The API response to a send returns only the wamid, with no time. The send time arrives later, in the sent status webhook, with the same id:

{
  "id": "wamid.HBgLNTUx...",
  "status": "sent",
  "timestamp": "1792929735",
  "recipient_id": "5511999999999"
}

The following statuses (delivered, read, failed) arrive with their own timestamps. The article on message status webhooks covers each one.

Three precautions to keep the numbers honest:

  • Use the event timestamp, not the webhook arrival time. Meta retries unacknowledged events for up to 7 days, and they may arrive late or duplicated.
  • Separate bot from human. Store who originated each outgoing message (bot, agent, automation). An automatic welcome sent in 2 seconds should not count toward the team’s FRT.
  • Account for business hours. A message at 11pm answered at 8am is 9 clock hours and zero working hours. Calculate both and make clear which one the dashboard shows.

Minimum data model

To calculate everything above, each message needs these fields:

FieldSource
wamidmessages[].id or the send response
conversation_idYour system
directioninbound or outbound
authorcustomer, bot, agent, automation
agent_idYour system
sent_atmessages[].timestamp (inbound) or the sent status (outbound)
delivered_at, read_atdelivered and read statuses

And each conversation: opened_at, queued_at, assigned_at, closed_at, and the CSAT score if any.

Calculating response time and FRT in SQL

With messages in PostgreSQL, the LAG function finds the previous customer message for each reply. The query below returns, per agent, the median and 90th percentile response time over the last 30 days:

WITH turns AS (
  SELECT
    conversation_id,
    author,
    agent_id,
    sent_at,
    LAG(author)  OVER w AS prev_author,
    LAG(sent_at) OVER w AS prev_at
  FROM messages
  WHERE sent_at >= now() - interval '30 days'
  WINDOW w AS (PARTITION BY conversation_id ORDER BY sent_at)
)
SELECT
  agent_id,
  COUNT(*) AS replies,
  percentile_cont(0.5) WITHIN GROUP (ORDER BY sent_at - prev_at) AS response_median,
  percentile_cont(0.9) WITHIN GROUP (ORDER BY sent_at - prev_at) AS response_p90
FROM turns
WHERE author = 'agent' AND prev_author = 'customer'
GROUP BY agent_id
ORDER BY response_median;

For first response time, take the first customer message and the first agent message in each conversation:

SELECT
  c.id,
  MIN(m.sent_at) FILTER (WHERE m.author = 'agent')
    - MIN(m.sent_at) FILTER (WHERE m.author = 'customer') AS first_response
FROM conversations c
JOIN messages m ON m.conversation_id = c.id
WHERE c.opened_at >= now() - interval '30 days'
GROUP BY c.id;

Why median and 90th percentile instead of just the average? Because a handful of chats forgotten over the weekend push the average up and hide normal behavior, and the average alone also hides the customers who waited far too long. The median shows what is typical; the p90 shows who is being poorly served.

Measuring CSAT inside WhatsApp

CSAT is the “from 1 to 5, how was your support?” question sent when a conversation closes. On WhatsApp, the best format is an interactive message: the customer taps instead of typing and the answer arrives structured. Reply buttons allow up to three options; for a 1-to-5 scale, use a list. The list messages documentation allows up to 10 rows, row titles up to 24 characters and button text up to 20.

{
  "messaging_product": "whatsapp",
  "to": "5511999999999",
  "type": "interactive",
  "interactive": {
    "type": "list",
    "body": { "text": "Your support chat is closed. How would you rate the help you received?" },
    "action": {
      "button": "Rate",
      "sections": [{
        "title": "Your rating",
        "rows": [
          { "id": "csat_5", "title": "5 - Excellent" },
          { "id": "csat_4", "title": "4 - Good" },
          { "id": "csat_3", "title": "3 - Fair" },
          { "id": "csat_2", "title": "2 - Poor" },
          { "id": "csat_1", "title": "1 - Very poor" }
        ]
      }]
    }
  }
}

The answer arrives as type: "interactive" with interactive.list_reply.id set to the id of the selected row. Store the score on the conversation.

Details that make a difference:

  • Send it right after closing. The 24-hour window is still open, so no template is needed.
  • Ask one question. If the score is 1 or 2, ask for the reason next and route it to a supervisor.
  • Calculate CSAT as the percentage of 4 and 5 ratings. And track the response rate: a high CSAT with few responses says little.
  • Cost. Since October 1, 2026, service messages are charged from the 1,001st delivered per month, per number, according to Meta’s pricing page. Factor the survey in.

For NPS and surveys after the product is delivered, when the window has already closed, see post-sale and NPS on WhatsApp.

How to set targets

This article deliberately does not quote “industry benchmarks”: generic numbers say little about your operation. A more useful path:

  1. Measure for two to four weeks without changing anything. That is your baseline.
  2. Set targets on percentiles, not averages. For example: “90% of first responses within X minutes during business hours”.
  3. Treat the 24-hour window as a hard ceiling. The target for “chats unanswered for 24 h” should be close to zero.
  4. Split by queue and time of day. Sales and support move at different speeds; Monday morning is not Thursday afternoon.
  5. Review monthly. A target you beat comfortably becomes the new baseline.

Indicators on Meta’s side

Besides support metrics, track two indicators that Meta calculates itself:

  • Phone number quality rating. Green, yellow or red, based on recent blocks and reports. Slow support and out-of-context messages make it worse. See number quality on the API.
  • Delivery and read rates. Share of sent messages that reach delivered and read. A sudden drop usually points to a problem with the number, a template or a list.

How to do this with Vectalk

With Vectalk, message and status webhooks are Meta’s, with the same timestamp fields used above; register your URL with POST /api/webhooks and store the events in your database. To check or rebuild data, GET /api/messages lists history with filters for date, status, direction and messageId. For aggregate indicators (sent, delivered, read, failed, rates and number quality), use GET /api/analytics/instances/{instanceId}/stats, grouped by day, week or month. Per-agent support metrics (response time, handling time, CSAT) depend on your own system’s data, as in the example. Details at docs.vectalk.com.br; sign up at apps.vectalk.com.br/register.

To build the operation that produces these numbers, see multi-agent support with the API and welcome and away messages.

Frequently asked questions

What is the difference between response time and handling time?

Average response time measures how long the customer waits on each message for a reply. Average handling time measures the full length of the conversation, from start to close. An operation can have a low response time and a high handling time, for example when a problem takes many back-and-forth messages.

Do bot replies count toward response time?

It depends on what you want to measure. For customer experience, they do. For evaluating the team, they do not. That is why you should store the author of each message and calculate both versions.

Can I use the API response time instead of the status webhook?

The send response has no timestamp, only the wamid. You can use your server’s clock at send time as an approximation, but the sent status is Meta’s record and is more consistent.

How do I measure CSAT if customers do not answer the survey?

Track the response rate separately and do not fill in missing scores. If few people respond, test a different send time or question wording.

Can I get these metrics from the WhatsApp Business app?

Not at this level of detail. The app does not record who replied or how long each agent took. Per-agent metrics require the API and a system that stores the events.


Official sources consulted on October 25, 2026: Messages webhook, Webhooks overview, Interactive list messages, Platform pricing, Vectalk docs: instance stats, Vectalk docs: list messages.

Integre o WhatsApp oficial ao seu sistema

A Vectalk entrega a Cloud API da Meta com os mesmos payloads e webhooks, um token para todas as contas e documentação completa.