Doors closed ₨6.29M / ₨10M generated · ₨4.00M courier-verified Watch the proof →
FIELD NOTES

Essays from inside
a COD brand.

Short, honest notes about the numbers that actually run cash-on-delivery commerce — written by a team that watches them every day, not by a content department. No growth hacks. Just the truth we trip over.

NOTE 01 · AUG 2026 · 4 MIN

Delivered CAC: the number Meta will never show you.

Every performance marketer in our part of the world manages to a number that doesn't exist. Open your Ads Manager: it tells you what a customer costs. It is wrong — not because Meta is dishonest, but because Meta's truth ends at the checkout, and your truth happens at the door.

Here is the math nobody wants to do. You spend ₨3,000,000 in a month. The dashboard reports 3,000 orders, so your reported CAC is ₨1,000. Clean. Manageable. Then the courier sheet arrives: 750 of those parcels came back. Refused at the door, unreachable, fake address, "not ordered." Only 2,250 humans actually paid.

Your real CAC — the delivered one — is ₨1,333. A third higher than the number you managed to. Not once. Every single month.

You don't have a CAC. You have two — and you're managing to the wrong one.

Why the platform can't see it

Ad platforms measure what they can observe: the click, the add-to-cart, the order. In prepaid commerce, that's where the story ends. In cash-on-delivery, that's where the story starts. The parcel still has to survive 48 hours of courier roulette — the wrong city hub, the rider who calls once and gives up, the customer who was never a customer. None of that exists in any ad dashboard. It exists in courier sheets, which nobody opens until the accountant screams.

What the gap does to your decisions

A 33% error doesn't stay a 33% error — it compounds into every decision downstream. The creative you killed last month for a ₨1,400 CAC? At a 20% RTO its delivered CAC was ₨1,750 — fine, kill it. But the one you scaled at a "healthy" ₨900? Its audience RTO'd at 40%. Delivered CAC: ₨1,500. You scaled the loser and buried the winner, and both decisions felt data-driven.

The fix is boring

Reconcile ad spend against delivered parcels — not orders — every week, split by campaign, by courier, by city, by refusal reason. Do it in a spreadsheet if you have to; the discipline matters more than the tool. We did it manually for months before we built a machine that does it nightly and leaves the verdicts on our desk. Either way: manage to the number the courier would agree with. It's the only one that's ever paid anyone.

NOTE 02 · AUG 2026 · 4 MIN

The parcels the courier never collected.

Last week the founder was staring at the courier aging report and asked a question nobody had asked out loud: why are 76% of our Leopards parcels "late"? Not refused. Not returned. Just… old. Sitting in the 11+ day bucket, reading like a delivery problem.

It wasn't a delivery problem. When we split the bucket by whether the courier had ever scanned a pickup, the pile separated like oil and water: 533 of 701 Leopards parcels — and 164 of 205 PostEx parcels — were never collected at all. The courier accepted the booking, generated the tracking number, and never sent a rider.

The parcel wasn't late. The parcel was still on our shelf, wearing a tracking number.

Why it hid so well

Every aging report in this industry sorts by days-since-booking. That's the trap: a parcel booked 30 days ago and a parcel shipped 30 days ago look identical in that view. One is a delivery failure. The other is a pickup failure. They have opposite owners, opposite fixes, and opposite blame — and the report averaged them into one sad number called "late".

What changes when you see it

Everything about the action flips. For a late parcel you chase the customer and the destination hub. For a never-collected parcel you chase the pickup — re-book, call the station manager, or move the parcel to the courier who shows up. And the money math is brutal: a never-collected parcel still ages toward a doorstep refusal, because the customer's excitement has a shelf life even if the perfume doesn't.

The never-picked bucket is now a permanent detector, synced four times a day in each market — fresh parcels, aging parcels, and a 🚫 for the ones nobody came for, at any age. It took one founder, one question, and one afternoon. The pile was always there. Nobody had split it.

NOTE 03 · AUG 2026 · 5 MIN

We taught the AI how our data lies.

Everyone connecting an AI to their database makes the same move: they hand it the schema — table names, column names, types — and call it context. We did that too. Then we watched it answer beautifully, confidently, and wrong. Not because the model was weak, but because our data has habits no column name will ever confess.

So we wrote them down. The AI now gets the database with its traps attached — the ways this specific data has already fooled someone:

· oms_orders.created_at is not the order date. It's the moment the mirror row was inserted — and on about 20% of rows that's more than 24 hours after the customer checked out. Query "today's orders" on it and you're querying our sync latency, not your sales.

· The customer object has no displayName. One early query grouped by it anyway and filed 211 of 232 units under "unknown". The query ran fine. The answer was fiction.

· A one-day-old cohort shows 0% returns. A fifteen-day-old cohort shows 14–18%. Both numbers are "accurate". Only one is true.

The 98.2% incident

This is the one that changed the product. A four-day window held ~900 parcels and reported 98.2% delivery, 1.8% returns. The row count looked enormous. The assistant said — we're embarrassed to quote it — "your delivery ops turned a corner" and recommended scaling spend.

Only ~60% of that cohort had resolved. The un-resolved 40% were still riding around the country in courier bags. When parcels like that settle, they settle at roughly 15% returns — eight times worse than the number we almost acted on.

A missing measurement always flatters. The data that hasn't arrived yet is never bad news.

What we built instead

Now every answer ships with its working: the definition used, the sample size, a confidence — and a cohort-maturity check computed from the payload itself, which overrides the confidence. When the cohort is young, the warning goes into the summary — the part that gets read aloud — not a footnote: "⚠ NOT A REAL RESULT — only X% of this cohort has resolved."

It's the same thesis this whole company runs on, applied to ourselves: the flattering number is the dangerous one. We didn't just give the AI our data. We gave it the list of ways our data lies.

Get the next note.

One email when a note ships. Nothing else, ever.

[email protected]