← The Manifest
Marketing·3 October 2026·10 min read

Cost per booking, not per lead: trace WhatsApp enquiries to ads

Meta reports cost per WhatsApp chat, not cost per booking. An ad code, one sheet column and monthly maths show which campaigns actually sell trips.

Paris · 19:05

Ads Manager says your Kashmir campaign costs ₹150 a chat. It still cannot tell you whether that chat paid an advance. For an agency selling through WhatsApp, cost per booking, not cost per lead or cost per chat, is the only number that tells you whether an ad made money.

Meta's default click-to-WhatsApp setup optimises for the wrong thing: maximising conversations, and a conversation is any first message, including a "price bhejo" one-liner or a client returning after a week of silence. On that setup, the advance a chat pays twelve days later never reaches Ads Manager.

This post traces enquiries to bookings without buying anything: a code on every ad, one new sheet column, the advance linked back to that row, and cost per booking read monthly by campaign. Sending bookings back to Meta comes later, once the sheet already works.

Why cost per chat lies when the booking happens on WhatsApp

Meta's numbers are not wrong, they answer a different question. Under the Leads objective, click-to-WhatsApp ads default to the goal "maximise number of conversations" (Meta's help on creating click-to-WhatsApp ads, as of October 2026), and cost per conversation is simply spend divided by that count, where a conversation is the first message from an account, or the first after seven days of inactivity (Meta's metric definitions).

It gets softer further in. "Auto-detected purchases" are keyword matches, interest expressed, a payment link sent, an order "confirmed" in words (Meta's help on auto-detected purchases), not a UPI screenshot in your account. Whichever attribution window you read, one-day, seven-day or 28-day click (Meta's attribution-settings comparison), Ads Manager only counts what Meta can see; a booking closed over a phone call and a bank transfer never reaches it unless you send it.

Step 1: give every ad its own code

Start every ad's name with a short code (BALI1, KASH2), and end that ad's pre-filled WhatsApp message with the same code. Ads on the Traffic, Engagement, Leads or Sales objectives can carry a pre-filled message, set at the ad level under Customer actions > Pre-filled message (Meta's help on pre-filled messages); the customer can edit, delete, or send it as is. If the ad side isn't set up yet, the working click-to-WhatsApp setup covers the greeting scripts and the free reply window.

Because the code can be edited away, your first reply covers the gap: "Which offer did you see, [A] or [B]?" Log the answer as the source.

For lead forms, use a tracking parameter instead: the Settings of a new or duplicated form accept hidden name/value pairs such as src=DXB-LF, invisible to the applicant but present in the download and any connected system (Meta's help on tracking parameters). The default export already carries campaign_name and ad_name (Meta's help on lead data columns), but your own code outlasts a renamed campaign; pair this with the settings that stop junk form leads. Download within 90 days of submission; after that the leads can no longer be downloaded (Meta's help on retrieving leads data).

Code Where it runs Ad name starts with Carries the code via
BALI1 CTWA carousel "BALI1 - Bali honeymoon" Pre-filled message
KASH2 CTWA video "KASH2 - Kashmir family" Pre-filled message
DXB-LF Lead form "DXB-LF - Dubai 4N" Tracking parameter src=DXB-LF
Pre-filled message: Hi, I saw your <offer name> offer. Please send details. [<CODE>]

First-reply fallback (only when the code is missing):
Thanks for writing in. Which offer did you see: <offer A>, <offer B> or something else?

Step 2: fill the source column at first reply

Add one column, "Source code," to whatever register you already run. Fill it the moment the row is created, from the code or the fallback answer, never reconstructed later. Allowed values: the live codes, plus ORGANIC, REFERRAL, UNKNOWN. Don't rebuild the sheet; one filled column is the ask.

Track the UNKNOWN share weekly. A rising share means staff are skipping the fallback question, and any booking from those rows is one no campaign will ever get credit for.

A booking is the advance received, nothing earlier. Record it as a date in an "Advance date" field on the same row, never a new one. A quote sent, or a "confirm kar do" with no money behind it, isn't a booking; leave the date blank until payment lands.

Two rules settle most disputes later. Same number enquiring twice: credit the first coded row, the ad earned first contact, not whichever chat was open when payment arrived. One family, two trips off one enquiry: duplicate the row for the second trip with the same code; the ad produced the family, both bookings count.

The weekly and monthly maths

Weekly: spend by code from Ads Manager, next to rows and quotes sent by code; cost per quote is your early signal. Monthly: work in cohorts, bookings credited to the enquiry's arrival month, re-read once that cohort has aged past your own enquiry-to-advance lag.

With enquiry columns Date in (B), Source code (C), Stage (D), Advance date (E), and a maths tab with Code (A), Spend (B):

Bookings for a month, by code (maths tab, C2):
=COUNTIFS(Enquiries!$C:$C, $A2, Enquiries!$D:$D, "Advance paid",
          Enquiries!$B:$B, ">="&DATE(2026,9,1), Enquiries!$B:$B, "<"&DATE(2026,10,1))

Cost per booking (D2):
=IF(C2=0, "no booking yet", B2/C2)

Before comparing with margin: Meta's India help says GST and TDS are added whenever you're charged for ads (Meta's help on GST in India), so "amount spent" in Ads Manager is not the whole bill. If your CA says you can't claim that GST back as input credit, count the GST-inclusive figure as the real cost. The same page says the TDS is refunded as ad credit once you give Meta the TDS certificate; confirm the mechanics with your CA, not this post.

The cheap campaign that lost

The campaign that looks cheapest on Meta's dashboard can be the most expensive once you count bookings. One illustrative month, plausible but made-up numbers, not a benchmark for your agency:

Campaign Spend (pre-GST) Bookings Cost per booking
BALI1 (CTWA, Bali) ₹30,000 3 ₹10,000
KASH2 (CTWA, Kashmir) ₹21,000 5 ₹4,200
DXB-LF (lead form, Dubai) ₹15,000 2 ₹7,500
UNKNOWN (code lost) not allocated 1 not allocated

On the dashboard, BALI1 looked like the find of the month at ₹75 a conversation (₹30,000 over 400) against KASH2's ₹150 (₹21,000 over 140). Counted by bookings, BALI1 is the most expensive at ₹10,000, and KASH2, the "expensive" one, is the cheapest.

Pick a ceiling before you look at the table, an illustrative one is 30% of gross margin per booking. Against a ₹14,000 margin, KASH2's ₹4,200 sits right at that line. Against ₹16,000 the ceiling is ₹4,800, and BALI1's ₹10,000 is more than double it. DXB-LF's ₹7,500 eats 83% of a ₹9,000 margin.

Kill rules that don't kill too early

Read weekly, never daily, and give a campaign at least seven days before judging it; Meta's own guidance on optimising click-to-message campaigns for purchases is to run at least that long and judge on cost per on-Meta purchase, not conversations started (Meta's help on optimising for purchases). Editing an ad, ad set or campaign during the learning phase resets it, and an ad set usually leaves learning only after about 50 results in the week after its last significant edit (Meta's help on the learning phase); a small daily budget may take a while to clear that bar, and daily tinkering keeps restarting the count.

Treat three bookings against five as noise, not a verdict. For what a campaign should cost before bookings even enter the picture, see the India benchmarks. Compare two monthly cohorts, and only rework or pause a campaign that misses its ceiling on both.

Sending bookings back to Meta: worth it, with limits

Only once the sheet works on its own, and even then it's no guarantee of a lower cost per booking: at best Meta looks for more real buyers instead of more chatters. Three honest routes, each with limits.

The free WhatsApp Business app can share signals with no API: turn on Tools > Your customers' activity > "Allow Meta to receive information about events" (if your account shows the setting), then use its predefined labels: a chat from a click-to-WhatsApp ad labelled New order, Pending payment, Paid or Order complete counts as a purchase event (Meta's help on optimising click-to-message campaigns). Catches: the label must go on within seven days of the ad click, a custom label may not count, and a purchase label on a chat that has only been quoted still counts as a purchase, so keep them for paid advances. The app's separate "orders" feature is not available in India, as of October 2026.

The Conversions API for Business Messaging is the complete version, but it needs the WhatsApp Business Platform's Cloud API, usually through an integration partner (Meta for Developers on the Conversions API), plus a ctwa_clid, a click ID Meta attaches to messages from a click-to-WhatsApp ad (Meta's webhook reference), missing on Status-placement clicks. Events must reach Meta within seven days of the booking they describe or the batch is rejected (Meta on event timing), so a once-a-month upload won't work.

For lead forms, Meta's own Google Sheets or Excel connection needs no integration partner: new leads land in the sheet with a lead_status column and a lead ID, and each time you update the status Meta creates a Conversions API event from it (Meta's help on retrieving leads data). On the WhatsApp side, the purchase goal opens only after you have shared at least ten purchase events, from app labels or the Conversions API, within a prior 30-day period.

One more thing before data leaves your sheet: the Digital Personal Data Protection Rules, 2025 were notified 14 November 2025, with an eighteen-month phased roll-in (PIB's backgrounder). Say plainly, in whatever consent line you already give enquirers, that their data may be used to measure which ads work.

Your 30-day test plan

  1. Week 0: code every live ad, add the pre-filled message or tracking parameter, then leave settings alone, you want to read results, not reset learning.
  2. Weeks 1-4: run without edits. Fill Source code, Stage (Chat, Quoted, Advance paid, Lost, a cut-down version of the stages in where enquiries actually die) and Advance date the same day, not in a Friday batch.
  3. Day 30: cost per quote by code, not accurate for bookings yet, but a health check on volume and tagging.
  4. Day 45-60: once the cohort has aged past your usual lag, cost per booking by code, and decide: keep, rework or kill.

Common questions

Kaun se ad se booking aayi, kaise pata kare?

Meta's dashboard won't tell you, it only shows chats and leads, not who paid. Code every ad's pre-filled message or lead-form parameter, add a Source code column, and link the advance date back to that row. The answer lives in your sheet, not Ads Manager.

Can Meta tell me which ad brought the booking?

Not on its own; it has no record of money collected by UPI or cash. The free WhatsApp Business app can send a purchase signal through chat labels, but only for chats labelled within seven days of the ad click, and many travel advances land later than that.

Should I optimise my ads for purchases instead of chats?

Only once your sheet is solid. The purchase signal needs real labelling discipline, and the WhatsApp purchase goal opens only after at least ten shared purchase events in a prior 30 days. Until then, judge weekly by cost per booking from the sheet.

The short version

  • Judge every campaign on spend divided by paid bookings (advance received), not cost per chat or lead.
  • Meta's conversation count includes returning clients and one-line chats, and its auto-detected "purchases" are keyword matches; none of these are bookings.
  • Give every ad a short code in its pre-filled message or lead-form parameter, and ask for it in your first reply when it's missing.
  • Add one Source code column to your sheet, filled the day the enquiry lands, not rebuilt at month-end.
  • Read cost per booking by code monthly, once the cohort has aged, against a ceiling set as a share of margin.
  • Sending bookings back to Meta is worth it only once the sheet works, and each route (app labels, Conversions API) has real limits.
  • Recheck the app's label setting every few months, and take GST on ad spend and your DPDP consent line to your CA rather than settling them once.

See Tourify with your next trip.

Leave your number. We'll walk through your departure costs, quotes and bookings with you.

Indian mobile? Just enter 10 digits. For other countries, include the country code.

We use your details to follow up on this request. Privacy policy