Marketing agencies · WhatsApp

WhatsApp funnel

From ad to conversation, to handling and to sale, with a cost per conversation that does not pass for cost per sale.

UsageCommon
EffortMedium
ForAgencies that generate WhatsApp conversations for clients who close the sale in customer service.
Source

Media conversations, service tickets and CRM

Rule

Conversation linked to the ad and to the ticket

Outcome

Funnel and cost per conversation, ticket and sale

Activation

Dashboard, alerts and AI agent

What it solves

  • Cost per conversation stays separate from cost per sale, and the client stops comparing the two.
  • Each service ticket has a date, a line and an agent, without confusing contact with person.
  • The sale that came from the conversation is tied to the campaign that generated it.

Business questions it answers

Ask your agent these questions once the case is live.

How many conversations did each campaign generate and how much did each cost?
How many of those conversations were handled and how many became a sale?
Which WhatsApp line do customers reach most?
What is the wait time until first response, by day?
How many messages failed, and why?

What you need

  • The client's Meta Ads and Google Ads connected, with conversation campaigns identified by objective
  • The support tool or CRM connected, with the client's official list of numbers
  • An identifier linking the conversation to the ad: ad ID, ctwa_clid or a WhatsApp tracking tool

What you get

  • A service ticket table with date, line, department, agent and closing tag
  • The ad, conversation, service and sale funnel by campaign
  • An alert for campaigns pointing to an untracked number
  • An AI agent that answers about WhatsApp without calling a conversation a sale

Where to activate

Client dashboard

Conversations, tickets and sales by campaign, with the cost of each stage.

Setup alert

Campaign pointing to an untracked number or a line with no tickets that day.

AI agent via MCP

Answers how many conversations became sales, by line and by campaign.

Ready to build?

The media side is simple. The work is in the support tool, which changes from client to client, and in the key that links the conversation to the ad. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.

The problem

The platform counts conversations started and calls them results. The support tool counts occurrences, contacts and messages, each with several dates, and fields like closed mean a technical close, not a sale. Without a key between conversation and ad, the funnel breaks in the middle and the agency does not know which campaign sells.

How it is usually done, and the rule

Each row is a mistake that already happened in practice.

The common wayThe rule
01
Reporting cost per conversation as cost per sale.
A conversation started is top of funnel

In campaigns with optimization_goal CONVERSATIONS, the result is onsite_conversion.messaging_conversation_started_7d, and cost per conversation is those campaigns' spend divided by conversations started. On Google, the conversion is the WhatsApp click action, identified by the conversion action name. Neither is a qualified lead or a sale.

02
Counting table rows as customers served.
Ticket, contact and person are different

In the support tool, each occurrence (report.id in RD Station Conversas) is a service ticket, and the same contact has several. Unique contacts = distinct count of the contact ID within the tool, and that is not a unique person across systems. Always say which of the three is being counted.

03
Using opened_at as the conversation date.
One date for each question

The ticket's time axis is created_at, in the client's time zone. opened_at is the latest service session and, in a real API, only covered the last month, which would stack months of history into one. started_at, finished_at and closed_at answer their own questions and do not replace the creation date.

04
Counting closed tickets as sales.
Closed is not a sale

closed and closed_at record the technical close of the occurrence. They are not flow completion, success, conversion or sale. A sale comes from the CRM or a result field filled in by the team. The closing tag set by the agent (no reply, unqualified lead, sale) is worth more than any inference.

05
Filtering the line that carries the company name when asked about the company.
The WhatsApp line is a dimension

Clients with several numbers (sales, toll-free, events, branches) have the line identified by a technical integration key. Map the key to the operational name in a client table and filter by line only when the question is about a line: the client's name alone means the whole company, even if one line has the same name.

06
Accepting campaigns that point to any number.
All traffic to the tracked number

When the client uses a WhatsApp tracking tool, every paid campaign points to the number connected to it. A campaign that sends people to another number is a setup error and becomes an alert, because its conversations do not enter the funnel.

07
Matching by campaign name.
The bridge is the ad ID

Link the conversation to the ad through the ad ID that the tool or CRM stores (or the ctwa_clid), joined with the latest version of each ad. With no ID, use the normalized phone number (55, area code and number) and the phone's first conversation in the period. A typed campaign name is not a key.

08
Mean wait time.
Handling time by median

The tool delivers times as text (18h 10m 00s): convert to seconds. Use the median, never the mean, because a conversation answered at dawn destroys the mean. Separate business hours (valid_business_period) from the rest.

09
Summing all errors into one number.
A failed message has a cause

A message sent with status sent, delivered or read is a success; failed is an error. Separate errors of the team itself, errors from a closed 24-hour window and errors from the client's account. Template cost = messages sent x unit price of the template category; a category with no price stays null, not zero.

10
Sending the full phone number to the dashboard.
Phone numbers do not leave Nekt

For an external dashboard or app, pseudonymize the phone number (hash plus the last 4 digits) before it leaves. The full number stays in the internal layer only, used as a key.

WhatsApp funnel stages

Where each stage comes from and the field that counts it.

Meta · CONVERSATIONS objectiveConversation startedonsite_conversion.messaging_conversation_started_7d
Meta · advertiser replyFirst replyonsite_conversion.messaging_first_reply
Google · conversion actionWhatsApp clickconversion_action_name
Support toolService ticketreport.id
Support toolContactdistinct customer.id
Sale closing tag or CRMSalewon deal
closed = trueTechnical close, not a saleclosed_at

Definitions

Conversations started
sum of messaging_conversation_started_7d in conversation objective campaigns, in the period
Cost per conversation
spend of conversation campaigns / conversations started, over the same period
Service tickets
distinct count of occurrence IDs created in the period (created_at in the client's time zone)
Unique contacts
distinct count of the contact ID in the support tool, in the period
Service coverage
contacts that received a reply from the team / contacts that wrote in, in the period
Conversation to sale conversion
sales linked to conversations in the period / conversations in the period linked to an ad
Wait time
median, in seconds, of the time until first response, split by business hours
Cost per sale
spend of conversation campaigns / sales linked to those campaigns in the period

Pitfalls that already happened

Cheap conversation, expensive sale

Cost per conversation was below the agency's benchmark, and the client was losing money: many people opened a conversation and did not buy.

Show cost per conversation and cost per sale side by side.

Months stacked into one

opened_at carried each conversation's latest session and pushed the whole history into the current month, without any chart flagging an error.

Time axis on created_at.

Closed counted as a sale

The dashboard counted tickets with closed true as conversions, and the funnel showed almost 100% closing.

Sales only from the CRM or the closing tag.

Number outside tracking

One campaign pointed to another branch's WhatsApp, and its conversations vanished from the funnel.

Alert for campaigns with a number outside the client's list.

Ticket with no owner

The API's agents table came empty, and the dashboard showed tickets with no owner.

Take the agent from the ticket itself (employee field).

The company became a line

Questions about the company filtered only the line with the same name and showed a fraction of the contacts.

Line map applied only to line questions.

Acceptance test

The case is done when every item passes.

Agent package

Paste into Claude, ChatGPT or any client with the Nekt MCP connected.

Full Markdown
WhatsApp funnel
- A conversation started (onsite_conversion.messaging_conversation_started_7d) is top of funnel. It is not a qualified lead or a sale.
- Cost per conversation = spend of conversation objective campaigns / conversations started.
- Service ticket = one occurrence in the tool (report.id). Contact = contact ID in the tool. Neither is a unique person across systems.
- Ticket date = created_at in the client's time zone. opened_at is the latest session; closed_at is a technical close.
- A sale comes from the CRM or the sale closing tag set by the team. closed = true is not a sale.
- Filter by WhatsApp line only when the question is about a line. The client's name alone is the whole company.
- Wait and handling time: median in seconds, split by business hours.
- Phone numbers leave Nekt only pseudonymized.
Per-client exceptions:
- <client>: tracked number <number>; a campaign pointing to another number is a setup error.
- <client>: lines <integration-1> = <sales>, <integration-2> = <toll-free>.
- <client>: sale = closing tag <sale> at the end of the ticket; time zone <time zone>.

Variations

Orders through chat

For delivery and retail: contacts, orders created and orders delivered by day and by channel.

Template cost

Messages sent by template category times the category price, per broadcast campaign.

AI assistant in service

Handoff and resolution without a human measured from the closing tags.