Fetchstart

Understanding the Resource Timing API's Key Timestamp for Performance Measurement

Modern web performance measurement relies heavily on the browser's built-in timing APIs. Among these, the fetchStart property stands as a crucial timestamp that marks the moment when the browser is ready to begin fetching a resource. Understanding this property and its place within the Resource Timing API enables developers to measure and optimize their web applications' loading performance with precision and confidence.

The Resource Timing API provides detailed timing information about network requests made by the browser. This API exposes a wealth of data that developers can use to understand exactly how long each phase of resource loading takes, from initial cache checking through DNS resolution, connection establishment, and finally to response delivery. For teams focusing on SEO performance optimization, these metrics directly impact search rankings and user experience scores.

Key Characteristics of fetchStart

High-Precision Timestamp

Returns a DOMHighResTimeStamp measured in milliseconds, providing sub-millisecond accuracy for precise performance measurements.

Cross-Origin Availability

Unlike many other timing properties, fetchStart is available for cross-origin requests without requiring the Timing-Allow-Origin header.

Cache Check Completion

Represents the moment immediately after cache checking, when the browser is ready to begin fetching the resource.

Redirect Handling

For redirected resources, fetchStart marks the time before fetching the final resource, not intermediate redirects.

The Resource Timing API in Context

The Resource Timing API is part of the broader Performance API that browsers provide for measuring web performance. This API collects detailed timing data for every network request made by a page, including images, scripts, stylesheets, fonts, and other resources.

When a browser loads a web page, it makes numerous network requests to fetch the resources needed to render that page. Each of these requests goes through several distinct phases: cache checking, DNS resolution, TCP connection establishment, TLS negotiation (for HTTPS requests), request sending, response waiting, and response receiving.

Accessing this timing data is straightforward. Developers can retrieve resource timing entries using performance.getEntriesByType("resource"), which returns an array of PerformanceResourceTiming objects for all resources loaded by the page.

Timing Properties Overview

PropertyDescription
fetchStartMoment browser starts fetching the resource
domainLookupStartDNS resolution begins
connectStartTCP connection establishment begins
secureConnectionStartTLS negotiation begins
requestStartHTTP request is sent
responseStartFirst byte of response received
responseEndLast byte of response received

Understanding these timing phases is essential for comprehensive performance auditing and identifying bottlenecks in resource loading.

Practical Code Examples

Implementing fetchStart in performance measurement requires understanding how to access the Performance API and calculate durations from the timing data.

Basic fetchStart Usage
1// Get all resource timing entries2const resources = performance.getEntriesByType("resource");3 4// Calculate fetch time for each resource5resources.forEach(resource => {6 const fetchTime = resource.responseEnd - resource.fetchStart;7 console.log(`${resource.name}: fetch time = ${fetchTime.toFixed(2)}ms`);8});
Using PerformanceObserver
1// Create a PerformanceObserver to watch for new resource entries2const observer = new PerformanceObserver((list) => {3 list.getEntries().forEach(entry => {4 const fetchTime = entry.responseEnd - entry.fetchStart;5 console.log(`New resource: ${entry.name}`);6 console.log(`Fetch time: ${fetchTime.toFixed(2)}ms`);7 8 // Example: Log slow resources for investigation9 if (fetchTime > 1000) {10 console.warn(`Slow resource detected: ${entry.name}`);11 }12 });13});14 15// Start observing resource timing entries16observer.observe({ type: "resource", buffered: true });
Sending Performance Data to Analytics
1// Send performance data reliably, even on page unload2function sendPerformanceData(data) {3 const payload = JSON.stringify(data);4 5 if (navigator.sendBeacon) {6 // Use sendBeacon for reliable delivery7 navigator.sendBeacon("/analytics/performance", payload);8 } else {9 // Fallback to fetch with keepalive10 fetch("/analytics/performance", {11 method: "POST",12 body: payload,13 keepalive: true14 });15 }16}

Best Practices for Performance Measurement

Using fetchStart effectively in performance measurement requires following established best practices that ensure accurate data collection and meaningful insights.

Use PerformanceObserver

Rather than polling performance.getEntriesByType(), use PerformanceObserver for efficient, event-driven monitoring:

// Recommended: Use PerformanceObserver for production monitoring
const performanceObserver = new PerformanceObserver((list) => {
 const entries = list.getEntries();
 // Process entries efficiently
 processEntries(entries);
});

performanceObserver.observe({ type: "resource", buffered: true });

Handle Edge Cases

Always validate timing data before calculations, as some properties may be zero or undefined:

// Safely calculate fetch time with validation
function calculateFetchTime(entry) {
 if (!entry.fetchStart || !entry.responseEnd) {
 return null; // Timing data not available
 }

 const fetchTime = entry.responseEnd - entry.fetchStart;

 if (fetchTime < 0) {
 return null; // Invalid timing (clock sync issue)
 }

 return fetchTime;
}

Batch Analytics Data

Reduce network overhead by batching performance data before sending to analytics:

const batch = [];
const observer = new PerformanceObserver((list) => {
 batch.push(...list.getEntries());

 // Send batch when it reaches a threshold
 if (batch.length >= 10) {
 sendToAnalytics(batch);
 batch.length = 0; // Clear the batch
 }
});

observer.observe({ type: "resource", buffered: true });

Implementing these performance measurement best practices as part of your development workflow helps identify issues before they impact users.

Common Use Cases and Performance Insights

The fetchStart property enables various performance analysis scenarios that help developers optimize their web applications.

Third-Party Resource Monitoring

Identify slow third-party resources that may be affecting page performance:

// Identify slow third-party resources
const thirdPartyResources = performance.getEntriesByType("resource")
 .filter(entry => !entry.name.includes(window.location.hostname));

thirdPartyResources.forEach(entry => {
 const fetchTime = entry.responseEnd - entry.fetchStart;
 if (fetchTime > 500) {
 console.warn(`Slow third-party resource: ${entry.name} (${fetchTime.toFixed(0)}ms)`);
 }
});

Cache Hit Analysis

Understand how effectively caching strategies are working:

const resources = performance.getEntriesByType("resource");
let cacheHits = 0;

resources.forEach(entry => {
 if (entry.transferSize === 0) {
 cacheHits++;
 }
});

const cacheHitRatio = (cacheHits / resources.length) * 100;
console.log(`Cache hit ratio: ${cacheHitRatio.toFixed(1)}%`);

Monitoring these metrics helps improve Core Web Vitals and provides actionable insights for performance optimization.

Performance Optimization Strategies

Understanding fetchStart timing helps identify optimization opportunities across several areas.

DNS and Connection Optimization

Use browser hints to perform DNS resolution and connection establishment in advance:

<!-- Preconnect to known third-party domains -->
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">

Resource Prioritization

Ensure critical resources load first by controlling fetch priority:

<!-- Prioritize above-the-fold image -->
<img src="hero.jpg" fetchpriority="high" alt="Hero image">

<!-- Defer below-the-fold images -->
<img src="secondary.jpg" loading="lazy" alt="Secondary image">

Key Optimization Areas

  • DNS Optimization: Use dns-prefetch and preconnect hints
  • Connection Reuse: Leverage HTTP/2 multiplexing
  • Response Size: Compress and optimize assets
  • Caching: Implement effective cache headers and service workers
  • Prioritization: Use fetchpriority and loading attributes appropriately

By applying these strategies alongside comprehensive performance monitoring, development teams can significantly improve page load times and user experience.

Frequently Asked Questions

What is the difference between fetchStart and requestStart?

fetchStart marks when the browser is ready to begin fetching (after cache checking), while requestStart marks when the actual HTTP request is sent. The difference between these timestamps represents DNS resolution, connection establishment, and any redirect following time.

Why is fetchStart available for cross-origin requests?

Unlike other timing properties that require Timing-Allow-Origin headers, fetchStart is intentionally exposed for cross-origin requests because it reveals minimal sensitive information while providing valuable performance insights for third-party resource monitoring.

How do I calculate total fetch time?

Subtract fetchStart from responseEnd: `const fetchTime = entry.responseEnd - entry.fetchStart;`. This gives you the total time from when the browser was ready to fetch until the response was fully received.

What does it mean when fetchStart equals responseEnd?

This indicates the resource was served from cache with near-zero latency. The browser checked the cache, found a valid copy, and served it without making a network request.

Ready to Optimize Your Web Performance?

Our team specializes in building high-performance web applications using modern frameworks and best practices.