# How to fix a low Meta Custom Audience match rate on a phone list

> Why phone lists match poorly in Meta Custom Audiences: missing country codes, dead and recycled numbers, landlines. The format Meta expects and a cleanup order.

Canonical: https://mobilevalidate.com/blog/meta-custom-audience-phone-list-match-rate · Last updated: 2026-11-03

![A customer spreadsheet with two flagged rows flows down through three narrowing filter cards labelled E.164, LINE and HLR; rejected rows drop out to the side, and a locked, hashed list feeds a match-score gauge under a consent shield.](https://mobilevalidate.com/images/blog/meta-custom-audience-phone-list-match-rate.svg)

*Fix the format, drop dead numbers and landlines, then judge the match score, on consented lists only.*


By MobileValidate team (https://mobilevalidate.com/about) · Published: 2026-11-03 · Category: Guides · Tags: Facebook, Instagram, Custom audiences, E.164, List hygiene, Consent, Bulk jobs

A low Meta Custom Audience match rate on a phone list usually comes down to data quality, not to Meta. Numbers without a country code, disconnected and reassigned numbers, landlines and numbers that were never added to a Facebook or Instagram account can't match, however the file is uploaded. Fix the format first, remove dead numbers next, and only then judge the match rate.

This guide sets out what Meta's own documentation says about formatting and hashing, why valid-looking numbers still fail, and the cleanup order we recommend for a consented customer list. Meta's documentation was checked on 3 November 2026.

## What is a good Custom Audience match rate for phone lists?

There is no official benchmark. As of November 2026, Meta's help pages give no target or guaranteed match rate. They say only that "the more information you can provide, the better the match rate" ([Meta Business Help Center](https://www.facebook.com/business/help/341425252616329)), and recommend adding more main identifiers "to increase the chances of getting a better match rate" ([Meta, formatting guidelines](https://www.facebook.com/business/help/2082575038703844)).

What Meta does show is a **match score** for each customer-list audience. Its help page says the score is "out of ten", appears "in increments of 0.5" and "is calculated by dividing matched rows by uploaded rows" ([Meta](https://www.facebook.com/business/help/2082575038703844)). So a score of 6 means roughly 60% of the rows you uploaded matched a profile.

Figures you will find elsewhere are third-party estimates. One ad-tools company publishes these "typical" ranges without naming a source or sample ([LeadEnforce, undated](https://leadenforce.com/blog/how-to-improve-facebook-custom-audience-match-rate)):

| Segment (third-party estimate) | Typical match rate quoted |
|---|---|
| Recent buyers | 60–80% |
| Customers from the last 12 months | 45–60% |
| Older CRM records | 20–40% |

Treat these as a rough picture, not a target. The pattern is the useful part: the older a record, the less likely its phone number still belongs to the person you collected it from. The best benchmark is your own: the same kind of list, uploaded the same way, over time.

## Which phone format does Meta's customer-list upload expect?

Every number needs its country code. Meta's formatting guidelines say: "Phone numbers must include a country code to be used for matching, even if they're all from the same country. For example, a one must precede a phone number in the United States." The same page says Meta accepts "phone numbers in up to 3 separate columns, with or without punctuation" ([Meta](https://www.facebook.com/business/help/2082575038703844)).

Meta's other list requirements, from the same page:

| Requirement | What Meta says (3 November 2026) |
|---|---|
| File type | CSV or TXT |
| List size | "at least 1,000 customers" |
| Identifiers | At least one main identifier (e-mail, phone, mobile advertiser ID); more improve the chance of a match |
| Country column | An "ISO two-letter country code, even if they're all from the same country" |
| Freshness | An audience is marked **Outdated** when its list "hasn't been updated in over 30 days" |

If you send data through the Marketing API instead of uploading a file, you normalize and hash it yourself. For the `PHONE` key, Meta's developer documentation says: "Remove symbols, letters, and any leading zeroes. You should prefix the country code if the `COUNTRY` field is not specified." Hashing must be SHA-256, sent as lowercase hex ([Meta for Developers](https://developers.facebook.com/docs/marketing-api/audiences/guides/custom-audiences)).

In practice the safest form for both routes is the [E.164](/blog/e164-phone-number-format-guide-for-developers) number without the plus sign:

| What's in your CRM | E.164 | What you hash (API) |
|---|---|---|
| `0491 570 156` (Australian customer) | `+61491570156` | `61491570156` |
| `(020) 7946 0018` (UK customer) | `+442079460018` | `442079460018` |
| `+61491570156` | `+61491570156` | `61491570156`, not `+61491570156` |

Two details trip up a lot of teams. First, the hash of `+61491570156` and the hash of `61491570156` are completely different values, so a stray plus sign is enough to lose a match. Second, "leading zeroes" means the trunk `0` of a national number or an international prefix in front of the country code, not every zero. Some countries, Italy for example, keep a `0` after the country code for fixed lines. Convert numbers with a phone-number library and the customer's country, rather than with a find-and-replace.

## Why do valid-looking numbers fail to match?

A row matches only when Meta holds an account with the same number. Each of these causes stops that, and only the first one is about formatting:

| Cause | Why it doesn't match | Can you fix it? | How to find it |
|---|---|---|---|
| Missing or wrong country code | `0491 570 156` without `61` is a different number for a global matcher | Yes: add the country code from the customer's country | Normalization with a default country |
| Typos and impossible numbers | Too short, too long or not in the numbering plan | Sometimes: ask the customer again | Format validation |
| Disconnected numbers | Nobody uses the number any more; an old account may have dropped it | No: remove or re-confirm | [HLR](/services/hlr-lookup) status `unreachable` or `invalid` |
| Reassigned (recycled) numbers | The number now belongs to someone else, so it may match the *wrong* person | No: re-confirm with the customer | List age, HLR changes over time ([list decay](/blog/number-recycling-and-list-decay)) |
| Landlines and some VoIP numbers | Most people attach a mobile number to their accounts | Collect a mobile number or e-mail instead | [Line type](/services/carrier-lookup) `fixed_line`, `voip` |
| No account with that number | On Facebook and Instagram the phone number is optional; many people sign up with e-mail | No: add an e-mail column | Facebook and Instagram presence checks |

The reassigned row is the one to worry about. A low match rate is just a cost, but a recycled number that matches can show your ad to a stranger who never was your customer. That's a consent problem, not a performance one. Our post on [number recycling and list decay](/blog/number-recycling-and-list-decay) covers how fast lists age.

One honest caveat about the match score: removing rows that can't match raises the score, because the score is matched rows divided by uploaded rows. It doesn't add one person to the audience. The rows that can actually start matching are the ones with fixable formatting errors.

## How do you clean a phone list before uploading it?

Work from cheap to expensive, and only on customers who gave you their number:

1. **Normalize.** Convert every number to E.164 with the customer's country, and drop or set aside rows that can't be parsed. Remove duplicates *after* normalizing, because `0491 570 156` and `+61 491 570 156` are the same number.
2. **Check line type.** A carrier and line type lookup separates mobile, fixed-line and VoIP numbers. Landlines rarely match an account, so for those customers an e-mail column is the better identifier.
3. **Check live status (HLR).** An [HLR lookup](/blog/hlr-lookup-results-explained) asks the home network whether a mobile number is in service. `unreachable` can be temporary; `invalid` (not assigned) is not. Suppress dead numbers and re-confirm the customer's contact details.
4. **Optionally, estimate Facebook and Instagram presence.** Before you pay for a test campaign, a presence check tells you roughly how many of your customers have an account on each platform. More on this below.
5. **Upload with more identifiers.** Add e-mail, name and country columns where you have them. That is the one lever Meta itself recommends.
6. **Refresh on a schedule.** Meta marks a list as Outdated after 30 days. Re-run the hygiene steps before each refresh, not just once.

Here is step 1, and the hashing Meta's API expects, in Node. We ran it on 3 November 2026 with Australian and UK numbers from the ranges reserved for fiction:

```js
import { createHash } from "node:crypto";
import { parsePhoneNumberFromString } from "libphonenumber-js/max";

// raw value from the CRM, and the customer's country from the same record
const rows = [["0491 570 156", "AU"], ["+61 491 570 156", "AU"], ["0061491570157", "AU"], ["(020) 7946 0018", "GB"], ["491 570", "AU"]];

for (const [raw, country] of rows) {
  const p = parsePhoneNumberFromString(raw, country);
  if (!p?.isValid()) { console.log(raw.padEnd(17), "-> drop: not a valid number"); continue; }
  const digits = p.number.slice(1); // E.164 without "+": country code + national number
  const hash = createHash("sha256").update(digits).digest("hex");
  console.log(raw.padEnd(17), "->", p.number, (p.getType() ?? "unknown").padEnd(10), hash.slice(0, 12) + "…");
}
```

```text
0491 570 156      -> +61491570156 MOBILE     10fb72368adc…
+61 491 570 156   -> +61491570156 MOBILE     10fb72368adc…
0061491570157     -> drop: not a valid number
(020) 7946 0018   -> +442079460018 FIXED_LINE 99a4599795d2…
491 570           -> drop: not a valid number
```

The first two rows are the same customer written two ways, so they produce the same hash and should be counted once. The third row is a lesson in international prefixes. Australia dials abroad with `0011`, not `00`, so `0061…` doesn't parse as an Australian number. If your data has `00` prefixes, replace them with `+` before parsing, and check the result. The fourth row is a valid UK landline. The fifth is too short and is dropped.

If you upload a file in Ads Manager, you don't need the hashing step: the [Custom Audience terms](https://www.facebook.com/legal/terms/customaudience) say contact information "is hashed before you upload and pass it to Meta". The normalization still matters, because the country code has to be there before anything is hashed.

## Can you estimate how many numbers have a Facebook or Instagram account?

Yes, roughly. A Facebook or Instagram number check answers one question per number: is an account on that platform associated with it today? The answer is `registered: true`, `false` or unknown, with the time of the check. Run on your own consented list, the share of `true` answers gives you an idea of how many customers Meta could ever match on phone alone.

Read the result as an estimate, for three reasons:

- **It isn't Meta's matcher.** A presence check and Meta's ad matching are separate processes, so your match score won't equal the share of `true` answers.
- **`false` is weak evidence.** On these platforms the number is optional and people control how findable it is. Our guide to [checking a number for Facebook or Instagram](/blog/check-if-a-number-has-facebook-or-instagram) explains why.
- **Unknown means no information.** Treat it as unchecked, never as a no.

What it's good for is deciding where to put effort. If presence is high but the match score is low, look for a format problem. If presence is low, phone is a weak identifier for this list, so add e-mail addresses. If a segment has many dead or landline numbers, fix the data at collection.

What it's not for: the check never returns a profile, name, username or photo, and we don't offer reverse lookups. It must never be used to find people outside your customer base or to build an audience from a bought or scraped list. Requests with 20 or more consecutive numbers are refused as enumeration, and our [acceptable use policy](/legal/acceptable-use) forbids audience building of that kind.

## What consent do you need to upload a customer list?

You need a lawful basis for the upload, and Meta makes you promise you have one. In its Customer List Custom Audiences terms (effective 3 December 2025) you "represent and warrant" that you have "all necessary rights and permissions and a lawful basis to disclose and use the Audience and Customer List Data". You also confirm the list leaves out anyone "who has exercised an option" you offered "to opt out of having such data used to create such audiences", and you must remove people who opt out later ([Meta](https://www.facebook.com/legal/terms/customaudience)). The same terms say Meta "will delete the Customer List Data after the match process is complete", subject to optional features you choose.

Under the [GDPR](https://eur-lex.europa.eu/eli/reg/2016/679/oj), a phone number of a person is personal data, so uploading it, and running hygiene checks on it, needs a lawful basis under Article 6 ([is a phone number personal data?](/blog/is-a-phone-number-personal-data-gdpr)). For marketing use, many businesses rely on consent collected with the number. Rules differ by country, so ask your counsel what applies to your list.

Three rules we apply to every list we check:

- **Only numbers people gave you.** Customers, sign-ups and leads who agreed to hear from you. No bought, scraped or generated lists.
- **Suppress before you check.** Honour opt-outs first, so you don't process numbers you shouldn't hold.
- **Keep the answer, not the raw data.** Store the result, its date and your decision.

## How does MobileValidate help with list hygiene?

One bulk job runs the whole cleanup on your consented list: normalization, deduplication, line type, live status and the optional presence checks. Prices from our live catalog on 3 November 2026 (current prices are on the [pricing page](/pricing)):

| Check | Code | What it tells you | Bulk price per 1,000 | Real time per 1,000 |
|---|---|---|---|---|
| [Carrier and line type](/services/carrier-lookup) (beta) | `network.carrier` | mobile, fixed line, VoIP and carrier | $1.50 | $3.00 |
| [Live network status (HLR)](/services/hlr-lookup) | `number.hlr` | reachable, unreachable, invalid | $5.00 | $6.00 |
| [Facebook](/services/facebook-number-check) | `facebook` | account associated with the number: yes, no, unknown | $0.10 | $0.50 |
| [Instagram](/services/instagram-number-check) | `instagram` | the same, for Instagram | $0.10 | $0.50 |

Unknown and other non-conclusive answers are never charged, nor are invalid numbers and duplicates. Before anything runs, the free estimate shows how many rows are valid, invalid and duplicate. This is real output from the public sandbox key, which answers only test numbers, so `max_cost` is 0. The second number is the first one in national format, and the estimate counts it as a duplicate:

```bash
curl https://api.mobilevalidate.com/v1/jobs/estimate \
  -H "Authorization: Bearer $MOBILEVALIDATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"numbers": ["+447700900001", "07700 900001", "+44 7700 900002", "07700900003"],
       "default_country": "GB", "checks": ["network.carrier", "facebook", "instagram"]}'
```

```json
{"object":"estimate","total":4,"valid":3,"invalid":0,"duplicate":1,"cached":0,"unsupported":0,"suppressed":0,
 "checks":["network.carrier","facebook.registered","instagram.registered"],"checks_total":12,"billable_max":0,
 "max_cost":{"amount":"0","currency":"USD"},
 "breakdown":[{"check":"network.carrier","price_mode":"batch","reason":null,"checks":3,"unit_price":{"amount":"0.0015","currency":"USD"},"max_cost":{"amount":"0","currency":"USD"}},
   {"check":"facebook.registered","price_mode":"batch","reason":null,"checks":3,"unit_price":{"amount":"0.0001","currency":"USD"},"max_cost":{"amount":"0","currency":"USD"}},
   {"check":"instagram.registered","price_mode":"batch","reason":null,"checks":3,"unit_price":{"amount":"0.0001","currency":"USD"},"max_cost":{"amount":"0","currency":"USD"}}],
 "unsupported_checks":[]}
```

The bulk flow: upload a CSV with a `phone` column in the dashboard, or send it to `POST /v1/jobs` (up to 50,000 rows per job), read the estimate, set a cost cap and start. When the job finishes, download the results as CSV with one row per number and columns for each check. Keep the rows you can fix, re-confirm the dead ones with your customers, and upload the normalized list to Meta. The [bulk jobs guide](/docs/bulk-jobs) has the details.

**How to start for free:**

1. [Get a free test key](/get-test-key). It returns fixed answers for the [test numbers](/docs/test-mode), so you can build the whole flow first.
2. [Request access](/request-access) for a live account. Every live account gets 5 real phone checks and 5 real e-mail checks on the dashboard's **Try it** page.
3. Upload your list and read the free estimate before you spend anything. Top-ups of $100 or more get a bonus: +5% from $100, +8% from $500 and +10% from $2,000.

Facebook, Instagram and Meta are named here descriptively. MobileValidate is not affiliated with Meta Platforms, and we can't promise a higher match rate. Only Meta's matcher decides that.

## What are the key takeaways?

- **Meta publishes no target match rate.** The match score is matched rows divided by uploaded rows, and third-party benchmarks are estimates.
- **Every number needs a country code.** For the API, hash the E.164 digits without the plus sign, using SHA-256 in lowercase hex.
- **Valid-looking numbers fail** when they are disconnected, reassigned, landlines or never added to an account. Only formatting errors can be fixed in the file.
- **Clean in this order:** normalize, check line type, check live status, optionally estimate Facebook and Instagram presence, then upload with more identifiers.
- **Removing unmatched rows raises the score but adds no people.** Do it for hygiene, not to make the dashboard look better.
- **Only consented customer lists.** Meta's terms require a lawful basis and respect for opt-outs, and our checks never return profiles.

## Sources

1. [Customer list formatting guidelines for custom audiences (fetched 3 November 2026)](https://www.facebook.com/business/help/2082575038703844) — Meta Business Help Center, 2026
2. [About customer list custom audiences (fetched 3 November 2026)](https://www.facebook.com/business/help/341425252616329) — Meta Business Help Center, 2026
3. [Custom Audiences: hashing and normalizing data, multi-key matching (Marketing API, fetched 3 November 2026)](https://developers.facebook.com/docs/marketing-api/audiences/guides/custom-audiences) — Meta for Developers, 2026
4. [Customer List Custom Audiences Terms (effective 3 December 2025)](https://www.facebook.com/legal/terms/customaudience) — Meta, 2025
5. [How to improve Facebook custom audience match rate (ad-tools blog, undated, fetched 3 November 2026)](https://leadenforce.com/blog/how-to-improve-facebook-custom-audience-match-rate) — LeadEnforce, 2026
6. [General Data Protection Regulation (EU) 2016/679](https://eur-lex.europa.eu/eli/reg/2016/679/oj) — European Union, 2016

## Frequently asked questions

### What is a good match rate for a Meta Custom Audience built from phone numbers?

Meta publishes no target or guaranteed match rate. Its help pages only say that more identifiers per customer give a better chance of matching. Third-party blogs quote rough ranges, such as 60–80% for recent buyers and 20–40% for older CRM records, but those are unsourced estimates. Compare your own uploads over time instead.

### Which phone number format does Meta want in a customer list?

Every number needs its country code, even if all customers are in one country. In a file upload Meta accepts numbers with or without punctuation, in up to three phone columns. Through the Marketing API you normalize first (digits only: no symbols, letters or leading zeros, country code included) and send the SHA-256 hash.

### Should the hashed phone number include the plus sign?

No. Meta's Marketing API rules say to remove symbols, so you hash the digits of the E.164 number without the +, for example 61491570156. A hash of +61491570156 is a different value and will not match.

### Why do correctly formatted numbers still not match?

Because a match needs a Meta account that holds that number. Numbers that are disconnected or reassigned, landlines, and numbers whose owner never added them to Facebook or Instagram cannot match, however well they are formatted.

### Will removing unmatched numbers improve my campaign?

It raises the reported match score, because Meta divides matched rows by uploaded rows, but it adds no new people to the audience. Remove dead numbers for list hygiene, and fix numbers with formatting errors, because those are the rows that can actually start matching.

### Can MobileValidate raise my match rate?

We can't promise a higher match rate, and nobody outside Meta can. A bulk job helps you find rows with formatting errors, dead numbers and landlines, and estimates how many of your consented customers have a Facebook or Instagram account, before you spend money on a test campaign.

### Does the Facebook or Instagram check return the customer's profile?

No. Each check answers registered, not registered or unknown, with the time of the check. It never returns a name, username, photo or profile link, and nothing is sent to the number.

### Do I need consent to upload a customer list to Meta?

You need a lawful basis for the upload, and Meta's Custom Audience terms make you promise that you have one, and that you leave out people who opted out of this use. In many countries that means consent for marketing use. Ask your counsel, and never upload or check numbers you bought, scraped or generated.
