PerformanceJanuary 1, 2024ยท 8 min read
CDN Detection: Is This Website Using a Content Delivery Network?
A practical Fusebox guide to cdn detection.
CDN Detection: Is This Website Using a Content Delivery Network?
Published: January 2024
Reading time: 7 minutes
Content Delivery Networks (CDNs) serve websites from servers closest to users, dramatically improving performance. Here's how to detect CDN usage, understand its impact, and analyze CDN performance.
What CDNs Reveal
When you detect a CDN, you learn:
- Performance priority - Site cares about speed
- Global reach - Serving international users
- Traffic scale - High traffic needs CDN
- Cost investment - CDNs aren't free
- Technical sophistication - Proper implementation
Quick CDN Detection
1. Response Headers Check
// Quick CDN detection via headers
(function detectCDN() {
fetch(window.location.href)
.then(response => {
const headers = response.headers;
const cdnHeaders = {
'cf-ray': 'Cloudflare',
'x-amz-cf-id': 'Amazon CloudFront',
'x-akamai-transformed': 'Akamai',
'x-fastly-request-id': 'Fastly',
'x-served-by': 'Various CDNs',
'x-cache': 'Various CDNs',
'via': 'Various CDNs/Proxies'
};
console.log('๐ CDN Detection Results:\n');
let cdnDetected = false;
for (const [header, cdn] of Object.entries(cdnHeaders)) {
const value = headers.get(header);
if (value) {
console.log(`โ
${cdn} detected via ${header}: ${value}`);
cdnDetected = true;
}
}
if (!cdnDetected) {
console.log('โ No CDN detected via headers');
}
// Check server header
const server = headers.get('server');
if (server) {
console.log(`\nServer header: ${server}`);
if (server.toLowerCase().includes('cloudflare')) {
console.log('โ
Cloudflare confirmed');
}
}
});
})();
2. DNS and IP Analysis
// Detect CDN via domain analysis
async function analyzeCDN() {
const resources = performance.getEntriesByType('resource');
const domains = new Set();
const cdnPatterns = {
'cloudflare': ['cloudflare'],
'cloudfront': ['cloudfront.net', 'amazonaws.com'],
'akamai': ['akamaihd.net', 'akamaized.net'],
'fastly': ['fastly.net', 'fastlylb.net'],
'maxcdn': ['maxcdn.com', 'netdna-cdn.com'],
'bunny': ['bunnycdn.com', 'b-cdn.net'],
'jsDelivr': ['jsdelivr.net'],
'unpkg': ['unpkg.com'],
'cdnjs': ['cdnjs.cloudflare.com']
};
// Collect all external domains
resources.forEach(resource => {
const url = new URL(resource.name);
if (url.hostname !== location.hostname) {
domains.add(url.hostname);
}
});
console.log('๐ CDN Usage Analysis:\n');
// Check each domain against CDN patterns
const cdnsFound = new Set();
domains.forEach(domain => {
for (const [cdn, patterns] of Object.entries(cdnPatterns)) {
if (patterns.some(pattern => domain.includes(pattern))) {
cdnsFound.add(cdn);
console.log(`โ
${cdn}: ${domain}`);
}
}
});
if (cdnsFound.size === 0) {
console.log('No public CDN usage detected');
} else {
console.log(`\nTotal CDNs used: ${cdnsFound.size}`);
}
}
analyzeCDN();
Common CDN Patterns
1. Cloudflare
// Cloudflare detection
{
headers: {
'cf-ray': '7a1234567890abcd-SJC',
'cf-cache-status': 'HIT',
'server': 'cloudflare'
},
features: [
'DDoS protection',
'Auto minification',
'Rocket Loader',
'Polish image optimization'
]
}
// Check Cloudflare features
if (window.Rocket) {
console.log('Cloudflare Rocket Loader active');
}
2. Amazon CloudFront
// CloudFront headers
{
'x-amz-cf-id': 'cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==',
'x-amz-cf-pop': 'SFO5-C1',
'x-cache': 'Hit from cloudfront',
'via': '1.1 08f323deadbeef892.cloudfront.net (CloudFront)'
}
// Often paired with S3
// Look for: .s3.amazonaws.com or .cloudfront.net domains
3. Fastly
// Fastly detection
{
'x-served-by': 'cache-sjc10047-SJC',
'x-cache': 'HIT',
'x-cache-hits': '5',
'x-timer': 'S1234567890.123456,VS0,VE0',
'via': '1.1 varnish'
}
// Fastly uses Varnish
// Very fast, often < 50ms response times
CDN Performance Analysis
1. Cache Hit Ratio
// Analyze CDN cache effectiveness
function analyzeCachePerformance() {
const resources = performance.getEntriesByType('resource');
const stats = {
total: 0,
hits: 0,
misses: 0,
noInfo: 0
};
resources.forEach(resource => {
fetch(resource.name, { method: 'HEAD' })
.then(response => {
stats.total++;
// Check various cache headers
const cacheStatus =
response.headers.get('cf-cache-status') ||
response.headers.get('x-cache') ||
response.headers.get('x-cache-status');
if (cacheStatus) {
if (cacheStatus.toUpperCase().includes('HIT')) {
stats.hits++;
} else if (cacheStatus.toUpperCase().includes('MISS')) {
stats.misses++;
}
} else {
stats.noInfo++;
}
// Log results after checking all resources
if (stats.total === resources.length) {
const hitRate = (stats.hits / (stats.hits + stats.misses) * 100).toFixed(1);
console.log('๐ CDN Cache Performance:');
console.log(`Hit Rate: ${hitRate}%`);
console.log(`Hits: ${stats.hits}`);
console.log(`Misses: ${stats.misses}`);
console.log(`No cache info: ${stats.noInfo}`);
}
});
});
}
2. Geographic Performance
// Measure CDN response times
async function measureCDNLatency() {
const testUrls = [
{ url: '/favicon.ico', type: 'origin' },
{ url: '/static/css/main.css', type: 'static' },
{ url: '/api/health', type: 'dynamic' }
];
console.log('โก CDN Latency Test:\n');
for (const test of testUrls) {
const measurements = [];
// Multiple measurements for accuracy
for (let i = 0; i < 3; i++) {
const start = performance.now();
try {
await fetch(test.url, {
method: 'HEAD',
cache: 'no-cache'
});
const latency = performance.now() - start;
measurements.push(latency);
} catch (e) {
console.error(`Failed to fetch ${test.url}`);
}
}
if (measurements.length > 0) {
const avg = measurements.reduce((a, b) => a + b) / measurements.length;
console.log(`${test.type}: ${avg.toFixed(1)}ms average`);
// CDN should be < 100ms for static content
if (test.type === 'static' && avg < 100) {
console.log(' โ
Good CDN performance');
} else if (test.type === 'static' && avg > 200) {
console.log(' โ ๏ธ Slow for CDN-cached content');
}
}
}
}
Real-World CDN Examples
Example 1: E-commerce Site
// High-performance setup
{
"HTML": "Cloudflare (cached for 5 min)",
"CSS/JS": "Cloudflare (cached for 1 year)",
"Images": "Cloudfront + S3",
"API": "No CDN (dynamic)",
"Performance": {
"Static hit rate": "94%",
"Image optimization": "WebP via Polish",
"Compression": "Brotli",
"HTTP/2 Push": "Enabled"
}
}
// Benefits observed:
// - 65% faster page loads globally
// - 80% reduction in origin traffic
// - $500/month saved in bandwidth
Example 2: News Website
// Multi-CDN strategy
{
"Primary CDN": "Fastly",
"Image CDN": "Cloudinary",
"Video CDN": "Akamai",
"Cache Strategy": {
"Homepage": "1 minute",
"Articles": "5 minutes",
"Breaking news": "30 seconds",
"Images": "30 days"
},
"Results": {
"Global latency": "<50ms",
"Availability": "99.99%",
"Bandwidth saved": "95%"
}
}
Example 3: SaaS Application
// CDN with security focus
{
"CDN": "Cloudflare Enterprise",
"Security Features": {
"WAF": "Enabled",
"DDoS": "Always active",
"Bot protection": "Challenge suspicious",
"Rate limiting": "100 req/min"
},
"Performance": {
"Argo routing": "20% faster",
"Workers": "Edge computing",
"Cache": "Aggressive for assets"
}
}
CDN Configuration Detection
1. Cache Headers Analysis
// Understand caching strategy
function analyzeCacheStrategy() {
const resources = performance.getEntriesByType('resource');
const strategies = {
aggressive: [], // > 1 day
moderate: [], // 1 hour - 1 day
conservative: [], // < 1 hour
none: [] // no-cache
};
resources.forEach(async resource => {
const response = await fetch(resource.name, { method: 'HEAD' });
const cacheControl = response.headers.get('cache-control');
if (cacheControl) {
const maxAge = cacheControl.match(/max-age=(\d+)/);
if (cacheControl.includes('no-cache') || cacheControl.includes('no-store')) {
strategies.none.push(resource.name);
} else if (maxAge) {
const seconds = parseInt(maxAge[1]);
if (seconds > 86400) {
strategies.aggressive.push({ url: resource.name, days: (seconds/86400).toFixed(1) });
} else if (seconds > 3600) {
strategies.moderate.push({ url: resource.name, hours: (seconds/3600).toFixed(1) });
} else {
strategies.conservative.push({ url: resource.name, minutes: (seconds/60).toFixed(1) });
}
}
}
});
console.log('๐ Cache Strategy Analysis:', strategies);
}
2. CDN Feature Detection
// Detect advanced CDN features
async function detectCDNFeatures() {
const features = {
http2: false,
http3: false,
brotli: false,
webp: false,
minification: false,
security: false
};
// Check protocol
if (performance.getEntriesByType('navigation')[0].nextHopProtocol.includes('h2')) {
features.http2 = true;
}
// Check compression
const response = await fetch(location.href);
const encoding = response.headers.get('content-encoding');
if (encoding?.includes('br')) {
features.brotli = true;
}
// Check security headers (indicates CDN WAF)
if (response.headers.get('x-frame-options') ||
response.headers.get('x-content-type-options')) {
features.security = true;
}
// Check for WebP support
const images = Array.from(document.images);
if (images.some(img => img.src.includes('.webp'))) {
features.webp = true;
}
console.log('๐ CDN Features Detected:', features);
}
CDN Cost/Benefit Analysis
Bandwidth Savings
// Calculate CDN bandwidth savings
function calculateCDNSavings() {
const resources = performance.getEntriesByType('resource');
let cached = 0;
let total = 0;
resources.forEach(resource => {
total += resource.transferSize || 0;
// If served from cache (transferSize is 0 or very small)
if (resource.transferSize < 300) {
cached += resource.decodedBodySize || 0;
}
});
const savedPercentage = (cached / (total + cached) * 100).toFixed(1);
const savedMB = (cached / 1024 / 1024).toFixed(2);
console.log('๐ฐ CDN Bandwidth Savings:');
console.log(`Saved: ${savedMB} MB this page load`);
console.log(`Percentage saved: ${savedPercentage}%`);
// Estimate monthly savings (assuming 1M page views)
const monthlySavingsGB = (cached * 1000000 / 1024 / 1024 / 1024).toFixed(2);
const costSavings = (monthlySavingsGB * 0.09).toFixed(2); // ~$0.09/GB
console.log(`\nEstimated monthly savings:`);
console.log(`Bandwidth: ${monthlySavingsGB} GB`);
console.log(`Cost: $${costSavings}`);
}
CDN Issues and Debugging
1. Cache Invalidation Problems
// Detect stale content
async function checkCacheFreshness() {
const resources = document.querySelectorAll('link[rel="stylesheet"], script[src]');
for (const resource of resources) {
const url = resource.href || resource.src;
if (!url) continue;
const response = await fetch(url, { method: 'HEAD' });
const lastModified = response.headers.get('last-modified');
const etag = response.headers.get('etag');
// Check if URL has version parameter
const hasVersion = url.includes('?v=') || url.includes('?version=');
if (!hasVersion && !etag) {
console.warn(`โ ๏ธ No cache busting for: ${url}`);
console.log(' Consider adding version parameters');
}
}
}
2. Geographic Failures
// Test CDN from different regions (simulation)
async function testCDNRegions() {
// These would need actual geographic testing infrastructure
const regions = [
{ name: 'US-East', endpoint: 'us-east-1' },
{ name: 'EU-West', endpoint: 'eu-west-1' },
{ name: 'Asia-Pacific', endpoint: 'ap-southeast-1' }
];
console.log('๐ CDN Regional Performance:');
// In reality, you'd need distributed testing
// This shows the concept
const currentRegion = await detectCurrentRegion();
console.log(`Your region: ${currentRegion}`);
console.log('(Full geographic testing requires distributed infrastructure)');
}
async function detectCurrentRegion() {
// Check CDN headers for POP location
const response = await fetch(location.href);
const cfRay = response.headers.get('cf-ray');
const xServedBy = response.headers.get('x-served-by');
if (cfRay) {
const pop = cfRay.split('-')[1];
return `Cloudflare POP: ${pop}`;
} else if (xServedBy) {
return `Served by: ${xServedBy}`;
}
return 'Unknown';
}
CDN Optimization Tips
1. Optimal Cache Headers
# Static assets (CSS, JS, images)
Cache-Control: public, max-age=31536000, immutable
# HTML (balance freshness and performance)
Cache-Control: public, max-age=300, s-maxage=3600
# API responses (user-specific)
Cache-Control: private, max-age=0, must-revalidate
# Real-time data
Cache-Control: no-cache, no-store
2. CDN Selection Criteria
const cdnComparison = {
'Cloudflare': {
pros: ['Free tier', 'Easy setup', 'Security features'],
cons: ['Limited free bandwidth', 'Less control'],
bestFor: 'Small to medium sites'
},
'CloudFront': {
pros: ['AWS integration', 'Scalable', 'Many features'],
cons: ['Complex pricing', 'Setup complexity'],
bestFor: 'AWS-based applications'
},
'Fastly': {
pros: ['Real-time purging', 'Edge computing', 'Fast'],
cons: ['Expensive', 'Technical complexity'],
bestFor: 'High-traffic, dynamic sites'
},
'Akamai': {
pros: ['Largest network', 'Enterprise features', 'Reliable'],
cons: ['Very expensive', 'Complex contracts'],
bestFor: 'Enterprise, global reach'
}
};
Quick CDN Audit Script
// Comprehensive CDN audit
(async function cdnAudit() {
console.log('๐ CDN Comprehensive Audit\n');
// 1. Detect CDN
const response = await fetch(location.href);
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
// 2. Identify CDN
let cdnDetected = 'None';
if (headers['cf-ray']) cdnDetected = 'Cloudflare';
else if (headers['x-amz-cf-id']) cdnDetected = 'CloudFront';
else if (headers['x-served-by']?.includes('cache')) cdnDetected = 'Fastly/Varnish';
console.log(`CDN Provider: ${cdnDetected}`);
// 3. Performance metrics
const resources = performance.getEntriesByType('resource');
const cdnResources = resources.filter(r => r.name.includes('cdn') || r.name.includes('static'));
const avgDuration = cdnResources.reduce((sum, r) => sum + r.duration, 0) / cdnResources.length;
console.log(`\nAverage CDN response time: ${avgDuration.toFixed(1)}ms`);
// 4. Cache effectiveness
let cacheHits = 0;
cdnResources.forEach(r => {
if (r.transferSize === 0 || r.transferSize < 300) cacheHits++;
});
const hitRate = (cacheHits / cdnResources.length * 100).toFixed(1);
console.log(`Cache hit rate: ${hitRate}%`);
// 5. Recommendations
console.log('\n๐ก Recommendations:');
if (cdnDetected === 'None') {
console.log('- Consider implementing a CDN for better global performance');
}
if (avgDuration > 200) {
console.log('- CDN response times are high, check configuration');
}
if (hitRate < 80) {
console.log('- Low cache hit rate, review cache headers');
}
})();
The Bottom Line
CDN detection reveals:
- Performance commitment - Using CDN = caring about speed
- Geographic strategy - Global vs regional focus
- Technical maturity - Proper implementation matters
- Cost priorities - CDNs aren't cheap
- Security posture - Many CDNs include WAF
A well-configured CDN can improve performance by 50-80%. A poorly configured one is just expensive.
Detect CDN usage instantly: Fusebox identifies CDN providers, cache performance, and configuration while you browse. Understand any site's delivery strategy. $29 one-time purchase.