In Meta Conversions API, client_ip_address and client_user_agent must represent the actual end-user's browser, NOT your application server or cloud proxy. The IP address must be a valid public IPv4 (e.g. 73.189.42.15) or IPv6 address (not private subnets like 10.0.0.1 or 127.0.0.1), and client_user_agent must be the complete, unparsed User-Agent header string. These fields must NOT be hashed.
1. The Cloud Proxy IP Leak Disaster
When servers communicate with Meta CAPI, developers frequently make a critical error: they pass `req.socket.remoteAddress` as the `client_ip_address`. Behind cloud load balancers (Cloudflare, AWS ALB, Fastly), this returns the private IP of the load balancer (e.g. `10.0.1.45`).
Meta's API accepts the event with an HTTP 200 OK, but internally discards the IP because it is a non-routable private address. Over weeks, your Event Match Quality suffers silently without throwing a single error in your server logs.
- Private IP Subnet Leaks: Passing internal 10.x, 172.16.x, or 192.168.x addresses.
- Truncated User Agents: Stripping OS version details and device signatures.
- Accidental Hashing: Running SHA256 on IP addresses or user agents (Meta mandates plaintext for these two fields).
2. Comparative Analysis: Standard Tracking vs CAPI Control
The table below outlines the architectural and financial differences between passive conversion tracking and active signal governance:
| Parameter | Hashing Requirement | Common Error | Correct Syntax |
|---|---|---|---|
| client_ip_address | DO NOT HASH (Plaintext) | Passing load balancer IP: '10.0.0.1' | True client public IP: '73.189.42.15' |
| client_user_agent | DO NOT HASH (Plaintext) | Passing truncated name: 'Chrome Mobile' | Full header: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5)...' |
| IPv6 Addresses | DO NOT HASH (Plaintext) | Malformed colon syntax | Standard RFC 4291 IPv6 string |
3. True Client IP Extraction Middleware
Extract the true public IP address across multiple cloud proxies and reverse tunnels:
// True Client IP Extraction Function
export function getTrueClientIP(headers) {
// Cloudflare Connecting IP (Most reliable if on Cloudflare)
if (headers["cf-connecting-ip"]) return headers["cf-connecting-ip"];
// Standard X-Forwarded-For header (First IP is the true client)
const xForwardedFor = headers["x-forwarded-for"];
if (xForwardedFor) {
const ips = xForwardedFor.split(",").map(ip => ip.trim());
return ips[0]; // Client is always the leftmost IP
}
// Fastly / AWS Real IP headers
return headers["x-real-ip"] || headers["true-client-ip"];
}
How to Deploy CAPI Control to Fix This Today
- Step 1: Check your server-side payload logs to confirm `client_ip_address` is a public routable IP.
- Step 2: Confirm that `client_ip_address` and `client_user_agent` are sent as raw plaintext (NOT hashed).
- Step 3: Deploy CAPI Control to automatically parse edge network headers correctly.
- Step 4: Observe immediate EMQ score recovery in Meta Events Manager.
Frequently Asked Questions
Why does Meta require plaintext for IP and User-Agent?
Because IP addresses and user agents must be matched against live active network sessions, which requires immediate plaintext parsing rather than hash comparisons.
What happens if a customer is on an IPv6 connection?
Meta fully supports IPv6 addresses. Pass them exactly as received in the network header.
Does passing client_user_agent impact privacy compliance?
User agent strings represent device architecture and do not contain personal identities, fully conforming to standard web analytics practices.
Ready to steer Meta & Google toward your most profitable traffic?
Drop in CAPI Control in under 2 minutes. Transmit 100% of conversion signals free forever, or activate autonomous signal AI agents to get 3x better ad traffic.