All articles
Guide

WhatsApp Contact Import: Why CSV Rows Vanish India 2026

Uploaded 10,000 numbers and the campaign shows 8,700? Nothing errored — rows that will not normalise are skipped silently. What decides which survive.

RichAutomate Editorial
11 min read 0 views
WhatsApp Contact Import: Why CSV Rows Vanish India 2026

Direct answer — the row count is not the contact count

If you uploaded a CSV of 10,000 numbers and the campaign screen says 8,700 recipients, nothing errored. Rows that cannot be turned into a usable number are skipped silently — no warning, no rejected-rows file, no line number — and the importer's own progress counter counts only the survivors, so the number it reports back to you already excludes everything it threw away.

That is the whole problem in one sentence: an importer's success count is not a reconciliation. It tells you how many rows made it, never how many did not. If you want the difference, you have to compute it yourself, before the campaign goes out rather than after finance asks why the send volume missed forecast.

This page walks the path a single CSV row takes on its way to becoming a messageable contact, and names the five places it can quietly disappear.

The header row decides everything

Contact importers are almost always header-driven. The first row of the file is read once, each column name is lowercased and trimmed, and the importer looks for the specific names it knows. Everything else in that header row is ignored — not rejected, ignored. A column the importer does not recognise contributes nothing and raises nothing.

In practice the recognised set is small. A phone column, and a set of positionally-numbered variable columns for template placeholders. That is frequently the entire contract. Columns called email, city, order_id, gst or last_purchase sail past untouched unless the platform explicitly documents them as custom attributes.

The failure this produces is not dramatic, which is exactly why it survives to production: your file looks rich, the upload succeeds, and the send goes out with none of the personalisation you thought you had attached.

The header names that actually matter

What you write in the headerWhat a header-driven importer does
phoneRecognised. This column becomes the recipient.
Phone, PHONE,  phone Recognised — matching is done on the lowercased, trimmed name.
mobile, whatsapp, Phone Number, contact_noNot recognised. These are the four most common Indian CRM exports, and none of them match.
var_1, var_2, var_3Recognised as template variables, bound to placeholder position 1, 2, 3.
name, city, amountIgnored for templating. Put the value in var_1 if the template's first placeholder is the customer's name.

The practical rule: rename your columns to match the importer, do not expect the importer to guess. Renaming a header in a spreadsheet takes ten seconds. Diagnosing a campaign that sent 8,700 messages with blank placeholders takes an afternoon.

When there is no phone column

Here is the behaviour that surprises people most. When a header-driven importer cannot find its phone column, the sane thing to do would be to stop and tell you. What many actually do instead is fall back to the first column of the file and treat it as the number.

The fallback is well-intentioned — plenty of real uploads are a bare list of numbers with a throwaway header — and when the first column genuinely is the phone number, it rescues the import. When it is not, the outcome is silent and total:

  • First column is name → every row normalises to nothing → every row is skipped → the campaign has zero recipients and no error explaining why.
  • First column is customer_id → numeric, so it looks superficially plausible → some IDs may pass a length check and be sent as phone numbers to whoever owns those digits. This is the dangerous variant.
  • First column is email → zero recipients, same silent nothing as the name case.

Two defences, both cheap. Always include a literal phone header. And always verify the recipient count before scheduling — a zero or a wildly wrong count is the fallback telling you it guessed wrong, in the only language it has.

The silent skip: rows that leave no trace

Every row's number goes through a normaliser on its way in — the step that turns whatever the spreadsheet holds into the E.164 form the WhatsApp Business API expects. If normalisation returns nothing usable, the row is dropped and the loop moves on. No exception, no log line, no rejected-rows report.

What actually triggers it, in the order we see it in real Indian contact files:

  1. Blank cells. Exported CRMs leave gaps. A blank phone is a skipped row.
  2. Excel's number formatting. A column stored as a number turns 09876543210 into 9876543210 by eating the leading zero, and long numbers into 9.87654E+11 in scientific notation. The second one never recovers.
  3. Landlines and toll-free numbers. 02226541234 and 1800… rows are in almost every legacy database and none of them are WhatsApp identities.
  4. Two numbers in one cell. 9876543210 / 9123456789 is extremely common in Indian records. It is one cell, so it is one row, and it normalises to nothing.
  5. Stray characters. Non-breaking spaces from a web copy-paste, trailing tabs, a smart-quote apostrophe some tools prepend to force text formatting.

Only the first two are obvious in a spreadsheet. The rest look completely fine to a human reading the file.

The number itself can also be perfectly well-formed and still not reach anybody — normalising cleanly is a different question from resolving to a real WhatsApp account. That distinction is its own subject; we cover the four possible outcomes in why the WhatsApp API rejects a phone number as invalid.

Deduplication happens after normalisation, not before

Importers typically create contacts with a find-or-create against a key of tenant plus normalised phone number. This ordering matters more than it sounds, and it is good news:

Rows in your fileContacts createdWhy
09876543210
+91 98765 43210
919876543210
1All three normalise to the same E.164 value, so the key collides and the row matches the contact that already exists.
9876543210
9876543211
2Different numbers, different keys.
9.87654E+11
9876543210
1 (+1 skipped)The scientific-notation row fails normalisation and is dropped before it can dedupe against anything.

So a file with the same customer written three ways does not produce three contacts and does not send three messages. Dedupe by normalised number is doing real work for you.

The catch is that it also makes your reconciliation arithmetic non-obvious. File rows ≠ contacts created ≠ messages sent. Rows collapse through dedupe, rows vanish through skips, and both happen before a single message is queued. If you are budgeting a send, budget on the recipient count the platform shows you after the import, never on the row count of the file you uploaded.

Stop overpaying on WhatsApp

Get a 1-minute BSP audit on WhatsApp

Drop your WhatsApp number — we line-item your current invoice against Meta India rates in under 60 seconds. India-hosted, DPDP-compliant.

DPDP-compliant · India-hosted · 1-min reply

The name column trap

Find-or-create has a second consequence that catches people on their second import rather than their first: the attributes you supply are applied only when the contact is created. On a match, they are not applied at all.

Concretely: import a list, get contacts named Unknown because your file had no usable name column. Fix the file, add proper names, re-import the same numbers. The contacts already exist, so the key matches, so nothing updates. They are still called Unknown.

This is correct behaviour — an importer that overwrote existing contact data on every upload would be far more destructive — but it means the first import of a number sets its record, and a re-import will not repair it. Get the name column right before the first upload, or plan to fix names through the contact editor or an update endpoint rather than by re-uploading.

opt_in is not a column you should let an importer invent

Many importers set an opt-in flag to true on every contact they create, because the implicit assumption is that you would not be uploading a list you had no permission to message. That assumption is doing an enormous amount of unearned work.

Under the DPDP Act 2023, consent has to be demonstrable — you need to be able to say when it was given, through which channel, and for what purpose. A flag flipped to true by a CSV parser records none of those things. It records only that a row existed in a file.

Treat the flag as a convenience default, never as evidence. The consent record that matters lives outside the import:

  • Source — the specific form, checkout, kiosk, WhatsApp opt-in message or paper consent the permission came from.
  • Timestamp — when. Consent from 2019 for a purpose you have since changed is not consent for today's campaign.
  • Purpose — transactional-only permission does not authorise a promotional broadcast.

Carry those three as their own columns in the file even when the importer ignores them, and keep the file. When a grievance arrives, the file is your audit trail. Lists also decay — numbers get recycled, people churn — which is a separate discipline covered in WhatsApp opt-in list hygiene and re-permissioning.

And a list you bought or scraped does not become permissioned because a column says true. What is and is not lawful at volume is set out in how to send bulk WhatsApp messages legally in India.

Template variables ride on the same row

Positional variable columns — var_1, var_2 and so on — are read from the same row as the phone number and bound to the template's placeholders in order. Three things follow:

  • Position is the contract, not the column name. var_1 fills {{1}}. If your template's first placeholder is the customer's name, the name goes in var_1, whatever else you call it elsewhere.
  • A missing variable column does not skip the row. The row still sends. It sends with a hole where the personalisation should have been, which is worse than not sending, because it is visible to the customer.
  • Variable count must match the approved template. A template approved with three placeholders needs three values every time. Supplying two is a send-time rejection, not an import-time one — the file uploads happily and the failure surfaces later, per-message.

Because that class of failure happens after the import and after the schedule, it is easy to misattribute to the import. It is not; it is a payload problem, and we unpack it in WhatsApp template parameter mismatch errors.

Reconciling the file: a five-number check

Run this every time, before you schedule. It takes two minutes and it is the only thing that catches a silent skip.

  1. Rows in the file. Count them in the spreadsheet, minus the header. Write the number down.
  2. Unique normalised numbers. Your own estimate of how many distinct people are in the file. The gap between this and (1) is your expected dedupe.
  3. Recipients the platform reports after the import completes.
  4. (1) − (3) = total shrinkage. Now the important part: is that number close to your expected dedupe from (2)? If it is much larger, the excess is skipped rows.
  5. Spot-check five known numbers from different parts of the file — including one you know is formatted awkwardly — and confirm each is present in the contact list.

If step 4 shows unexplained shrinkage, do not schedule. Open the file, sort by the phone column, and look at the top and bottom — blanks sort together, and scientific notation is instantly visible once the column is sorted.

Preparing the file: checklist

  1. Header row present, and the phone column is literally named phone.
  2. Phone column formatted as text in the spreadsheet before you type or paste anything into it.
  3. No scientific notation anywhere in the column — sort it and check both ends.
  4. One number per cell. Split a / b cells into separate rows.
  5. Landlines, toll-free and internal extension numbers removed.
  6. Country code strategy decided and consistent — pick one form and let the normaliser do the rest.
  7. Variable columns named var_1var_N, in the order the approved template expects.
  8. Every variable column populated for every row, or the row removed.
  9. Consent source, timestamp and purpose carried as columns even if the importer ignores them.
  10. Names correct on the first upload — a re-import will not fix them.
  11. File saved as UTF-8 CSV, under the platform's size limit (commonly 10 MB; split larger lists).
  12. Recipient count reconciled against row count before scheduling.

Further reading

Imports that tell you what they dropped

An import is a data-integrity operation wearing a file-upload costume. The count you get back should be reconcilable against the file you handed over, and when rows do not make it, you should be told which ones and why — before the campaign, not after.

If you are moving a legacy contact database onto the WhatsApp Business API and want the shrinkage explained rather than absorbed, talk to us.

Rows lost at import shrink the campaign before it ever sends; rows lost after it starts are a different problem — see reading campaign state.

Ready to ship this?

Get the full migration playbook on WhatsApp

A founder-led 1-minute reply with the migration steps, template approval timeline, and a 14-day pilot offer. DPDP-compliant. India-hosted. No spam.

DPDP-compliant · India-hosted · 1-min reply
Tagged
WhatsApp Business APIContact DataCampaignsDPDPIndia
Written by
RichAutomate Editorial
Editorial team at RichAutomate. We build the WhatsApp Business automation platform Indian D2C brands, fintechs, and agencies use to ship campaigns and flows on the official Meta Cloud API.
FAQ

Frequently asked questions

Why did my WhatsApp contact import create fewer contacts than rows in my CSV?
Two things shrink the count. Rows whose number cannot be normalised to E.164 are skipped silently — blanks, landlines, scientific notation from Excel, two numbers in one cell. And rows for the same person written different ways collapse into one contact, because deduplication runs on the normalised number rather than the raw text. Subtract your expected dedupe from the total shrinkage; whatever is left is skipped rows.
What should the phone column in a WhatsApp import CSV be called?
Literally 'phone'. Header matching is done on the lowercased, trimmed column name, so 'Phone' and 'PHONE' work too, but 'mobile', 'whatsapp', 'contact_no' and 'Phone Number' do not — and those are the four most common Indian CRM export headers. If no phone column is found, many importers fall back to the first column of the file, which silently produces zero recipients when that column is a name or an email.
Does Excel break phone numbers in a WhatsApp import file?
Yes, in two ways. A column formatted as a number strips the leading zero from 09876543210, and long numbers get rewritten into scientific notation such as 9.87654E+11, which cannot be recovered. Format the phone column as text before typing or pasting into it, then sort the column and check both ends of the file before uploading.
Will re-importing a CSV fix contact names that came in as Unknown?
No. Importers use a find-or-create against tenant plus normalised phone number, and the attributes you supply are applied only when the contact is created. On a match, nothing is updated — so the existing record keeps the name it was first given. Get the name column right on the first upload, or correct names through the contact editor or an update endpoint instead of re-uploading.
Does a CSV import prove opt-in consent under the DPDP Act?
No. An importer that sets an opt-in flag to true on every contact it creates records only that a row existed in a file. The DPDP Act 2023 requires demonstrable consent — when it was given, through which channel, and for what purpose. Carry consent source, timestamp and purpose as columns in the file and keep the file as your audit trail, even if the importer ignores those columns.
How do template variables work in a WhatsApp campaign CSV?
Columns named var_1, var_2 and so on are read from the same row as the phone number and bound to the template's placeholders by position, so var_1 fills {{1}}. Position is the contract, not the column name. A missing variable column does not skip the row — it sends with a visible hole in the personalisation — and supplying fewer values than the approved template expects fails at send time, per message, rather than at import time.
RichAutomate · WhatsApp BSP for India 2026

Ship WhatsApp campaigns + flows on a transparent, compliance-ready BSP.

₹0 platform fee. DPDP audit log included. Visual flow builder. Multi-tenant from day one.

Start free trial
Want this for your brand?

Get a free 24-hour BSP audit

Send us your last invoice. We line-item it against Meta's published rates and benchmark against three alternatives.

Limited Spots Available

Get a Free
Automation Audit

Stop leaving revenue on the table. Get a custom roadmap to automate your growth.

Secure & Confidential

Continue reading

All articles
Guide

WhatsApp API Invalid Phone Number: Fix It India 2026

The digits looked fine but the send failed? Validation proves a number is plausible — only a send proves anyone is there. Four recipient states, decoded.

Read article
Deliverability

WhatsApp Campaign Stuck at QUEUED or PROCESSING 2026

Campaign says COMPLETED but only 60% went out? COMPLETED means no rows left queued — not that everyone received it. How to read each campaign state.

Read article
Guide

WhatsApp for Amusement & Water Park Ticketing India 2026

The capacity-ticket-and-weather-rain-check playbook for amusement and water parks - a capacity-confirmed e-ticket with a QR code the moment payment clears (the money message), a pre-visit info push, an instant weather rain-check reschedule thread, in-park fast-pass upsells, and a season-pass renewal campaign.

Read article
Guide

WhatsApp for Digital Marketing Agencies India 2026 Guide

How Indian marketing agencies run their lead-to-retainer funnel and white-label WhatsApp for clients in 2026 — automation stack, DPDP rules and costs from ₹0.10/msg.

Read article
Guide

WhatsApp Marketing India 2026: The Complete Guide

The complete 2026 pillar guide to WhatsApp marketing in India: what it is and why India, compliant opt-in bulk sending via the official API (not illegal blasting), Meta template categories, the campaign types that convert, real per-message cost math, a step-by-step playbook, ROI measurement, six industry examples and the mistakes that get numbers banned. Real RichAutomate numbers: Rupee 0 platform fee, Client Pay 0.10/msg + Meta direct, SaaS Pay 1.20 marketing / 0.30 utility-auth, 14-day trial + 100 free credits.

Read article
Guide

WhatsApp Business API Cost India 2026: 10 Questions Answered

The 10 questions Indian buyers ask before going live on WhatsApp Business API: cost, is it free, green tick, setup time, DPDP and the cheapest option.

Read article