Event Match Quality: a practical guide to raising your EMQ
What Meta's EMQ score actually measures, which user_data fields move it, the exact normalization and SHA-256 hashing rules, and why higher scores tend to mean cheaper results.
Event Match Quality (EMQ) is Meta's 0-10 score, shown per event type in Events Manager, estimating how well the user_data you send with each event lets Meta match that event to a real account. It is not a vanity metric. An event Meta cannot match to a person is an event that cannot be attributed to an ad, cannot exit an ad set from learning, and cannot teach the delivery system anything. Matching is the gate everything else passes through.
The score is computed from which identifiers you send, how often they're present, and how often they match. Which means it is also one of the few platform metrics you can engineer directly.
The fields that move the score
All customer information parameters help, but they are nowhere near equal. In practice, roughly in order of impact:
| Field | What it is | Notes |
|---|---|---|
em | SHA-256 of normalized email | The workhorse. Stable across devices and years; the single highest-value field. |
ph | SHA-256 of normalized phone | Nearly as strong as email where you collect it (checkout, lead forms). |
fbc / fbp | Click ID cookie / browser ID cookie | fbc ties the event to a specific ad click, which is huge for attribution. Sent raw, never hashed. |
external_id | SHA-256 of your own user/visitor ID | Consistency is the point: send the same value for the same person on every event. |
client_ip_address + client_user_agent | Raw IP and UA of the visitor | Weak alone, valuable in combination. Required context for website events via CAPI. |
fn, ln, ct, st, zp, country, db, ge | Hashed name, geo and demographic fields | Individually weak, but they compound. Send them when the order record already contains them. |
Normalization before hashing: the part everyone gets wrong
Hashing is deterministic: [email protected] and [email protected] produce completely different SHA-256 digests. If you hash without normalizing exactly the way Meta does, your hash will never equal the hash Meta holds, and the field contributes nothing. The rules:
- Email: trim whitespace, lowercase, then hash.
- Phone: strip everything but digits, include country code, no leading zeros or
+: E.164 without the plus (15551234567), then hash. - Names, city, state: lowercase, strip punctuation and whitespace (
stas two-letter code, e.g.ca), then hash. - Zip: lowercase; US zips as the first five digits.
- Date of birth:
YYYYMMDD. Gender:form. - Never hash
fbc,fbp,client_ip_addressorclient_user_agent, which must arrive raw. And never double-hash: hashing an already-hashed value silently zeroes its matching value.
import { createHash } from "crypto";
const sha256 = (v: string) =>
createHash("sha256").update(v).digest("hex");
const em = sha256(email.trim().toLowerCase());
const ph = sha256(phone.replace(/\D/g, "")); // "+1 (555) 123-4567" -> "15551234567"
// Rebuild fbc from a captured fbclid if the cookie is gone:
// fb.<subdomainIndex>.<creationTime>.<fbclid>
const fbc = `fb.1.${clickCapturedAtMs}.${fbclid}`;Realistic ways to raise EMQ
- Send email on every event you can, not just Purchase. The biggest EMQ gaps are usually upper-funnel events (AddToCart, InitiateCheckout) sent with cookies only. If the visitor is logged in or has entered an email at any prior step, a server-side setup can attach the hash to every subsequent event.
- Capture
fbclidon landing and persist it. The_fbccookie dies with ITP's seven-day cap; the click ID you stored first-party does not. Rebuildingfbcat conversion time (format above) is the single most underrated EMQ lever, because it also directly restores click-through attribution. - Ship a stable
external_id. Use your internal user ID or a persistent first-party visitor ID, hashed, identical across pixel and CAPI. Its value comes from repetition: one-off IDs are noise. - Move purchase events server-side.Order records contain the customer's real email, phone, name and address, fields the browser pixel rarely sees. Sending Purchase from the server with the full order identity routinely lifts that event's EMQ from the 4-5 range into the 8+ range.
- Fix the silent quality killers. Empty strings instead of omitted fields, hashes of placeholder values (
sha256(""),sha256("null")), uppercase emails hashed verbatim, phones without country codes. Each one reads as a “sent but never matches” field, which drags the score harder than sending nothing.
What doesn't work: stuffing fabricated or bought data into user_data. Matching runs against Meta's accounts; invented identifiers don't match anything, and misrepresenting event data is a policy violation with real enforcement.
Why EMQ correlates with cheaper results
EMQ doesn't buy you anything by itself. It is a proxy for how many of your events survive matching. But that proxy sits upstream of everything expensive:
- Attribution:matched events get credited to campaigns; unmatched ones vanish into “organic”. Higher match rates mean reported CPA falls toward your true CPA.
- Optimization: the delivery system learns from attributed conversions. More matched events means faster learning on a less biased sample of your buyers.
- Audiences: lookalikes and Advantage+ audiences are seeded by matched converters. Better matching, better seed, better expansion.
Meta's own guidance says the quiet part: advertisers with higher EMQ tend to see lower cost per result, because the system is optimizing on more complete data. Treat the exact numbers with skepticism. The direction, though, matches what anyone who has lifted an account's EMQ has watched happen. It is the same mechanism we describe in What is signal loss? running in reverse: give the algorithm back the data it was missing, and it stops paying a blindness tax with your budget.
Check your scores now: Events Manager → your pixel/dataset → each event → Event Match Quality. Anything below 6 on a revenue event is money on the table, and it is almost always fixable with the list above plus a proper server-side setup.