Connection Quality Detection | Blue Frog Docs

Connection Quality Detection

Implement adaptive experiences based on network connection quality

Connection Quality Detection

What This Means

Connection quality detection allows your site to adapt to users' network conditions. Without it:

  • Mobile users download unnecessary large assets
  • Slow connections timeout on heavy resources
  • Users on data-saver mode waste bandwidth
  • Poor experience on unreliable networks

How to Diagnose

Network Information API

// Check for Network Information API support
const connection = navigator.connection ||
                   navigator.mozConnection ||
                   navigator.webkitConnection;

if (connection) {
  console.log({
    effectiveType: connection.effectiveType,  // '4g', '3g', '2g', 'slow-2g'
    downlink: connection.downlink,            // Mbps
    rtt: connection.rtt,                      // Round trip time in ms
    saveData: connection.saveData,            // Data saver enabled
    type: connection.type                     // 'wifi', 'cellular', etc.
  });
}

Connection Types

effectiveType Typical Use Case
4g Full experience, high-res images
3g Standard experience, optimized images
2g Minimal experience, critical content only
slow-2g Text-only or offline mode

General Fixes

Adaptive Image Loading

// Load different image sizes based on connection
function getOptimizedImageUrl(baseUrl) {
  const connection = navigator.connection;

  if (!connection) {
    return `${baseUrl}?quality=80`;
  }

  if (connection.saveData) {
    return `${baseUrl}?quality=30&width=400`;
  }

  switch (connection.effectiveType) {
    case 'slow-2g':
    case '2g':
      return `${baseUrl}?quality=30&width=400`;
    case '3g':
      return `${baseUrl}?quality=60&width=800`;
    default:
      return `${baseUrl}?quality=80&width=1200`;
  }
}

// Usage
const imgUrl = getOptimizedImageUrl('/api/images/hero.jpg');

Conditional Feature Loading

// Load heavy features only on good connections
async function loadEnhancedFeatures() {
  const connection = navigator.connection;

  // Skip on slow connections or data saver
  if (connection?.saveData ||
      ['slow-2g', '2g'].includes(connection?.effectiveType)) {
    console.log('Skipping enhanced features due to slow connection');
    return;
  }

  // Load video backgrounds, animations, etc.
  await import('./enhanced-features.js');
}

// React with connection hook
function useConnectionQuality() {
  const [quality, setQuality] = useState('unknown');

  useEffect(() => {
    const connection = navigator.connection;
    if (!connection) {
      setQuality('unknown');
      return;
    }

    const updateQuality = () => {
      setQuality(connection.effectiveType);
    };

    updateQuality();
    connection.addEventListener('change', updateQuality);

    return () => {
      connection.removeEventListener('change', updateQuality);
    };
  }, []);

  return quality;
}

Preload Strategy Based on Connection

// Aggressive preloading on fast connections only
function setupPreloading() {
  const connection = navigator.connection;

  if (!connection || connection.effectiveType !== '4g' || connection.saveData) {
    return; // Don't preload on slow or metered connections
  }

  // Preload likely next pages
  const linksToPreload = document.querySelectorAll('a[data-preload]');
  linksToPreload.forEach(link => {
    const prefetch = document.createElement('link');
    prefetch.rel = 'prefetch';
    prefetch.href = link.href;
    document.head.appendChild(prefetch);
  });
}

Connection Change Handler

// React to connection changes
function setupConnectionMonitoring() {
  const connection = navigator.connection;
  if (!connection) return;

  connection.addEventListener('change', () => {
    console.log('Connection changed:', {
      type: connection.effectiveType,
      downlink: connection.downlink,
      rtt: connection.rtt
    });

    // Adjust behavior
    if (connection.effectiveType === 'slow-2g') {
      pauseVideoPlayback();
      reduceImageQuality();
    }

    // Show indicator to user
    if (connection.effectiveType === '2g' || connection.effectiveType === 'slow-2g') {
      showSlowConnectionBanner();
    }
  });
}

CSS-Based Adaptation

/* Use low-quality images by default (save-data) */
.hero-image {
  background-image: url('/images/hero-low.jpg');
}

/* Upgrade on fast connections via JS */
.hero-image.high-quality {
  background-image: url('/images/hero-high.jpg');
}

/* Reduce animations on slow connections */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
// Apply high-quality class based on connection
if (navigator.connection?.effectiveType === '4g' && !navigator.connection?.saveData) {
  document.querySelectorAll('.hero-image').forEach(el => {
    el.classList.add('high-quality');
  });
}

Offline Detection

// Handle offline state
function setupOfflineDetection() {
  window.addEventListener('online', () => {
    console.log('Back online');
    retryFailedRequests();
    hideOfflineBanner();
  });

  window.addEventListener('offline', () => {
    console.log('Gone offline');
    showOfflineBanner();
    queueRequestsForLater();
  });

  // Initial check
  if (!navigator.onLine) {
    showOfflineBanner();
  }
}

Browser Support

Feature Chrome Firefox Safari Edge
Network Information API Yes Limited No Yes
navigator.onLine Yes Yes Yes Yes
connection.saveData Yes No No Yes

Fallback strategy:

function getConnectionQuality() {
  const connection = navigator.connection;

  // Use Network Information API if available
  if (connection?.effectiveType) {
    return connection.effectiveType;
  }

  // Fallback: measure actual download speed
  return measureConnectionSpeed();
}

async function measureConnectionSpeed() {
  const startTime = performance.now();
  const response = await fetch('/speed-test.bin'); // ~100KB file
  const blob = await response.blob();
  const duration = performance.now() - startTime;
  const speedMbps = (blob.size * 8) / (duration * 1000);

  if (speedMbps > 5) return '4g';
  if (speedMbps > 1) return '3g';
  if (speedMbps > 0.1) return '2g';
  return 'slow-2g';
}

Verification

  1. Test with DevTools Network throttling
  2. Verify different assets load per connection
  3. Check saveData flag is respected
  4. Monitor connection change events

Further Reading

// SYS.FOOTER