How do I calculate the average response time per message?
The average response time per message is calculated like this: for each incoming message, you take the timestamp of that incoming message and the timestamp of the first reply the business gives in that same conversation; you subtract the first from the second and get the delay for that message. You add up all the delays and divide by the number of incoming messages that did get a reply. The result, expressed in minutes or hours, is your average response time. If you also want the average per conversation instead of per message, first you group by contact and count only the delay until the first reply in each thread.
It sounds simple, but 90% of calculations that go wrong don't fail on the subtraction: they fail on which rows are included, which timestamp is used, and what counts as a reply. Below is the detail of each decision, with the cases where the number changes drastically.
Why the calculation seems easy and almost always comes out wrong
The formula is elementary, but WhatsApp Business data doesn't come as an ordered pair ready to subtract. It comes as a list of events: incoming message, incoming message, outgoing message, incoming message, outgoing message. Before calculating, you have to define five things: what counts as an incoming message, what counts as a reply, what happens with messages that get no reply, how you handle messages outside business hours, and which time column you use. Each of those decisions moves the average by several points.
The most common mistake is using the wrong column. In many databases there are two different timestamps: one that records when Meta processed the message (the real event timestamp) and another that records when the row was inserted into your database (created_at). If you imported history from a migration, the created_at of thousands of old messages all falls on the same day, at the same time. Any average calculated on that column will say your business replies at 15:00 on a Tuesday, always. It's not data: it's an import artifact. The rule is simple: use the timestamp Meta sends, never the created_at.
Before publishing or reporting any average, do a quick test: plot the distribution of times of your incoming messages. If 50% or more fall in a single hour of the day, you're looking at created_at and not the real timestamp. Real businesses have a curve with peaks in the mid-morning, at midday and in the afternoon.
What counts as a "reply" and what doesn't
A reply is an outgoing message from the business within the same conversation, after the incoming message. But not every outgoing message counts the same. An automatic welcome message that fires at 2 in the morning is not the same as a person typing. If you mix the two, your average plummets and the number stops reflecting the customer's real experience.
- Count as a response only outgoing messages that come after the incoming message in the same conversation.
- Decide whether automated messages (welcome, after-hours) count as a response. If you count them, also calculate a separate average without them, because they are two different metrics.
- An incoming message answered with three outgoing messages counts only once: the delay is until the first one.
- Messages that never received a response do not go into the average response time, but they do go into the response rate. Report both together or the average will lie.
- Voice notes, images and documents are also messages. If your inbox receives them, they count.
The most debated decision is what to do with unanswered messages. If you exclude them, your average response time looks better than it is. If you count them as infinite, the average breaks. The standard solution is to report two numbers: average response time (only over answered messages) and response rate (answered over total). A business that answers 60% of messages in 5 minutes and leaves 40% unanswered does not have an average time of 5 minutes: it has a coverage problem.
Step by step: how to build it in a spreadsheet
- 1Export the messages with at least four columns: conversation id, direction (incoming/outgoing), actual event timestamp and message type.
- 2Sort by conversation and by ascending timestamp. Without this order, the subtraction makes no sense.
- 3For each incoming message, find the first outgoing message after it within the same conversation. In Excel or Google Sheets that is done with a conditional lookup; in SQL, with a window function like MIN() OVER (PARTITION BY conversation).
- 4Subtract: delay = outgoing_timestamp - incoming_timestamp. Convert the result to minutes.
- 5Discard negative or absurd delays (more than 7 days) and review them separately: they are almost always old reactivated conversations or time zone errors.
- 6Calculate the average with AVERAGE() or AVG(). Also calculate the median: if the median is much lower than the average, you have a few very bad cases dragging the number up.
- 7Segment by time slot and by day of the week. The overall average hides the fact that you answer in 2 minutes at 11:00 and in 4 hours at 21:00.
If your volume is small, the spreadsheet is enough. If you go over thousands of messages per month, it is better to do it in SQL or in a BI tool, because the conditional lookup in the spreadsheet becomes slow and fragile. In any case, save the script or the spreadsheet: the number is only useful if you can recalculate it every month with the same criteria.
Time zone: the detail that ruins more averages than any other
WhatsApp API timestamps usually come in UTC. If your team works in Buenos Aires, Mexico City or Bogota, and you do not convert the time zone, your calculation will be off by between 3 and 6 hours. That does not change the overall average if all messages are off by the same amount, but it destroys any analysis by time slot: you will believe you answer quickly at 3 in the morning when it is actually 10 at night.
The practical rule: convert everything to the business time zone before segmenting. And if you have teams in several countries, save the timestamp in UTC and add a column with the contact's time zone, so you can break down the analysis by region.
The average alone is not enough: look at the distribution
An average of 12 minutes can mean two opposite things: that you answer almost everything in 10 to 15 minutes, or that you answer half in 1 minute and the other half in 23. The customer experience is completely different. That's why, along with the average, you should also report the median and the 90th percentile.
- Average: sum of all delays divided by the number of cases. Sensitive to extreme cases.
- Median: the value that leaves half of the cases below it. It better reflects the typical case.
- 90th percentile: the delay that 90% of messages do not exceed. It measures how bad things go for the unluckiest customer.
- Response rate: percentage of incoming messages that received at least one reply.
If the average is 15 minutes, the median is 4 minutes and the 90th percentile is 3 hours, your problem is not overall speed: it's a few messages that go unanswered. That's where you should look at what happened with those cases, not lower the overall average.
Outside business hours: does it count or not?
A message that comes in at 23:40 and is answered at 9:10 the next day has a delay of 9 and a half hours. Is it fair to count it? It depends on what you want to measure. If your goal is to evaluate the customer experience, yes: the customer waited 9 and a half hours. If your goal is to evaluate the team's performance, no: nobody was working.
The solution is to calculate two metrics: response time during business hours (only messages that came in during business hours) and total response time (all of them). The difference between the two is, in practice, the cost of having the inbox closed. If your hours are from 9:00 to 18:00 and the total average is double the average during business hours, you know that half of your delay comes from messages that come in when no one is there.
How to lower it without lying to yourself
Lowering the average response time is not about replying faster to the easy messages. It is about attacking the two extremes: the ones that come in outside business hours and the ones that are left unanswered. There are three concrete levers.
- After-hours coverage: an automatic reply by schedule that lets the customer know when you will respond. It does not lower the actual delay, but it lowers the customer's anxiety and prevents them from writing three more times.
- Prioritization: if the inbox shows unanswered messages that have been waiting the longest first, the 90th percentile improves without anyone working faster.
- Ready-made drafts: when the team does not have to write from scratch, the time to first contact drops. In Wando, the AI suggests a reply based on how the business responded before and the agent approves it with one click; this reduces the time between reading and replying, without taking control away from the person.
What does not work is measuring one thing and managing another. If you report the average only for messages answered during business hours, you will have a nice number and angry customers. Report both metrics together and the average becomes a management tool, not a decoration in the report.
How often to recalculate it and what to compare it with
Average response time moves with seasonality. A food business does not respond the same way on a Tuesday at 15:00 as on a Saturday at 21:00. Calculating it once a year is useless. The reasonable frequency is weekly for the overall number and monthly for the analysis by time slot and by agent.
For comparison, use your own historical series before any external benchmark. Industry averages vary too much by sector, size, and channel, and the sources that publish a single number usually do not clarify how they calculated it. Your best reference is your previous month with the same calculation criteria.
Common mistakes that inflate or deflate the number
- Using created_at instead of the event timestamp. It inflates or flattens everything depending on when you imported the data.
- Not converting from UTC to the business's time zone. It breaks the analysis by time slot.
- Counting automatic messages as a human reply. It lowers the average artificially.
- Excluding unanswered messages from the denominator. It raises the response rate and hides the real problem.
- Averaging over conversations instead of over messages, or vice versa, without clarifying which. Both numbers are valid but not comparable.
- Mixing channels (WhatsApp, Instagram, Messenger) into a single average when volumes and teams are different.
If you are going to report the number externally, write next to it how you calculated it: over which time column, whether you included messages without a response, whether you counted automated ones and in which time zone. An average without a methodology cannot be audited and, sooner or later, someone will calculate it differently and it will look like you lied.
Frequently asked questions
Is the average response time calculated per message or per conversation?+
They are two different metrics. Per message: each incoming message is subtracted against the first subsequent reply in that conversation. Per conversation: only the first incoming message of each thread is taken and subtracted against the first reply. The per-conversation one is usually higher because it includes messages that come in after the customer has already been served. Pick one, state it clearly, and don't mix the two in the same report.
What do I do with messages that never received a reply?+
Don't include them in the average delay, because they have no measurable delay. But do count them separately as a response rate: replied over total incoming messages. Reporting the average without the response rate gives an incomplete picture, because a business can have an excellent average and leave half of its messages unanswered.
Why does my average show that all messages arrive at the same time?+
You are almost certainly using the created_at column (when the row was saved in your database) instead of the real event timestamp that Meta sends. If you imported history from a migration, thousands of old messages share the same created_at. Switch to the event timestamp column and the time-of-day analysis will show a normal curve.
Does an automatic welcome message count as a reply?+
Technically it is an outgoing message and it can be counted, but it's better to calculate it separately. An average that mixes automatic replies with human replies doesn't reflect the real customer experience or the team's performance. The most useful approach is to report three numbers: delay until the first automatic message, delay until the first human reply, and total delay.
How often should the average response time be recalculated?+
Weekly for the overall number and monthly for breakdowns by time slot, day of the week, and agent. The metric moves with seasonality and with team changes, so an annual calculation quickly becomes outdated. The important thing is to always use the same criteria so the series stays comparable.
Is it useful to compare my average with that of other companies?+
Carefully. Averages published by industry rarely state how they were calculated: whether they included unanswered messages, whether they counted automatic ones, what time zone they used. Your best reference is your own historical series with consistent criteria. If you still want an external benchmark, look for one that documents its methodology and compare only what is comparable.
Answer WhatsApp with AI
Try Wando free. No credit card required.