The Fetch API is a modern JavaScript interface used to make network requests between a web browser and a server. It replaces the older XMLHttpRequest method with a more flexible system for fetching resources. Marketers and SEO practitioners use it to load external data, trigger tracking pixels, and improve page speed by updating content without reloading the page.
Entity Tracking
- Fetch API: A JavaScript interface providing a unified architecture for fetching resources across the web platform.
- Promise: A JavaScript object representing the eventual completion or failure of an asynchronous operation and its resulting value.
- CORS (Cross-Origin Resource Sharing): A protocol that uses HTTP headers to tell browsers whether a specific web application can share resources with another origin.
- Request Object: A functional representation of a resource request, including the URL, method, and headers.
- Response Object: A functional representation of the response returned by a server to a specific fetch request.
- AbortController: A mechanism that allows you to stop one or more web requests as they are in progress.
- ReadableStream: A data structure that allows you to handle response body data chunk by chunk as it arrives from the network.
- fetchLater(): An interface used to request a deferred fetch that is sent after a delay or after the page is closed.
What is Fetch API?
The Fetch API is the standard tool for making asynchronous HTTP requests in modern web browsers. It is available in both the global Window and Worker contexts, making it accessible for standard scripts and background tasks.
Unlike previous technologies, Fetch is built on JavaScript Promises. When you call the fetch() method, it returns a Promise that eventually resolves into a Response object. This happens as soon as the server responds with headers, which means the Promise stays fulfilled even if the server responds with an HTTP error status like 404 or 500.
Why Fetch API matters
- Simpler Data Integration: It uses a cleaner syntax than older methods, allowing SEO tools to pull in third-party metrics or API data with less code.
- Improved User Experience: By loading data in the background, pages remain interactive, reducing bounce rates and improving Core Web Vitals.
- Better Browser Compatibility: Core features became fully supported in all modern browsers in June 2017.
- Efficient Tracking: The
keepaliveflag allows requests to continue even if the user navigates away from the page, which is essential for accurate conversion and click tracking. - Memory Efficiency: Because it supports streaming, the browser does not have to buffer an entire file in memory before processing it.
How Fetch API works
To fetch a resource, you call the fetch() method with the URL of the resource you need. The process generally follows these steps:
- Initiate Request: Call
fetch('URL'). - Receive Headers: The browser receives response headers from the server and resolves the Promise.
- Check Status: You must manually check the
response.okproperty (which is true for status codes 200–299) to ensure the request succeeded. - Extract Body: Use methods like
response.json(),response.text(), orresponse.blob()to turn the raw data into a usable format. - Handle Errors: Use a
.catch()block ortry...catchfor network failures, such as a lost internet connection.
Requests can be configured using an optional second argument to set methods (POST, GET, etc.), headers, and the request body.
Best practices
- Validate the Response: Always check
if (!response.ok)before processing data. This prevents your script from trying to parse a 404 error page as JSON. - Set Content-Type: When sending data to a server (POST or PUT), use headers to tell the server what format you are using, such as
application/json. - Implement Timeouts: Use
AbortControllerto cancel requests that take too long. This prevents slow third-party APIs from hanging your page's scripts. - Clone the Response: Remember that response bodies are streams. If you need to read a response twice (for example, to log it and also display it), you must use the
.clone()method. - Manage Quotas: If using the newer
fetchLater()for analytics, remember that the deferred-fetch quota is 640 kibibytes per tab.
Common mistakes
- Mistake: Assuming a resolved Promise means a successful request. Fix: Check
response.okor the specific numericalresponse.statuscode. - Mistake: Including a body in a
GETrequest. Fix: Append data to the URL as a query string instead. - Mistake: Reading a body twice without cloning. Fix: Use
response.clone()if you need to access the data multiple times, as bodies are "disturbed" after one read. - Mistake: Exceeding keepalive limits. Fix: Keep your payload under 64 kibibytes for keepalive requests.
- Mistake: Misconfiguring CORS. Fix: Ensure the server provides the
Access-Control-Allow-Originheader when making cross-origin requests.
Examples
Basic JSON Fetch
This scenario shows how to retrieve data from an API and log it to the console.
async function getMetrics() {
try {
const response = await fetch("https://api.example.com/seo-data");
if (!response.ok) throw new Error("Status: " + response.status);
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Network error:", error);
}
}
POSTing Form Data
This scenario demonstrates sending data to a server, common for tracking conversions or form submissions.
const response = await fetch("https://example.org/post", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ lead_id: "12345" })
});
Fetch API vs XMLHttpRequest
| Feature | Fetch API | XMLHttpRequest |
|---|---|---|
| Syntax | Simple, Promise-based | Complex, event-based |
| Streaming | Supports streaming bodies | Limited support |
| Service Workers | Fully compatible | Not compatible |
| Error Handling | Better, but status check is manual | Difficult to manage callbacks |
| Defaults | Does not send cookies cross-origin | Does not send cookies cross-origin |
FAQ
Does Fetch API automatically reject 404 errors?
No. The Promise returned by fetch() only rejects if there is a network failure or if the request is blocked (e.g., by a browser's security policy). Success and failure codes from the server, like 404 (Not Found) or 500 (Internal Server Error), still resolve the Promise. You must check the response.ok property in your code to handle these cases.
Can I use Fetch API to track users who leave my site?
Yes. By setting the keepalive property to true in the fetch options, you can ensure a request finishes even if the user closes the tab or navigates away. This is very useful for marketing analytics. However, keepalive requests are limited to a 64 kibibyte payload.
How does Fetch handle cookies?
By default, Fetch only sends and receives cookies for same-origin requests. If you need to include cookies in a cross-origin request, you must set the credentials option to include. Note that the server must also agree to this by returning the Access-Control-Allow-Credentials: true header.
Why am I getting an "opaque" response?
This usually happens when you make a cross-origin request with the mode set to no-cors. In this mode, the browser restricts access to the response headers and body to protect security. You will see a status of 0 and cannot read the content. To fix this, the server you are request must support CORS.
Is it possible to cancel a fetch request once it has started?
Yes. You can use an AbortController. You pass the controller's signal to the fetch request. If you call controller.abort(), the fetch Promise will reject with an AbortError.
What is fetchLater()?
The fetchLater() API is a newer method used to request a deferred fetch. The request is sent by the browser at a later time, such as when the page is closed or after a specific period. It is specifically designed to help with reporting and analytics without needing to worry about the exact timing of the page closure.