Skip to content
Crafzo
Menu

IP lookup essentials

X-Forwarded-For Header: How to Get the Real Client IP Behind a Proxy

X-Forwarded-For carries the client address through proxies and CDNs, and anyone can forge it. How to read it safely from a trusted hop and get the real client IP.

Updated
Reading time
3 min read

Header format and order

The `X-Forwarded-For` header is a comma-separated list of IPs added by proxies, often shaped like `client, proxy1, proxy2`. Many apps use the leftmost value as the original client IP, but that is safe only when the header chain is controlled by trusted infrastructure.

If any public client can send requests directly to your app, it can also send a fake `X-Forwarded-For` header. Your server must know which proxy added or sanitized the header before using it for rate limits, logging, or security decisions.

Trusted proxy pattern

A safer pattern is to maintain a trusted proxy list and walk the forwarded chain from right to left until you reach the first untrusted address. In TypeScript, that means parsing the header into IP strings, validating each item, and comparing proxy hops against your known load balancer or CDN ranges.

Cloudflare users should prefer `CF-Connecting-IP` when requests are guaranteed to come through Cloudflare. Vercel and many load balancers expose `x-real-ip` or normalized forwarded headers, but you should still confirm the deployment behavior.

Use the result responsibly

Once extracted, normalize the IP and store the original header only if you have a clear debugging or security need. Be careful with private, loopback, malformed, or reserved addresses because they should not be treated as public user locations.

For high-risk decisions, combine the extracted client IP with account history, request velocity, authentication state, and lookup results. Crafzo is useful for checking whether the chosen IP belongs to the expected country, ISP, or proxy type.

Validate the value before you look it up or store it. Accept both address families: a growing share of real clients, especially on mobile carriers, arrive over IPv6, and a check that only understands dotted-decimal IPv4 will reject or mishandle them. Normalize the address (IPv6 has several equivalent spellings) and treat empty, malformed, and private-only inputs as errors when a public location is what you need.

Frequently asked questions

Keep reading