Geographic Performance Variation in CDN Networks: Why Speed Differs by Region

Last year I was on a call with an e-commerce team who couldn't figure out why their new image-heavy homepage felt instant in New York and London but sluggish in São Paulo and Mumbai. Their origin was in Virginia, their CDN coverage map looked perfect, yet real-user data showed a 4x difference in Largest Contentful Paint. We pulled up the edge logs and the story was obvious — geographic performance isn't just about having a dot on a map, it's about what happens between that dot and the user.

The Physics Haven't Changed: Why Fiber Distance Still Governs Latency Geography

We’ve spent a decade pushing assets closer to users, but we can't negotiate with the speed of light. In a vacuum, light travels at about 300km per millisecond. In fiber, it’s slower — roughly 200km per millisecond — and that signal never travels in a straight line. Your packet from Chicago to Sydney doesn’t cut through the Earth; it bounces through terrestrial fiber to a subsea cable landing station, rides a system like Southern Cross or SEA-ME-US, then hops through metro fiber and last-mile networks. I learned this the hard way back in 2016 when we were debugging why traffic from our Johannesburg PoP to users in Lagos was routing via London — the terrestrial fiber path simply didn’t exist yet, so the round trip was paying a double ocean-crossing penalty.

That distance translates directly into RTT, and RTT controls everything else. For a TLS 1.3 connection you’re looking at one round trip for the handshake, another for the HTTP request, and then TCP’s congestion control has to ramp up. On a 15ms link in Frankfurt, that’s trivial. On a 280ms link to rural Indonesia, those same round trips add up to nearly a second before you’ve even delivered the first byte of HTML. This is where Bandwidth-Delay Product and CDN Tuning: Filling the Pipe Without Overwhelming It becomes critical — if you don’t size your initial congestion window and buffers for the actual BDP of the long-haul path, you’ll spend several additional RTTs just getting to full throughput. The HTTP Working Group Specifications at https://httpwg.org/specs/ still assume these round trips in their timing models, and they’re a useful reality check when your lab tests on localhost look nothing like field data.

# Measure geographic RTT and TTFB differences from the edge
# Run this from different vantage points or use a RUM collector
for edge in "iad.example-cdn.net" "fra.example-cdn.net" "sin.example-cdn.net" "gru.example-cdn.net"; do
  echo "=== Testing $edge ==="
  curl -o /dev/null -s -w "DNS: %{time_namelookup}s | TCP: %{time_connect}s | TLS: %{time_appconnect}s | TTFB: %{time_starttransfer}s | Total: %{time_total}s\n" \
  "https://$edge/static/test-100k.jpg?cache-bust=$(date +%s)"
done

# For deeper path analysis, mtr shows where the latency geography hits
mtr --tcp -P 443 -c 20 sin.example-cdn.net

Peering Density and Infrastructure Gaps: Why CDN Speed by Region Isn't Just Miles

If geography were the only factor, performance would degrade in perfect concentric circles from your origin. It doesn’t. I’ve seen users 500km from a PoP in a poorly peered market get worse performance than users 3,000km away in a well-connected one. The difference is interconnection density. In regions like Western Europe or the US East Coast, a single CDN edge might have direct peering with 200+ networks at an IXP like DE-CIX or Equinix Ashburn, plus private network interconnects (PNIs) with the big eyeball ISPs. That keeps the path short and uncongested. In parts of Africa, South Asia, and rural Latin America, that same edge might rely on a single transit provider with limited capacity, adding hops, bufferbloat, and contention. We once chased a regional variation issue in Manila where p95 latency was 4x the median — it turned out one dominant ISP was rate-limiting transit during peak hours, and traffic that should have been served from our Manila cache was tromboning through Hong Kong.

Last-mile conditions amplify that core difference. Even if the CDN has a great PoP in-country, the access network might be congested 4G, legacy DSL, or CGNAT-heavy mobile infrastructure with high packet loss. TCP interprets loss as congestion and backs off, which is devastating on high-RTT links. You can’t fix the radio, but you can tune the stack. That’s why I always check TCP Window Scaling and Its Impact on CDN Throughput: Why Defaults Fall Short when we onboard a new region — default window sizes that work fine for a 20ms RTT in Amsterdam will starve throughput on a 180ms link to Chennai. You’ll want larger initial windows, proper window scaling support, and often a more aggressive loss recovery like BBR instead of CUBIC for those networks. Articles on https://web.dev/articles/ do a good job of connecting these transport realities to what users actually experience in Core Web Vitals.

# Python: estimate if your TCP settings fit the region's BDP
# Run this for each target region's typical RTT and bottleneck bandwidth

def check_bdp(rtt_ms, bandwidth_mbps, tcp_window_kb=64):
    rtt_s = rtt_ms / 1000
    bandwidth_bps = bandwidth_mbps * 1_000_000
    bdp_bytes = bandwidth_bps * rtt_s / 8
    bdp_kb = bdp_bytes / 1024
    window_ok = tcp_window_kb >= bdp_kb
    return {
        "bdp_kb": round(bdp_kb, 1),
        "window_kb": tcp_window_kb,
        "window_sufficient": window_ok,
        "recommendation": "OK" if window_ok else f"Increase window to ~{int(bdp_kb * 1.5)}KB or enable scaling"
    }

# Well-peered region: low RTT, high bandwidth
print(check_bdp(rtt_ms=18, bandwidth_mbps=100, tcp_window_kb=64))
# Poorly-peered, high-latency region: same window fails
print(check_bdp(rtt_ms=185, bandwidth_mbps=25, tcp_window_kb=64))
# With scaling enabled
print(check_bdp(rtt_ms=185, bandwidth_mbps=25, tcp_window_kb=512))

What Regional Variation Looks Like in Production Metrics

You can’t tune what you don’t measure correctly. Synthetic checks from a single global monitor won’t show you geographic performance at all — they’ll just show you how great your backbone is. I’ve learned to rely on a mix of Real User Monitoring (RUM) segmented by country, ASN, and PoP, plus active probes from diverse eyeball networks. Be careful how you collect RTT, too. A lot of teams grab it from the TCP handshake at the edge and call it a day, but that ignores the last-mile and Wi-Fi tail. For accurate edge-to-user numbers, you need timing from the client side, like Navigation Timing and Resource Timing APIs. If you’re building your own collector, read RTT Measurement Methodology for CDN: Getting Accurate Round-Trip Times first — small mistakes like using time-to-first-byte instead of actual RTT or averaging p50 and p95 together will hide the very regional spikes you’re trying to find.

The table below is a composite pulled from a media customer I worked with last quarter. Same 850KB hero bundle, same cache hit at the edge, same TLS 1.3 + HTTP/2 stack. The only variable was the user’s geography and local network. Notice how CDN speed by region diverges not just on median RTT but on p95 and throughput — that tail is where poor peering and last-mile loss show up. North America and Western Europe are boringly fast because they have dense PoPs, abundant peering, and modern access networks. Southeast Asia and South America look OK on median but fall apart at p95, which matched exactly where we saw transit congestion and mobile packet loss in our logs.

Region (Eyeball Network) Median RTT p95 RTT Median TTFB (Cache HIT) Avg. Throughput (HIT)
Western Europe (DE-CIX peered) 14 ms 28 ms 22 ms 78 Mbps
US East Coast (Ashburn peered) 18 ms 35 ms 27 ms 65 Mbps
Southeast Asia (Manila, transit-heavy) 48 ms 210 ms 85 ms 18 Mbps
South America (São Paulo, mixed peering) 42 ms 185 ms 71 ms 22 Mbps
Oceania (Sydney, well-peered but distant) 32 ms 68 ms 41 ms 45 Mbps

Implementing Region-Aware CDN Performance Optimization

You'll never beat the speed of light, but you can be a lot smarter about how you dance around it. Once you've mapped your regional variance — and I mean really mapped it, per-PoP, per-ASN, per-hour — the fix isn't just "add more PoPs." We've seen teams throw three new edge locations in South America and move their p95 by 4ms. The real gains come from tiered architecture and smarter request routing. In practice, that means moving from a single global anycast blanket to a latency-aware, performance-based routing layer.

Start by segmenting your traffic. Don't look at global averages; break RUM data down by continent, then country, then network. When we audited a large e-commerce platform last year, their global p50 looked great at 38ms. But their p95 in Southeast Asia was 340ms and their p99 in Johannesburg was pushing 680ms — entirely because origin fetches were falling back to us-east-1 across 14,000km of fiber. By deploying a tiered origin shield in Singapore (ap-southeast-1) and Frankfurt, and enabling true EDNS Client Subnet (ECS) support so DNS resolvers pass the client subnet to your authoritative DNS, we cut cache MISS latency for those regions by 62%. If you're not measuring tail latency correctly, you're flying blind — our guide on CDN Percentile Latency Analysis: What p50, p95, and p99 Actually Tell You breaks down why that p50 number is lying to you.

The implementation itself is straightforward with most modern CDNs. The pattern below is a simplified edge worker for multi-CDN, performance-based failover. It doesn't just fail over on 5xx errors; it actively steers users away from a high-latency PoP based on real-time RUM thresholds. We've used this to shave 25-40ms off p95 in regions where a single provider has thin peering.

// Edge Worker: Latency-aware multi-CDN steering
// Runs at the outer CDN layer, decides origin/CDN path per region
const REGIONAL_THRESHOLDS = {
  'SA-EAST': { p95_target: 85, failover_cdn: 'cdn-b.sa-east.example.net' },
  'AP-SOUTHEAST': { p95_target: 75, failover_cdn: 'cdn-b.ap-southeast.example.net' },
  'AF-SOUTH': { p95_target: 95, failover_cdn: 'cdn-b.af-south.example.net' },
  'DEFAULT': { p95_target: 60, failover_cdn: 'cdn-b.global.example.net' }
};

async function handleRequest(request, region, observedP95) {
  const config = REGIONAL_THRESHOLDS[region] || REGIONAL_THRESHOLDS.DEFAULT;
  
  // If recent RUM p95 for this region exceeds target, steer 20% of traffic
  if (observedP95 > config.p95_target) {
    if (Math.random() < 0.20) {
      // Add header for observability - track steering rate in logs
      request.headers.set('X-CDN-Steer-Reason', `p95:${observedP95}ms>target:${config.p95_target}ms`);
      return fetch(`https://${config.failover_cdn}${new URL(request.url).pathname}`, request);
    }
  }
  return fetch(request);
}

// Collect RUM beacon and update regional p95 in KV store (e.g., Cloudflare Workers KV / Fastly Config Store)
// Beacon payload: { region, ttfb, asn, colo }

Advanced Patterns and Troubleshooting Stubborn Regional Outliers

You've deployed shields, you've tuned anycast, and yet one region — let's say Chennai or Lima — still shows a stubborn 150ms jitter and 12% slower throughput than you'd expect for the distance. That's where you have to stop looking at distance and start looking at path quality. Two of the biggest hidden culprits we see aren't distance at all; they're jitter and packet reordering. A link might have a decent 45ms median, but if its jitter is +/- 30ms, your TCP congestion window never stabilizes and your effective throughput collapses. Don't just chart latency, chart its variance — as we detail in CDN Jitter Measurement and Its Impact on User Experience, a region with 50ms ± 5ms will consistently outperform one with 35ms ± 25ms for video and large asset delivery.

Packet reordering is the other silent killer, especially on congested peering links in emerging markets or over long-haul routes with equal-cost multi-path (ECMP) hashing issues. When packets arrive out of order, even by 2-3 positions, TCP assumes loss, triggers fast retransmit, and halves its window. You'll see it as high retransmit rates ( >0.8% is a red flag ) and throughput that plateaus at 1-2 Mbps despite plenty of bandwidth. We've traced this in Western Africa where a single upstream was doing per-packet load balancing — fixing it by forcing per-flow ECMP at the peer cut reordering from 1.4% to 0.06% and instantly doubled throughput. If your regional throughput graphs look flat while latency looks okay, dig into reordering. Our deep dive on Packet Reordering Effects on CDN Performance: The Hidden Throughput Killer has the tcpdump and Wireshark patterns to confirm it.

For troubleshooting, isolate ruthlessly. Don't test from your corporate VPN in Virginia. Spin up synthetic tests from the actual eyeball networks: use RIPE Atlas probes, Catchpoint nodes on local ISPs, or even cheap VPS instances on Telkom Indonesia, Vivo Brazil, or MTN Nigeria. Compare anycast vs. unicast performance, test with and without Argo/transfer acceleration, and pull a traceroute with TCP SYN on port 443 — ICMP is often deprioritized and lies. If you see >15% latency difference between ICMP and TCP traceroute, you've got policing or congested middleboxes in the path.

Frequently Asked Questions

Why is my CDN fast in the US and EU but 3x slower in Southeast Asia or Africa?

It's almost always a combination of distance to origin and peering density, not your CDN vendor being "bad" there. In the US/EU, there are hundreds of peering points and your content is likely cached at an edge 5-15ms away. In Jakarta, Manila, or Lagos, you may be backhauling 180-250ms to a shield in Singapore or Frankfurt on a cache MISS, and the last-mile ISP might have only one or two congested transit links. Fix it with a regional origin shield, ensuring ECS is enabled, and checking that your CDN actually has a PoP inside the major local ISPs, not just in the country's capital.

Will adding more CDN PoPs automatically fix regional latency?

Not necessarily. More PoPs helps only if they're placed where your users' packets actually flow. We've seen a 40-PoP expansion deliver <5ms improvement because the new PoPs weren't peered with the dominant eyeball networks. A single well-peered PoP inside a major local exchange (like IX.br in Brazil or NAPAfrica in Johannesburg) will outperform three poorly-peered ones nearby. Always validate with ASN-level RUM data before buying more coverage.

What's an acceptable jitter threshold for CDN delivery?

For static assets and web pages, aim for jitter under 10ms on your p95. For low-latency video (LL-HLS/DASH) or real-time APIs, you really want under 5ms. If you're seeing jitter of 20-30ms+ in a region, expect rebuffering, TCP throughput collapse, and wildly inconsistent TTFB. That's often a sign of bufferbloat or congested peering — not just distance — and needs path-level investigation, not just cache tuning.

How should I measure regional CDN performance correctly?

Don't rely on synthetic ping from a single provider. Combine three sources: 1) RUM beacons from real users measuring TTFB, download time, and ASN/colo, 2) Synthetic tests from RIPE Atlas or ISP-hosted probes in the target region, and 3) CDN log analysis broken down by cache HIT/MISS ratio per PoP. And always look at p95/p99, not just the average. A region with a 45ms p50 but a 400ms p99 has a severe tail problem — usually origin fetches or reordering — that an average will completely hide.

Related Articles

References & Standards: HTTP Working Group Specifications · web.dev Articles · IETF Datatracker