How to clean a phone list before importing it to Klaviyo
Klaviyo's phone-number import is strict in one way and permissive in another, and the combination catches people out. It is strict about format — anything not in E.164 is rejected outright. It is permissive about whether the number can actually receive a text, a landline imports perfectly happily, then silently consumes SMS credits forever.
The same is broadly true of Attentive, Postscript, Braze and most ESPs with an SMS channel. The specifics below are Klaviyo's, but the shape of the problem is universal.
What Klaviyo requires
Phone numbers must be in E.164: a plus sign, then digits, no spaces or punctuation. Rows that fail are skipped, and the import summary tells you how many were skipped without telling you which ones or why. On a large file that is a genuinely painful debugging experience, which is the main argument for cleaning before you upload rather than after.
What happens to a number after it imports
The import is the visible step, so it gets the attention. What the number does afterwards is where the cost accumulates.
A phone number in Klaviyo attaches to a profile, and a profile is the unit that carries consent, subscription status and message history. Three consequences follow, and none of them are reversible by re-importing a better file later:
- A bad number becomes a durable record, not a rejected row. Once a well-formed but unreachable number creates a profile, it sits in your account, appears in segments, and receives every send that segment gets.
- Duplicates become separate people. Two formats of the same number create two profiles with two consent records, and merging them afterwards is manual work that grows with the size of the mistake.
- Deliverability metrics are computed over what you actually sent. Undeliverable profiles pull down the rates you use to judge whether a campaign worked, so bad data does not only cost money, it corrupts the measurement you would use to notice.
This is the argument for cleaning before rather than after. Cleaning before is a file operation. Cleaning after is a data-migration exercise inside a system that is actively sending.
Prepare the file in this order
1. Fix the format
Strip punctuation, convert leading 00 to +, resolve
each row's country, and drop the trunk prefix where that country uses one. The
UK +44 (0) 20… pattern deserves specific attention — naive
punctuation stripping turns it into a number with an extra zero that is the right
length for nothing.
2. Deduplicate after normalising, not before
Klaviyo will happily create separate profiles for
(415) 555-2671 and +14155552671 if your source treats
them as different strings, and then message the same person twice. Normalise
first so they collapse.
3. Drop unallocated numbers before upload
These import cleanly. They are well-formed, so nothing rejects them, and then sit in your account as permanently unreachable profiles, dragging your deliverability metrics down and, on plans billed by active profile, costing you money for contacts that cannot be contacted.
4. Remove landlines
This is the one with an ongoing cost. Landline profiles receive every SMS you send to that segment, forever, and every one is billed. A few thousand landlines in a list you message weekly is a recurring charge for messages that were discarded on arrival.
5. Check your consent data separately
Klaviyo requires that SMS subscribers have consented, and this is a legal requirement, not just a platform rule. Cleaning a list makes it deliverable. it does not make it compliant. Consent has to come from your own records, and if you cannot show where a number consented, it should not be in the SMS segment regardless of how clean it is.
Reading the import summary
Klaviyo tells you how many rows were skipped. It is much less forthcoming about which rows, and why. On a file of any size that is the difference between a five-minute fix and an afternoon.
The reliable way round it is to make the file unable to fail rather than to debug the failure afterwards. Before uploading, verify locally that:
- every row in the phone column starts with a plus and contains only digits after it;
- no value exceeds fifteen digits including the country code;
- the count of distinct values equals the count of rows, so you know deduplication actually happened;
- the file opens as UTF-8 without a byte-order mark, and contains no non-breaking or zero-width characters.
If those four hold, a skipped row is a Klaviyo-side rule rather than a formatting problem, and you have narrowed the search enormously.
Worth knowing that a row can also be accepted and then be wrong. An import that reports zero skipped rows is not evidence that the numbers are real. It is evidence that they were syntactically acceptable, which is a much weaker claim.
The CSV itself
- One column of numbers, already in E.164, one per row.
- Quote the phone column or format it as text — Excel will strip the leading plus and may convert long numbers to scientific notation. This destroys the file, and it is the most common reason a correctly prepared list fails at import.
- UTF-8 encoding. Non-breaking spaces from copy-paste look identical to normal spaces and fail the format check.
- Include your consent columns (timestamp, source, method) if you have them — importing them alongside is much less painful than backfilling later.
The Excel trap, concretely. Open a clean E.164 CSV in Excel
and save it, and +14155552671 can come back as
14155552671 or 1.41556E+10. If you must touch the file
in a spreadsheet, set the column type to Text before opening, or use Google
Sheets with a leading apostrophe, or do not open it at all.
The same problem in other platforms
The specifics above are Klaviyo's. The shape is common to every platform with an SMS channel, and the differences that matter are in how strict the import is and how the billing works.
| Behaviour | Why it changes what you do |
|---|---|
| Strict E.164 on import | Failures are loud and happen up front, which is the easier case to handle |
| Permissive import with normalisation at send time | Failures are quiet and happen later, per message, which is harder to attribute |
| Billed per active profile | An unreachable number is a recurring charge even if you never message it |
| Billed per message sent | An unreachable number costs only when that segment is sent to, but does so every time |
In every combination the preparation is the same, which is the practical reason to do the work in the file rather than in the platform. A cleaned E.164 file imports correctly into all of them. A file prepared for one platform's quirks does not travel.
A worked sequence on a real export
Concretely, on a 50,000-row export merged from a checkout system and two signup forms. The counts below are one list's, not a benchmark, and the reason to show them is the order rather than the proportions.
- 50,000 rows in. Three sources, three different formatting conventions, one of which stored numbers with the country name in a separate column and one of which did not store country at all.
- Normalise first. The rows with no country are the decision point. Where the number already carried a prefix it converts cleanly; where it did not, it is set aside rather than assumed into the majority country.
- Deduplicate second. Only now does the same number from checkout and from a form collapse into one row. Running this step first would have left both.
- Drop unallocated blocks third. These are the rows that pass every format check and cannot ring. They would have imported silently and become permanent profiles.
- Split landlines fourth, into a separate file for the voice team rather than into the bin.
- Import what is left, with the consent columns attached, and keep the removals as a suppression file for next month's export.
The step that most often gets skipped is the last clause of the last point. The same sources will produce the same dead numbers again in thirty days, and a suppression file is what stops you paying for them twice.
Consent is a separate file, and a separate problem
Worth restating, because technical cleanliness reads like compliance and is not.
Every number in an SMS segment needs consent you can evidence: when it was given, through what mechanism, and for what. That record lives in your own systems and has to survive a change of platform, which is why it belongs in the import file rather than being reconstructed later from whatever the platform happened to retain.
A perfectly formatted, deliverable, mobile number with no consent record behind it is a liability rather than an asset, and it is the one defect that cleaning cannot detect. Numbering-plan data can tell you that a number is real and that it is a mobile. It cannot tell you that someone agreed to hear from you.
Doing it once versus doing it monthly
For a one-off import of a few thousand rows, careful manual work in a spreadsheet gets you there.
For a list you re-export monthly, or one in the hundreds of thousands of rows, manual stops being viable, not because it is hard, but because it has to be repeated identically every time and it will not be. That is where a tool that does the whole sequence in one pass pays for itself: same rules, same output, every time, with the invalid rows accumulating into a suppression file so you are not re-cleaning the same junk each month.
Common questions
How do I format a phone number in international format?
Start with a plus sign, then the country code, then the national number with the trunk prefix removed and all spaces, brackets and dashes stripped. A UK mobile written 07700 900123 becomes +447700900123. The trunk zero is dropped, which is the step most often missed, and keeping it produces a number that is the right length for nothing.
How do I import contacts into Klaviyo?
Upload a CSV with one phone number per row, already in E.164, with the column formatted as text so the leading plus survives. Include your consent columns in the same file rather than backfilling them afterwards. Prepare the file completely before uploading, because the import summary reports how many rows were skipped without telling you which ones.
Why does Klaviyo reject my phone numbers?
Almost always formatting rather than the number itself. The common causes are a missing plus, a trunk prefix that was not removed, a value that a spreadsheet converted to scientific notation, and invisible characters such as non-breaking spaces picked up through copy and paste. All four produce a row that looks correct on screen.
Do landline numbers cost money in an SMS platform?
Yes, in both billing models. On a platform billed per message they consume a send every time the segment is messaged, and the message is discarded on arrival with nothing reported back. On a platform billed per active profile they are a standing charge for a contact that cannot be contacted. Neither shows up as an error.
Does cleaning a list make it compliant?
No. Cleaning makes a list deliverable. Compliance is about consent and about the registries you are required to check, and those use different data entirely. It is worth treating them as two separate passes with two separate records, because passing one says nothing about the other.
What are Klaviyo's weaknesses when it comes to phone data?
Scoped to phone numbers rather than the product generally: the import is strict about format but permissive about reachability, so a landline or an unallocated number imports as cleanly as a good mobile. The skipped-row summary reports a count without identifying the rows. And because a number becomes a profile, a bad import is a durable record rather than a rejected line. None of that is unusual among SMS platforms, and all of it is avoidable by preparing the file first.
Try it on a number right now
The free checker on the homepage runs the same engine the desktop app uses: validity, country, line type and carrier, one number at a time.
Check a number free