SEO check

How to Reduce HTTP Requests on Your Website

Count the files your page loads, cut the ones you do not need, and see how our free report scores the result.

Free to use 18 min read Updated Oct 2026

Reduce HTTP requests in one minute

Quick answer: An HTTP request is your browser asking a server for one file, so to reduce HTTP requests you make the page ask for fewer files. You remove what you don't use, merge or inline small files, and delay anything the first screen doesn't need. Our report counts the elements in your finished HTML that point to a file, and it passes the check at 50 or fewer.

  • Pass: 50 or fewer counted elements, and the report shows no How to Fix button.
  • Fail: 51 to 100 counted elements is a warning and more than 100 is failed, and both states show the red How to Fix button.
  • Fix: Start with the plugins, tags and images you no longer use, because deleting a file is the one change with no trade off.

Check my site free

To minimize HTTP requests without breaking anything, work in this order: remove first, then merge and replace, then delay, then cache, and stop as soon as the page feels fast. The count is a clue, not the goal. Our report reads the finished HTML instead of watching live network traffic, so the number can differ from your browser's.

What are HTTP requests and which ones add up?

Every page view starts with one HTTP request for the HTML document. The browser reads that document from top to bottom, and each time it meets a reference to a stylesheet, script, image, font, frame or media file, it sends another request for it. The protocol's rules live in RFC 9110, but you don't need the RFC to see the effect. A web page is really a list of files, and the list is nearly always longer than the owner expects. Your HTTP request count is simply the length of that list, and it is the requests per page figure that speed reports quote.

The extra requests rarely come from the content you wrote yourself. Theme and plugin files add stylesheets and scripts. A row of social icons arrives as a dozen small images. Web fonts add one file per weight and style, an embedded video or map pulls in a whole frame with files of its own, and a chat widget often loads a second and third file once the first one runs. Analytics and a tag manager are the classic case, since one line in your head section can bring in several more files from other hosts.

Add them up: one HTML file, 6 stylesheets, 12 scripts, 30 images, 4 fonts and 8 third-party files come to 61 requests, and none of those numbers is unusual. The Web Almanac request statistics from the HTTP Archive put the median page at 71 requests on desktop and 66 on mobile, according to the 2024 edition. An ordinary page therefore already lands in our warning range of 51 to 100, which is common and doesn't mean your site is broken. Those figures are network requests, while our report counts elements, so the two are close but not identical.

Request count versus page weight

Count is how many files a page loads, and weight is how many bytes they add up to. One 3 MB hero image is a single request, yet it can slow a page far more than twenty tiny icons. The two problems often travel together, but the fixes differ: you remove or merge files to cut the count, and you compress or resize them to cut the bytes. If your real problem is bytes, read our page size guide first.

How SEO Site Checker counts HTTP requests

The HTTP Requests row sits in the speed group of the report. To fill it, our crawler opens your page in headless Chromium, waits for the load event (it stops waiting after 20 seconds) and reads the finished HTML. Then it counts elements, which is a different thing from counting network traffic.

Our rule: The report adds up every img src, audio src, video src, script src, link href, iframe src, source src, embed src and object data in the finished HTML. A total of 50 or fewer passes, 51 to 100 is a warning, and more than 100 is failed.

This row is a different measurement from the DOM size check. That check counts every element in the document, while this row counts only the ones that point to a file.

What the report counts

The nine tag and attribute pairs above are grouped by tag name, so the result tells you how many of the counted elements are images, scripts, link tags and so on. Signed in users can open the grouped URL list in the report, which is the quickest way to see which group is heaviest. Counting is literal: an img with a src and loading="lazy" is counted, and so is a data: URI image, while an img that holds its address only in data-src is not.

Every link tag with an href counts, not just stylesheets. Canonical, icon, preconnect, preload and alternate links all add to the total, even though several of them, such as canonical and alternate, never download anything. Some things are left out on purpose:

  • The HTML document itself. The request for the page is not an element inside the page, so it never enters the total.
  • Files that CSS pulls in. Background images and web fonts declared in a stylesheet are invisible to the count.
  • Srcset candidates. Only the src attribute is read, so alternate images listed in srcset, or in a source tag that has no src, are not added.
  • Late additions. Fetch and XHR calls, and anything a script inserts after the load event, never reach the finished HTML the report reads.

Pass, warning and failed

The passed state shows its own message and no How to Fix button, so there is nothing to click when you are under the line. The warning and failed states are handled alike: both show the same too many requests message and the same red How to Fix button. If the on-screen text quotes a different recommended maximum, the thresholds on this page (50 and 100) are the ones that decide the status. A pass only says the page points to 50 or fewer files. It does not measure load time, the protocol, or whether those files block rendering.

These lines are ours, not Google's, and the pass line is stricter than the Web Almanac median, so plenty of healthy sites land in the warning band.

Why your browser number can differ

The biggest cause is noscript. Our parser reads the contents of a noscript block as real tags and counts them, while a normal browser with JavaScript on never fetches them. On one WordPress test page the report counted 83 elements, the browser console selector counted 64, and all 19 of the difference sat inside noscript blocks.

Timing matters too. The report reads the HTML as it stands once the load event has fired, so an image that a script adds two seconds later, or only when a visitor scrolls, can appear in your Network panel without ever being in the HTML the report reads.

For a quick cross-check, run the console selector from the counting section and compare totals. A warm cache changes timing and transferred size, but not the number of requests.

Check my website

Why do HTTP requests slow a page down?

A request is not just a download. For a file on a host the browser hasn't used yet, it first does a DNS lookup to find the server, then, on HTTP/1.1 and HTTP/2, opens a TCP connection (the TCP handshake) and completes a TLS handshake to secure it. Only then does it send the request, wait for the first byte of the answer, which tools report as time to first byte, and download the rest. That connection overhead is paid per host, not per page. Each of those steps usually costs a round trip, and latency on a phone connection makes round trip time expensive. HTTP/3 merges the transport and TLS handshakes, and a cached DNS answer skips the lookup.

That is why the first file from each new host costs the most. Later files from the same host can reuse the open connection, which is what keep-alive is for.

Under HTTP/1.1 a browser opens about six parallel connections per host, and each connection handles one request at a time. Anything beyond six waits in a queue, a problem known as head of line blocking. This is where the old advice to make fewer requests came from, and for that protocol it was sound.

The render path matters more than the raw count. Stylesheets and synchronous scripts in the head hold back the first paint, so three blocking files can hurt more than forty images that load after the page is already visible. The visible result is a later First Contentful Paint and Largest Contentful Paint, and one slow third party file can stall everything queued behind it. Our render blocking resources page covers which files do that and how to spot them.

Be careful with the SEO claim. Google has not named request count as a ranking signal. What it does measure is how the page feels to a visitor, through Core Web Vitals, and requests are one cause of a poor score among several. The page speed and SEO guide explains that link between speed and search in more detail.

HTTP/1.1, HTTP/2 and HTTP/3: do fewer requests still matter?

Yes, but less than they used to, and the advice you follow should depend on the protocol your server speaks. The table compares the three versions in terms that affect a site owner's decisions.

ProtocolHow requests travelEffect of many small filesWhat to do
HTTP/1.1One request at a time on each connection, with about six connections per hostFiles queue up, so every extra file can delay the ones behind itCombining and inlining small files still pays off
HTTP/2 (RFC 9113)Many requests share one connection (multiplexing), with header compressionSmall files cost far less, though each request keeps some overheadRemove files you don't need, and don't force everything into one bundle
HTTP/3 (RFC 9114)The HTTP/2 model carried over QUIC, which runs on UDPSimilar to HTTP/2, with better recovery when a packet is lostSame advice as HTTP/2, with the biggest gains on weak mobile networks

On HTTP/2 the browser no longer waits in line, but it hasn't made requests free. Every request still carries headers and server work, a file from a new host still needs its own DNS lookup and handshakes, and a blocking stylesheet still delays the first paint. HTTP/3 keeps the same model but removes the TCP stall: on HTTP/2 a single lost packet can pause every stream on the connection, and QUIC confines the delay to the stream that lost it.

The takeaway is simple. Removing requests you don't need helps on every protocol. Merging all your code into one giant bundle mostly helps on HTTP/1.1, and on newer protocols it can hurt, because a single edit invalidates the whole cached file. To see which protocol a site uses, open the Network panel, right-click the column headers, switch on Protocol and look for h2 or h3. If you see http/1.1 on your own site, follow the how to enable HTTP/2 guide for Apache and Nginx.

How to count the HTTP requests your page makes

Take a baseline before you change anything, or you will never know which step helped. You need two numbers, the total your browser reports and the total in our report, from the same URL.

  1. Open a clean window. Use a private or incognito window so browser extensions don't inject their own requests, and sign out of the site so you see what a visitor sees.
  2. Open the Network panel. Press F12 or Ctrl+Shift+I in Chrome, choose Network, and tick Disable cache so timing and transferred size match a first visit.
  3. Reload and scroll. Reload the page, note the total, then scroll all the way down so lazy loaded images and embeds start to download. Anything a script adds when you scroll is not in the finished HTML the report reads, so keep both the before and the after number.
  4. Read the count. The status bar at the bottom shows the number of requests. Filter by type (JS, CSS, Img, Font, Doc) to see which kind dominates, and sort by the Domain column to spot third parties (right-click the column headers to switch on Domain and Protocol).
  5. Read the request waterfall. Look for long chains where one file triggers the next, and for many different domains.
  6. Mirror the report in the console. Paste the one line below into the Console tab and press Enter. It counts the same nine tag and attribute pairs as our report.
  7. Run the report. Run your URL through our free SEO report and open the HTTP Requests row. If you are signed in, the grouped list shows which tags account for the total.
JavaScript
document.querySelectorAll('img[src], audio[src], video[src], script[src], link[href], iframe[src], source[src], embed[src], object[data]').length

The console number is often a little lower than the report because of noscript content, and it can be higher if scripts added elements after the load event. Write both totals down with the date, then change one thing and measure again the same way.

How to reduce HTTP requests step by step

The order matters. Removing a request is free, merging has trade offs, and delaying changes how the page behaves, so to make fewer HTTP requests you work from the safest change to the riskiest: remove first, then merge and replace, then delay, then cache, trimming third-party tags and limiting fonts along the way. Change one thing at a time and re-count after each step, which tells you what actually moved the number.

Remove files you do not use

This step usually gives the largest return for the least risk. Look for unused plugins and theme add-ons, duplicate libraries (two copies of jQuery is a common find), old widgets, images that no longer appear and tags left behind by a tool you cancelled years ago. Filter the Network panel by JS and CSS and ask of each file what it is for. If nobody can answer, switch it off and see whether anything breaks. Link tags are counted too, so drop preconnect hints and icons for hosts you no longer use: a leftover preconnect costs a count and opens a connection nobody uses. Never remove canonical, alternate or hreflang links just to lower the count, because they matter for SEO.

Combine and inline small CSS and JavaScript

Aim for one stylesheet and one script per page where that makes sense, both minified. Our JavaScript minifier and CSS minifier shrink the code before you merge it. Keep defer on scripts after combining, so one larger file doesn't block the first paint.

Inline only a few kilobytes of critical CSS in the head, and load the rest later. The pattern below inlines the rules for the top of the page and loads the full stylesheet without blocking it. The noscript line keeps the page styled when scripts are off.

HTML
<head>
  <style>
    /* critical rules for the first screen only */
    body { margin: 0; font-family: system-ui, sans-serif; }
    .hero { min-height: 60vh; }
  </style>
  <link rel="stylesheet" href="/css/site.min.css" media="print" onload="this.media='all'">
  <noscript><link rel="stylesheet" href="/css/site.min.css"></noscript>
</head>

This critical plus deferred pattern improves the first paint, but it is count-neutral, or one higher with the noscript fallback, because the full stylesheet link stays and the fallback adds a second link tag. Inlining a whole small stylesheet does remove a link element, but only a few kilobytes are worth inlining, because the inlined rules can't be cached separately. A strict Content Security Policy blocks the inline onload handler, so use a plain link tag there. Our inline CSS guide covers when it helps and when it hurts.

Replace small images with inline SVG or a sprite

Icons are the classic request wasters. A set of twenty social and feature icons can easily be twenty separate image files. Draw them as inline SVG instead, so they ship inside the HTML and cost no request at all. Icon fonts also cut the count to one file, but they load every glyph and need accessibility care, so inline SVG is the better default.

HTML
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
  <circle cx="10" cy="10" r="6" fill="none" stroke="currentColor" stroke-width="2"/>
  <path d="M15 15l6 6" stroke="currentColor" stroke-width="2"/>
</svg>

If you already have a sprite, or you must support a design built around one, MDN's guide to image sprites in CSS shows how to combine many small images into one file and reveal each part with background-position. Avoid base64 data URIs for anything but tiny files. They remove the request in the browser, but the report still counts a data: URI as an element, and the encoded text bloats your HTML.

Lazy load below the fold and load embeds on click

Add loading="lazy" to images and iframes that sit below the first screen, and never to the main image at the top, because that delays Largest Contentful Paint. Lazy loading postpones the download, but the element is still in your HTML with a src, so our report still counts it. The first load is faster in practice even though the HTML count stays the same.

Click to play placeholders are different, and they are worth setting up for video, map and chat embeds. Show a poster and a button, and write the real iframe src only after the visitor clicks. The Intersection Observer API can do the same on scroll. In the report this saves one counted element per iframe, and only if the poster is a CSS background on the button rather than an img with a src. The big win, often many more files than the iframe itself, shows up in the Network panel and in real load time, not in the HTTP Requests row.

Trim third-party tags

Third-party tags deserve their own audit. In the Network panel, sort by Domain and list every external host your page talks to. Google Tag Manager, analytics, tracking pixels, social share buttons, chat widgets and ad scripts all show up, and one tag often triggers requests to several more domains. Remove the ones with no clear job.

For those you keep, load chat, maps and social widgets only after a click or scroll, and run the rest as async scripts or with defer so they don't block the page. The web.dev article on loading third-party scripts efficiently walks through async, defer, resource hints and self hosting.

Limit web fonts

Every weight and style of a web font is a separate file, and Google Fonts can quietly add a stylesheet plus several font files on top. Stay with two families and a few weights at most, serve WOFF2, and set font-display: swap so text shows while the font loads. A system font stack costs no request at all and suits body text on most sites. Font files requested from CSS do not appear in the report, so only the Google Fonts stylesheet link and any preload links count.

Cache and serve through a CDN

Give versioned files a long Cache-Control lifetime and put a CDN in front of them. This doesn't lower the count in our report, because the page still points at the same files. What it removes is network time on repeat visits and distance for far-away visitors. Our CDN usage test guide explains how the report checks for a CDN.

Reduce HTTP requests in WordPress, Shopify, Wix and plain HTML

The principles are the same everywhere, but the levers differ: a hosted builder gives you little control, so the work there is mostly removal.

WordPress

Deactivate plugins one at a time and re-count after each, since a plugin you forgot about can add several stylesheets and scripts to every page. Use a script manager, or the settings of a free optimization plugin, so contact form, slider and map files load only on the pages that use them. Where a plugin loads files everywhere, dequeue its scripts and styles on the pages that don't need them. Free optimization plugins offer merge and delay options, which are worth testing on a staging copy first.

Then switch off what WordPress adds by default and many sites never use. Two of those are real files that the report counts: the block library stylesheet (handle wp-block-library), which a classic theme may need only on pages built with blocks, and the embed script (wp-embed.min.js), which only matters if you embed posts from other WordPress sites. WordPress has been moving block styles to on-demand loading, so check in the Network panel whether wp-block-library still loads as a separate file before you remove it. Paste the snippet below into your child theme's functions.php file after the opening PHP tag, or into a small plugin of your own.

PHP
<?php
add_action('wp_enqueue_scripts', function () {
    // Classic themes only: keep the block styles on posts that use blocks.
    if (!is_singular() || !has_blocks()) {
        wp_dequeue_style('wp-block-library');
        wp_dequeue_style('wp-block-library-theme');
    }
    // Deregister the embed script so it is not printed.
    wp_deregister_script('wp-embed');
}, 100);

Test after each line, since a block theme or a page that embeds another post can lose styling. Archive pages and the blog home page fail the singular test, so check them too, because excerpts with blocks and block widgets in your sidebar or footer can lose their styling there. Many older tutorials remove the emoji code, but on current WordPress that code is printed inline, so removing it does not change the counted total.

Shopify

Apps are the usual culprit. Uninstalling an app often leaves its code in your theme files, so open the theme editor and delete the snippets and script tags it left behind, and also switch off unused app embeds in the theme editor, since many current apps load their files from there. A typical find is a script tag in theme.liquid that still loads a file from an app you removed months ago. Keep the number of fonts and homepage sections down, since each section can bring its own stylesheet and script. Finally, check which lazy loading the theme already applies before you add anything of your own.

Wix and Squarespace

Control is limited on these builders, and you can't dequeue the platform's own files, so the realistic target is the warning band rather than a perfect score. On Wix, open the app list in your dashboard and remove apps you no longer use, then check the site's custom code and tracking settings for snippets left behind by tools you dropped. On Squarespace, look at the Code Injection settings (header and footer) for forgotten tracking snippets, and delete unused third party blocks and embeds from your pages. After that, cut animations and extra fonts, and keep custom code minimal.

Plain HTML on Apache or Nginx

Bundle your files with the build tool you already use, turn on HTTP/2, and set Cache-Control headers for versioned assets. The HTTP/2 setup guide walks through the server configuration for both Apache HTTP Server and Nginx.

Mistakes that make fewer requests backfire

Much of the advice online dates from the HTTP/1.1 era, and applying it blindly can leave you with a lower count and a slower site.

Warning: On HTTP/2 and HTTP/3, one huge bundle means one small edit invalidates the entire cached file, so every returning visitor downloads all of it again.

  • Inlining too much. Large inlined files or base64 images make the HTML heavier, the inlined parts can't be cached on their own, and the report still counts data URIs.
  • Lazy loading the hero. Anything on the first screen should load right away, otherwise Largest Contentful Paint gets worse.
  • Counting only images. Link tags, fonts and third-party tags add up just as fast and are easier to overlook.
  • Deleting without checking. Consent banners, order tracking and ad scripts all look removable until a sale goes unrecorded. Find out what a tag does before it goes.
  • Testing once. Measure in a private window, logged out, more than once, because a logged in session with a warm cache shows a different list from the one a visitor and the report see.
  • Chasing the number. A page with a few render blocking files can feel slower than a page with more files that are all deferred.

A quick checklist to get to 50 requests or fewer

Work through this list from top to bottom. The notes inside the items say which ones lower the report total and which only speed up real loading.

  • Baseline noted. Write down the report total and the Network panel total, plus the date.
  • Unused items removed. Plugins, apps, tags and images you don't use are gone, which lowers the report total.
  • Code merged. CSS and JavaScript are combined where it helps, minified and deferred, which lowers the report total.
  • Icons inline. Icons are inline SVG or one sprite instead of separate files, which lowers the report total.
  • Embeds on click. Video, map and chat embeds load only after a click, with the poster as a CSS background. Each one removes a counted iframe and speeds up real loading.
  • Fonts limited. Two families and a few weights, in WOFF2, which helps real loading but barely moves the report.
  • Re-tested. Checked in a private window, then run again in the free report.
  • Target met. 50 or fewer counted elements passes, and a simple page often lands well below that.

How to Fix

The short version, the same steps you see when you click How to Fix in your report.

Why this fails: Our report found more than 50 elements in your finished HTML that point to a file, and each one is a separate trip to a server. A total of 51 to 100 is a warning and more than 100 is failed. The count includes every link tag and anything inside noscript, so it can read higher than your browser.

How to fix it:

  1. Open the grouped list in the report (signed in) or the Network panel, and note the starting number.
  2. Remove plugins, apps, tags and images you no longer use.
  3. Merge and minify small CSS and JavaScript files, or inline a tiny stylesheet entirely.
  4. Swap small icon images for inline SVG or one sprite.
  5. Load video, map and chat embeds on click (with a CSS background poster), and lazy load images below the fold.
  6. Keep web fonts to two families.

To compare counts, paste this into the console:

JavaScript
document.querySelectorAll('img[src], audio[src], video[src], script[src], link[href], iframe[src], source[src], embed[src], object[data]').length

This speeds up the first paint but does not lower the report count:

HTML
<style>/* critical rules for the first screen */</style>
<link rel="stylesheet" href="/css/site.min.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/site.min.css"></noscript>

On WordPress (classic themes only), this removes the embed script and block library stylesheet. Paste it into a child theme's functions.php or a small plugin, then check archive pages and widgets:

PHP
<?php
add_action('wp_enqueue_scripts', function () {
    // Classic themes only. Block themes need these styles.
    if (!is_singular() || !has_blocks()) {
        wp_dequeue_style('wp-block-library');
        wp_dequeue_style('wp-block-library-theme');
    }
    wp_deregister_script('wp-embed');
}, 100);
  • WordPress: deactivate plugins one at a time and load scripts only where needed.
  • Shopify: uninstall unused apps and delete the code they left in theme files.
  • Wix and Squarespace: remove unused apps and embeds.
  • Plain HTML: bundle your files and enable HTTP/2.

Re-test: Clear the page and CDN cache, then run our free report again on the same URL and check the HTTP Requests row is lower (50 or fewer passes). Read loading third-party scripts efficiently for more.

Re-test my website

Frequently Asked Questions

How many HTTP requests is too many?
There is no fixed law. Our report passes a page with 50 or fewer counted elements, warns from 51 to 100 and fails above 100, while the Web Almanac 2024 median is 71 requests on desktop. Judge a page by what blocks its first paint and by real load time on a phone, not by the number alone.
Does the number of HTTP requests still matter with HTTP/2?
It matters less than before, because HTTP/2 and HTTP/3 send many requests over one connection instead of queuing them. Each request still has overhead, files from new hosts still need new connections, and blocking files still delay the first paint. So remove the requests you don't need, and stop forcing everything into a single giant bundle, which can hurt caching on the newer protocols.
How do I check how many HTTP requests my page makes?
Open the Network panel in your browser's developer tools, tick Disable cache, reload, scroll to the bottom and read the request count in the status bar. For the number our report uses, run the page through the free SEO report or paste the one line selector from this guide into the console. The report can read a little higher than the browser, because it also counts elements inside noscript blocks.
How do I reduce HTTP requests in WordPress?
Deactivate plugins one at a time and re-count after each. Load plugin files only on the pages that need them, switch off the embed script, dequeue the block library stylesheet on pages that use no blocks, and try a free optimization plugin for its merge and delay options. Re-test after each change so you know which step helped.
What causes too many HTTP requests on a page?
The usual causes are plugins and apps that each add their own files, many small icon images, several web font files, third-party tags and widgets, embedded videos and maps, and a long list of separate stylesheets and scripts. Third-party tags are the sneakiest source, because one tag often loads a second and third file from other domains that you never added yourself.
Do fewer HTTP requests help SEO?
Not directly, since Google has not named request count as a ranking signal. A faster page does give visitors a better experience and better Core Web Vitals, and cutting blocking requests is one way to get there. Treat the count as a clue, and check real load time and Largest Contentful Paint to see whether your changes actually helped the page.
Does lazy loading reduce HTTP requests?
It delays requests instead of removing them, so the first load asks for fewer files and finishes sooner. Our report still counts an image that has a src, even with loading lazy on it, because the element is in the HTML. A click to play placeholder for an embed saves one counted element per iframe, provided the poster is a CSS background and not an img. The larger saving is the files the embed would have loaded, which shows in the Network panel, not in the report row.
Are CSS sprites still worth using?
Only for a large set of tiny icons, where they can still save requests, especially on HTTP/1.1. On HTTP/2 an inline SVG icon set is usually easier to maintain and just as quick. Keep an existing sprite if it works well, and don't build a new one for a handful of icons.
Does a CDN reduce the number of HTTP requests?
Not by itself. The page still asks for the same files, so the count in our report does not change. A CDN serves each file from a server near the visitor and can cache it, which makes every request faster. Use it alongside the steps that remove requests, not instead of them.

See how your site scores right now

Paste your address into the free report, then use the How to Fix button on anything that needs work.

Free to use. Results in under a minute for most sites.