Serving Static Content with Cloud Storage? Don't Forget the CDN!

Many websites use cloud storage as part of how they deliver static content to end users. However using these services without a CDN in front of them has the potential to negatively impact performance. You might be surprised by how many sites do just that - about 8.5% of websites that use a CDN for their primary content, based on HTTP Archive data from January 2026!

Background

Content Delivery Networks (CDNs) are an essential component of website delivery, especially when it comes to web performance. According to the 2025 Web Almanac, approximately 70% of popular websites use them. CDNs enable users to connect to servers that are geographically close to them (and at lower latencies), provide distributed caching to offload backend/origin servers and provide other services such as image optimization, edge compute and security. Some CDNs offer cloud storage services, but pretty much all of them can sit in front of another cloud provider’s storage when it is configured for web delivery.

WebAlmanac CDN Usage

Many websites with a cloud backend/origin host their static content on cloud storage services such as Google Cloud Storage, Amazon S3, Oracle Cloud ObjectStorage and Azure Blob Storage. However it’s important to understand that these services operate as backends and do not automatically provide CDN functionality. Put another way: your content is only behind a CDN if you configure it to be!

In numerous web performance audits over the years, I’ve found cloud storage hostnames being used to deliver static content to end users. During my Performance Mistakes talk in November 2024, I shared that there were 580K websites serving content directly from Amazon S3. This has the potential to negatively impact performance, since those resources are generally served from the locations they are hosted in and not a CDN.

I queried the HTTP Archive to see how common this still is and found a few surprising statistics -

  • Overall 5.8% of websites serve at least 1 request directly from cloud storage!
  • 8.53% of websites that use a CDN for delivering their primary content, serve at least 1 request directly from cloud storage!
  • The number of websites serving content directly from Amazon S3 is now 629K - which is an increase of 8.5% since November 2024!

Websites Delivering Assets via Cloud Storage

Cloud Storage is not distributed like CDNs

When you configure cloud storage services, you usually have to define which region your content will be hosted in. This is essentially where your static content will live. When you deliver that content directly via a cloud storage solution, then it will fetch the asset the same as it would if it was hosted on a webserver.

For example, below is a request that was delivered from a European news site. I’m browsing it from the northeast US. The hostname s3.eu-central-1.amazonaws.com indicates that this content is being delivered from Amazon’s S3 region in Frankfurt, and I can confirm the same via a traceroute.

When I examine this in Chrome DevTools, I can see very high TCP and TLS connection times for this request!

Latency Example

What type of content is delivered directly via Cloud Storage

In this analysis, I’ve searched for 4 different popular cloud storage providers based on their documented URL structures for web delivery. For Amazon S3 I’m looking for hostnames ending in amazonaws.com with s3 optionally within the hostname. For Google Cloud Storage, I’m looking for a subdomain of storage.googleapis.com. For Azure, a subdomain of windows.net and for Oracle a subdomain of either oraclecloud.com or customer-oci.com.

The graph below illustrates the amount of requests delivered by these services across all measured sites, and it’s grouped by content type. Amazon S3 is by far the most commonly used cloud storage service when it comes to this type of delivery, followed by Google Cloud Storage.

Static Asset Types Delivered by Cloud Storage

If we look at the same data by the percentage of requests to each cloud storage service, we can see that regardless of the service almost 75% of content delivered from cloud storage are scripts and images. This type of content is best served to users via a CDN rather than a centralized storage solution.

Delivery of JSON content is also common. While JSON can be dynamically generated, if it’s being served from a cloud storage then it is likely cacheable. HTML delivery is less common, except for Oracle Cloud where it represents 11.8% of cloud storage requests!

Distribution of Static Asset Types Delivered by Cloud Storage

Caching and Compression

One thing that may not be apparent when configuring cloud storage for delivery of web content is that compression and downstream caching are often not enabled by default.

Based on the HTTP Archive, a majority of compressible content types are not being served compressed when delivered directly from Cloud Storage. This is a critical performance mistake, and is often overlooked because most web servers and CDNs do this by default!

Static Asset Compression When Delivered via Cloud Storage

Most content being delivered from cloud storage should be cacheable unless personalized. However the percentage of cloud storage services including Cache-Control headers is incredibly low (with the exception of Google Cloud Storage). That means that clients will have to frequently make requests to these cloud storage services.

ServiceCacheable RequestsNon-Cacheable Requests% Cacheable% Non Cacheable
Amazon S3736,9502,587,32022.2%77.8%
Google Cloud Storage969,660259,62978.9%21.1%
Azure Blob Storage102,857376,29121.5%78.5%
Oracle Cloud Object Storage6,76327,87719.5%80.5%

Digging a bit deeper we can see that images, JS, JSON and CSS account for most of the non-cacheable content delivered via Amazon S3. These asset types are often delivered with cache-control headers allowing caching from Google Cloud Storage.

Amazon S3Google Cloud StorageAzure Blob StorageOracle Cloud Object Storage
typecacheablenot-cacheablecacheablenot-cacheablecacheablenot-cacheablecacheablenot-cacheable
image561,5921,743,876489,387131,98884,912284,5364,66818,132
script91,890272,434370,12745,6215,37826,0611,6582,599
json41,046201,54348,53427,9173036,0832631,126
css26,926103,00730,8931,3402,91918,666141863
xml4085,77819311,90999,18633
other2,11182,0434,6232,17040814,539903
font13,00233,65224,6191,3448,2428,5113031
video19137,69944119,4356805,18379
text14816,3953864,24522,84037
html4,3502010,3825414,071
audio36,5144313,278413833
wasm12967

Here’s an example from a popular movie theater chain in the US. This content appears to be loaded by a 3rd party (Unbounce), and that third party is configured to load images directly from S3. There are no cache headers present, which means that the browser will heuristically cache the resources. On this particular page, this third party’s S3 content accounted for over 9MB of content - none of them containing a cache-control header! Beyond that there are a few opportunities for image optimization that could be applied.

Caching Example

In an example from another movie theater’s website, we can see render-blocking CSS and JS loaded from Amazon S3, with no cache-control header to indicate caching, and no compression. This is perhaps the worst case scenario - where you have content critical to the rendering of your website that is loaded slowly from a centralized location, with unnecessary large payloads and then unpredictable caching (or no caching) due to a missing cache-control header.

Caching Compression Example

Cloud Storage vs CDN Delivery Costs

It’s also worth evaluating how much delivering traffic directly from these cloud storage solutions is costing. Depending on your contracts with the providers, you may find that delivering directly via cloud storage is more expensive compared to CDN delivery - especially if you are not caching or compressing the content! If that is the case, you can get a double-win by saving money while improving performance!

Conclusion

It’s incredible that 8.5% of websites that utilize a CDN are delivering content to users directly from cloud storage services. Discovering and fixing these could provide a quick performance boost. When you audit your website’s performance, if you notice cloud storage hostnames then you should definitely investigate how they got there, and move that content behind your CDNs.

HTTP Archive queries

This section provides some details on how this analysis was performed, including SQL queries. Please be warned that some of the SQL queries process a significant amount of bytes - which can be very expensive to run.

What Percentage of CDN delivered sites have request for Cloud Storage hosted assets This query counts the number of sites that contain at least 1 request for an asset delivered directly via a Cloud Storage service (without a CDN).

 SELECT
    IF(JSON_VALUE(p.summary.cdn) IS NOT NULL AND NOT JSON_VALUE(p.summary.cdn) = "",true, false) AS usesCDN,
    CASE
       WHEN NET.HOST(url) LIKE "%.amazonaws.com" THEN "Amazon S3"
       WHEN NET.HOST(url) LIKE "%storage.googleapis.com" THEN "Google Cloud Storage"
       WHEN NET.HOST(url) LIKE "%.windows.net" THEN "Azure Blob Storage"
       WHEN NET.HOST(url) LIKE "%.oraclecloud.com" THEN "Oracle Cloud Object Storage"
       WHEN NET.HOST(url) LIKE "%.customer-oci.com" THEN "Oracle Cloud Object Storage"
       ELSE "Unknown"
    END AS CloudStorage,
    COUNT(DISTINCT p.page) AS sites
FROM `httparchive.crawl.requests` AS r
INNER JOIN `httparchive.crawl.pages` AS p
ON r.page = p.page
WHERE
   p.date = "2026-01-01" AND r.date = "2026-01-01"
   AND p.client = "mobile" AND r.client = "mobile"
   AND p.is_root_page = TRUE AND r.is_root_page = TRUE
   AND (
     NET.HOST(url) LIKE "%.amazonaws.com"
     OR NET.HOST(url) LIKE "%storage.googleapis.com"
     OR NET.HOST(url) LIKE "%.windows.net"
     OR NET.HOST(url) LIKE "%.oraclecloud.com"
     OR NET.HOST(url) LIKE "%.customer-oci.com"
   )
GROUP BY 1,2
Caching and Compression of Cloud Storage Delivered Assets This query counts the number of requests being delivered cached and compressed by content type.

 
SELECT
  IF(JSON_VALUE(p.summary.cdn) IS NOT NULL AND NOT JSON_VALUE(p.summary.cdn) = "",true, false) AS usesCDN,
  CASE
    WHEN NET.HOST(url) LIKE "%.amazonaws.com" THEN "Amazon S3"
    WHEN NET.HOST(url) LIKE "%storage.googleapis.com" THEN "Google Cloud Storage"
    WHEN NET.HOST(url) LIKE "%.windows.net" THEN "Azure Blob Storage"
    WHEN NET.HOST(url) LIKE "%.oraclecloud.com" THEN "Oracle Cloud Object Storage"
    WHEN NET.HOST(url) LIKE "%.customer-oci.com" THEN "Oracle Cloud Object Storage"
    ELSE "Unknown"
  END AS CloudStorage,
  JSON_VALUE(r.summary.type) AS type,
  CASE JSON_VALUE(r.payload._contentEncoding)
    WHEN 'gzip' THEN 'Gzip'
    WHEN 'br' THEN 'Brotli'
    WHEN 'zstd' THEN 'zStandard'
    ELSE 'No compression'
  END AS compression_type,
  IF(SAFE_CAST(JSON_VALUE(r.payload._cache_time) AS INT64) > 0, "cacheable", "not-cacheable") AS cacheable,
  COUNT(DISTINCT p.page) AS sites,
  COUNT(*) AS requests
FROM `httparchive.crawl.requests` AS r
INNER JOIN `httparchive.crawl.pages` AS p
ON r.page = p.page
WHERE
  p.date = "2026-01-01" AND r.date = "2026-01-01"
  AND p.client = "mobile" AND r.client = "mobile"
  AND p.is_root_page = TRUE AND r.is_root_page = TRUE
  AND (
      NET.HOST(url) LIKE "%.amazonaws.com"
      OR NET.HOST(url) LIKE "%storage.googleapis.com"
      OR NET.HOST(url) LIKE "%.windows.net"
      OR NET.HOST(url) LIKE "%.oraclecloud.com"
      OR NET.HOST(url) LIKE "%.customer-oci.com"
  )
GROUP BY 1,2,3,4,5
Examples of Sites that load content from cloud storage services Detailed examples of sites that are loading content from cloud storage services.

 SELECT
   p.rank,
   r.page AS page,
   JSON_VALUE(p.summary.cdn) AS pageCDN,
   NET.HOST(r.url) AS hostname,
   COUNT(*) AS requests,
   SUM(CAST(JSON_VALUE(r.summary.respBodySize) AS INT64)/1024/1024) AS responseMB,
   STRING_AGG(DISTINCT JSON_VALUE(r.summary.type)) AS types,
   FROM `httparchive.crawl.requests` AS r
INNER JOIN `httparchive.crawl.pages` AS p
ON r.page = p.page
WHERE
   p.date = "2026-01-01" AND r.date = "2026-01-01"
   AND p.client = "mobile" AND r.client = "mobile"
   AND p.is_root_page = TRUE AND r.is_root_page = TRUE
   AND p.rank <= 1000 AND r.rank <= 1000
   AND (
     NET.HOST(url) LIKE "%.amazonaws.com"
     OR NET.HOST(url) LIKE "%storage.googleapis.com"
     OR NET.HOST(url) LIKE "%.windows.net"
     OR NET.HOST(url) LIKE "%.oraclecloud.com"
     OR NET.HOST(url) LIKE "%.customer-oci.com"
   )
GROUP BY 1,2,3,4
ORDER BY 6 DESC

  

© 2026 Paul Calvano. All rights reserved.

Powered by Hydejack v9.0.2