Speed
- Aggregated Internet Measurement
- Glossary
- Speed
- Origin Analytics
- Observatory dashboard
- FAQ
- Observatory (beta)
- RUM beacon for Web Analytics
- Run test
- Understand test results
- Settings
- Measurement
- Recommendations
- Content compression
- Content optimizations
- Prefetch URLs
- Shared dictionaries
- Speed Brain
- FAQ
- Cloudflare Fonts
- Troubleshooting
- Enable
- Ignore JavaScripts
- Rocket Loader
- Content encoding issues
- Turn off Auto Minify via API
- Troubleshooting
- Image optimization
- Cloudflare Mirage (deprecated)
- Troubleshooting
- Image optimization on optimized images
- Troubleshoot missing images
- 0-RTT Connection Resumption
- Enhanced HTTP/2 Prioritization
- HTTP/2 to Origin
- HTTP/2
- HTTP/3 (with QUIC)
- Protocol optimization
- Enhanced HTTP/2 Prioritization negatively affects iOS/Safari devices
- Troubleshooting
- Troubleshoot protocol issues
- Troubleshooting
- Troubleshooting a slow website
Aggregated Internet Measurement
Aggregated Internet Measurement (AIM) helps you understand your Internet quality to identify scenarios that your Internet connection is good or bad for. Typically, an Internet speed test provides you with upload and download speeds, which may not always provide a holistic view of your Internet quality.
AIM uses a scoring rubric that assigns point values based on speed tests to help you understand how your Internet quality will perform for streaming, gaming, and webchat/real-time communication (RTC).
Scoring Rubric
AIM analyzes the following metrics to generate your score:
- Latency
- Packet Loss
- Download
- Upload
- Loaded Latency
- Jitter
After the test is run and a point value is assigned to each metric, the points are translated to a network score for streaming, gaming, and webchat/RTC. These scores will indicate how good your Internet is in each of these scenarios.
The possible network scores are:
- Bad
- Poor
- Average
- Good
- Great
Improve your network score
You have a few options to help improve network scores.
- Switch to a wired connection. When possible, switch to a wired connection instead of wireless to avoid performance issues due to radio interference and signal strength.
- Move closer to your router. If you are unable to use a wired connection, try to move closer to your wireless router. Signal strength drops as you move away from your wireless router and a weaker signal means poorer connectivity. Keep in mind that any objects or materials between you and your wireless router can also have a negative impact on signal strength.
- Upgrade your router. Ensure you are using a router capable of handling smarter queueing with hardware that will not fall over under load.
- Contact your ISP. If you’re using a wired connection or have a good connection to your wireless router and are still seeing issues, you may have issues with your Internet connection and should reach out to your ISP.
Glossary
import { Glossary } from "~/components"
Review the definitions for terms used across Cloudflare's Speed documentation.
Speed
import { CardGrid, Description, Feature, LinkTitleCard, Plan, RelatedProduct } from "~/components"
Improve the performance of your website or web application.
Speed allows you to assess the performance of your website and get recommendations of Cloudflare products to enhance the website performance.
Features
Use Observatory to conduct tests with both synthetic and real user data to identify potential website performance enhancements.
See how your origin server responds to Cloudflare. Identify slow endpoints, monitor response times, and diagnose errors.
Get recommendations of Cloudflare products and settings to improve your website’s performance.
Understand your Internet quality to identify scenarios that your Internet connection is good or bad for.
Related products
Customize the cache properties of your HTTP requests. Understand the performance of your webpages as experienced by your site visitors. Transform images on Cloudflare's edge platform: resize, adjust quality, and convert images to WebP or AVIF format on demand. Take advantage of "server think time" to asynchronously send instructions to the browser to begin loading resources while the origin server is compiling the full response.More resources
Learn about the quota limits for the number of tests you can run per month.
Engage with other users and explore more resources on Cloudflare support forum.
Origin Analytics
Origin Analytics shows how your origin server responds to Cloudflare, using data collected at the edge without an agent on your origin.
Use Origin Analytics to identify slow endpoints, monitor origin response times, and diagnose errors. When something goes wrong, Origin Analytics shows whether the source is your origin, the network path, or Cloudflare. For common error codes, refer to Cloudflare 5xx errors.
View Origin Analytics
To open the Origin Analytics tab:
- Log in to the Cloudflare dashboard and select your account and domain.
- Go to Speed > Origin Analytics.
Metrics
The dashboard displays the following metrics, derived from your zone's edge logs.
Origin response time
Use this metric to spot slowdowns and catch requests approaching your timeout threshold before they result in 524 errors.
Origin response time shows how long your origin takes to respond to Cloudflare, measured at the 50th, 95th, and 99th percentiles. A reference line indicates your zone's configured origin timeout.
The clock starts when Cloudflare decides the request must go to origin (a cache miss) and stops when Cloudflare receives the response headers — not the full body — back from your origin. It includes DNS resolution, TCP and TLS handshakes, request transmission, origin processing, and response receipt. If Argo Smart Routing or Tiered Cache is enabled, the metric also includes time spent routing through those services.
Because this measures the full upstream round trip, Origin Analytics shows higher response times than your origin's own monitoring tools (for example, Grafana or Datadog), which measure only server-side processing time.
Origin status codes
Use this metric to understand what your origin actually returned when users report errors. The error code the end user sees can differ from what your origin returned, because Cloudflare wraps certain origin failures in its own error codes (such as 520, 522, or 524).
Origin Analytics shows both values: the response code from your origin (originResponseStatus) and the code Cloudflare served to the end user (edgeResponseStatus). Status codes are grouped by class (2xx, 3xx, 4xx, 5xx) and shown over time.
The following table shows common scenarios where these values differ:
| What happened | originResponseStatus |
edgeResponseStatus |
|---|---|---|
Origin returned 200 with malformed headers |
200 |
520 |
| Origin returned a server error | 503 |
503 or 520 |
| Origin closed the connection mid-response | 0 |
520 |
| Origin did not respond in time | 0 |
524 |
| TCP connection to origin failed | 0 |
522 |
| Request served from cache | 0 |
200 |
| Worker handled the request | 0 |
Varies |
A status code of 0 means Cloudflare did not receive an HTTP response from the origin. This can indicate a connection failure, a timeout, or that the request was served from cache or handled by a Worker before reaching the origin.
Top endpoints
Use this table to narrow down which specific path is causing slowdowns or errors. Request paths are ranked by P95 response time, error rate, request volume, or TCP failure rate.
Common diagnostic flows
The following table describes how to use Origin Analytics to investigate common origin errors.
| Issue | What to check |
|---|---|
| 524 timeout errors | Origin response time chart. If P95 is approaching the timeout threshold, identify slow paths in the Top endpoints table. |
| 522 connection errors | Verify that your firewall allows Cloudflare IP ranges and that your origin is listening on the expected port. |
| 520 unknown errors | Origin status code chart. If the origin returned a 200 but Cloudflare served a 520, the origin response was malformed (for example, oversized headers or an early connection close). |
Related resources
- Cloudflare 5xx errors — diagnose specific error codes like 520, 522, and 524.
- Logpush — export per-request logs with origin timing fields not available in the dashboard.
- GraphQL Analytics API — query origin metrics programmatically, including fields not shown in the dashboard.
- Observatory dashboard — monitor end-user performance with synthetic tests and real user data.
Observatory dashboard
The Observatory overview dashboard provides a single view of your zone's performance over the past seven days. It combines synthetic monitoring, real user data, and Cloudflare's analysis to help you quickly identify performance bottlenecks and receive actionable recommendations.
Suggestions
The Suggestions panel highlights tailored optimizations you can make to improve performance. Examples include:
- Reduce Largest Contentful Paint (LCP) with Polish.
- Reduce Time to First Byte (TTFB) with Argo Smart Routing.
These recommendations will vary based on your site's observed performance.
Selecting a suggestion expands it to show more detail:
- Why you're seeing this: Explains the performance issue detected.
- What you can do: Lists recommended actions you can take.
Core Web Vitals
The dashboard integrates Core Web Vitals, showing values at the 75th percentile (p75). These metrics reflect real user experiences:
- Largest Contentful Paint (LCP): How quickly the main content of a page becomes visible.
- Interaction to Next Paint (INP): How responsive the site is to user interactions.
- Cumulative Layout Shift (CLS): How visually stable the page layout is.
If insufficient real user data is available, metrics may show as No data.
Network Performance
The Network Performance section shows timing data that can help pinpoint where latency occurs.
-
Time to First Byte (TTFB): Measures the time between the initial request and the first byte of the response.
-
Time to Last Byte (TTLB) Breakdown: Provides a breakdown of response phases:
- DNS resolution time
- TCP connection time
- Request processing time at the server
- Response transfer time
This breakdown helps identify whether delays are caused by DNS, connection setup, server processing, or response delivery.
HTTP Traffic
The HTTP Traffic section shows how traffic is handled between Cloudflare and your origin server:
- Served by: Percentage of requests served from Cloudflare versus from your origin.
- 4xx errors: Client errors, broken down by Cloudflare edge versus origin.
- 5xx errors: Server errors, broken down by Cloudflare edge versus origin.
This view helps distinguish between Cloudflare-side issues and origin-side issues.
Synthetic Monitoring
The Synthetic Monitoring table shows automated test results for your site. Each row includes:
- URL tested
- Last test run
- Repeats (if scheduled multiple times)
- Score (Pass/Fail)
Synthetic monitoring allows you to proactively test site availability and performance under consistent conditions, complementing real user monitoring (RUM).
Using the dashboard
Use the Speed Overview dashboard to:
- Review Suggestions for actionable optimizations.
- Track Core Web Vitals to ensure a good user experience.
- Analyze Network Performance to identify latency bottlenecks.
- Diagnose errors with HTTP Traffic insights.
- Confirm site reliability using Synthetic Monitoring results.
FAQ
import { Render, DashButton } from "~/components";
Below you will find answers to our most commonly asked questions. If you cannot find the answer you are looking for, refer to the community page to explore more resources.
How long does it take for a test to load?
It can vary from about 25 seconds to over a minute. If you leave your speed tab open, your test is still going to run. You can leave and return and still see your test results.
Are query parameters or anchors supported in tested URLs?
No. At the moment, any query parameter or anchor appended to the tested URL are dropped.
For example, using the https://example.com/blog/?utm_medium=social#title URL, the Observatory will discard the ?utm_medium=social query parameter as well as the #title anchor. The tested URL will actually be https://example.com/blog/.
I get a 403 response when rerunning the website analysis?
Check your WAF custom rules to make sure that you are not blocking traffic from Observatory to request your site.
Why might users not see any Real User Monitoring (RUM) data on the map in Observatory?
There are several reasons why users might not see any Real User Monitoring (RUM) data on the map in Observatory:
-
Time Required for RUM Data Population: Populating the RUM database takes some time. It means that newly enabled RUM might not have immediate data available, and users may need to wait for some time before RUM data starts appearing on the map.
-
Progressive Sampling: RUM data is progressively sampled, which means that not all requests are captured. Some requests may pass through the sampling period, resulting in incomplete or missing data points on the map.
-
Adblockers Impact on RUM Data: RUM data collection relies on third-party JavaScript executing on the real-user browser. However, adblockers or similar browser extensions can block this script, preventing the collection of RUM data, and thereby affecting the completeness of the analytics presented on the map.
-
The RUM feature needs to be enabled and configured in your environment. If it has not been turned on, or if configuration is incomplete, RUM data may not appear.
What are the potential reasons for discrepancies between RUM analytics and traffic analytics in Observatory?
Differences between Real User Monitoring (RUM) analytics and traffic analytics in Observatory can occur due to the following reasons:
-
Adblockers Impact on RUM Data: Similar to the previous point, RUM data collection can be thwarted by adblockers, leading to missed data. Since traffic analytics typically rely on server-side data collection, they may not be as affected by adblockers as RUM.
-
Progressive Sampling in RUM: RUM data is collected through progressive sampling, which means that not all user requests are captured. This sampling method could result in slight variations in analytics when compared to traditional traffic analytics that record every server request.
How do I disable Real User Monitoring (RUM) if it has been enabled from the Observatory test result page?
Enabling RUM creates a Web Analytics configuration entry for the hostname at the account level.
If you wish to disable RUM, follow these steps:
-
In the Cloudflare dashboard, go to the Web Analytics page.
-
Select Manage Site for the hostname for which you wish to disable RUM.
-
Select Delete.
Observatory (beta)
Observatory uses synthetic tests and real user data from browsers to assess the performance of your website. These data sources produce metrics that provide different types of insights into your website’s performance. Cloudflare then uses the analysis run by Observatory to recommend optimizations with the tools that best suit your performance issues.
Synthetic tests
As its name suggests, synthetic testing uses servers to simulate the conditions that a user might encounter when accessing your website. This has the advantage of being consistent, as the conditions are easily replicated each time the test is run. It also allows you to have an analysis of how a code change might affect the overall performance of your website, as well as test any URL you want. However, due to its synthetic nature, it cannot replicate the breadth and diversity of different conditions that real users will experience.
Observatory provides two different types of synthetic tests:
Browser test
The browser test loads the requested page in a headless browser and runs Google Lighthouse on it. This reports key performance metrics and provides light suggestions for improvement.
Network test
The network test is focused on giving a detailed breakdown of the network and back-end performance of an endpoint. For more information on metrics collected, refer to Network monitoring metrics.
Network comparison test
You can also compare network tests in Observatory by selecting any two completed tests. The results for each test are displayed side by side as histograms, allowing you to easily visualize and compare the full distribution of data points across both tests.
Real user monitoring (RUM)
Real user monitoring (also known as RUM), on the other hand, captures real metrics from real users accessing your own websites. This provides information that synthetic tests cannot capture, as users might access your website from different parts of the world, with different network conditions, ISPs, devices, browsers, browser extensions and other software competing for resources. Real user data also includes a user interaction metric that synthetic tests do not offer: Interaction to Next Paint (INP).
Free customers have RUM enabled automatically, with traffic from EEA/UK/CH excluded, and can switch it off if they prefer. Customers on other plans may enable RUM as needed.
Run testRUM beacon for Web Analytics
The RUM beacon is a JavaScript snippet that runs when a Cloudflare customer enables RUM through Web Analytics or Observatory. This script runs in users' browsers when they visit the customer's site, and its purpose is to collect performance-related data, for example, page load time, and send it to Cloudflare's systems for processing. This data is then presented to the customer, providing valuable insights into the website's performance and usage.
The RUM beacon script can be enabled into a webpage in two ways:
-
One-click setup: For sites proxied through Cloudflare that have Web Analytics enabled, the snippet can be automatically injected into pages as the HTML response passes through Cloudflare's edge network to the browser by simply enabling the automatic injection option.
-
Manual setup: Websites can manually add the script by embedding a code snippet into their pages. Refer to the Sites not proxied through Cloudflare section, for more information about how to manually insert the snippet into your HTML.
Data collection
Once downloaded to the browser, the RUM beacon script runs as JavaScript in the browser. It collects performance data from browser APIs and sends this data to Cloudflare for processing.
The data collected from the browser is summarized in the table below:
| Field | Example | Description | How it is collected |
|---|---|---|---|
pageloadId |
0c698922-8d60-40bf-85ac-7982b5f8034d | The unique ID for the page. | Generated in the browser code. |
referrer |
https://cfrumtest.com/ | The referring page URL. | If it is a multi-page application (MPA), then it is generated from document.referrer. If it is a single-page application (SPA), then it is generated from a local in-memory variable in the beacon code which stores previous URLs. |
startTime |
1693488419352 | Baseline for performance-related timestamps. | performance.timeOrigin |
memory |
{ totalJSHeapSize: 39973671, usedJSHeapSize: 39127515, jsHeapSizeLimit: 4294705152 } |
Measures memory heap size. | performance.memory (deprecated) |
timings |
Object of PerformanceTiming | Timing data. | performance.timing (deprecated, fallback when timingV2 is unavailable) |
timingV2 |
Object of PerformanceNavigationTiming | Navigation timing data. | performance.getEntriesByType("navigation") |
firstPaint |
Array of PerformancePaintTiming | Paint timing data. | performance.getEntriesByType("paint") |
firstContentfulPaint |
209 | First Contentful Paint metric. | web-vitals module [^1] |
FCP |
209 | First Contentful Paint metric. | web-vitals module [^1] |
LCP |
209 | Largest Contentful Paint metric. | web-vitals module [^1] |
CLS |
0.001 | Cumulative Layout Shift metric. | web-vitals module [^1] |
TTFB |
0.03 | Time to First Byte metric. | web-vitals module [^1] |
INP |
1.23 | Interaction to Next Paint metric. | web-vitals module [^1] |
landingPath |
https://cfrumtest.com/ | The landing page URL. | performance.getEntriesByType("navigation") |
Data processing
RUM data is generally processed at the nearest Cloudflare data center based on how the incoming request is routed. This is determined by a number of factors including Anycast and Unimog. Since RUM data does not use location services, it may be processed in a different country or region from where it originated. Although the RUM service receives the client/source IP address from the beacon as part of normal HTTP request handling process, it discards the IP address at the nearest Cloudflare data center and does not store it in core databases or logs.
Privacy information
The RUM beacon script does not store any data in the browser or access any storage data, such as cookies, localStorage, sessionStorage, IP address, or IndexedDB. The data we collect is performance data from the browser performance APIs. This performance data is ephemeral and only relates to the current webpage that is being viewed. If the user refreshes their browser, all the previous performance data is gone and new performance data starts being available. This data is not stored or accessed from anywhere on the device, it is only available as in-memory data.
RUM excluding EEA/EU
Customers have the option to enable RUM globally or to limit its application to exclude users connecting to Cloudflare data centers in the EEA/EU. If the latter option is selected, the RUM beacon does not process performance data for users connecting to a Cloudflare data center located in the following countries (ISO codes): AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LI, LT, LU, MT, NL, NO, PL, PT, RO, SK, SI, ES, SE, CH, GB.
Free customers have RUM enabled automatically, with EU traffic excluded, and can switch it off if they prefer. Customers on other plans may enable RUM as needed.
<div class="medium-img">

</div>
[^1]: The web-vitals module is an open-source module written by Google. It does not access any type of storage on the browser.
Run test
import { Render, DashButton } from "~/components";
Run Synthetic test
-
In the Cloudflare dashboard, go to the Synthetic Monitoring page.
-
Enter the URL you want to test. The URL must belong to the zone you are testing from.
-
Select the test type you want to use: Browser or Network tests.
-
Select the Region the automated browser will use.
-
Depending on your plan you can select to run the test once, daily or weekly. Refer to the Quotas section for information on the test frequency available for your plan. Note that these limits may change over time.
-
After the test finishes running, you will get a Lighthouse score and you will have access to the list of the tests run. The test result page will give you details regarding the performance of your website, both for the desktop and mobile versions. Refer to Understand test results for more information.
Recommendations
Observatory shows you a Recommendations tab, depending on the results from testing your website. The Recommendations section shows you the opportunities to improve your website that were identified based on the Lighthouse audits and recommends Cloudflare features or products that will help you improve those metrics. We also show you the potential savings you will get by enabling the recommended features or products.
Trend and History report
In the Tested URLs table, in the last column, you can select the three dots > View history report, and you will have access to the Trend table that will show your website’s performance metrics over time and a History report of all the tests you run on your website.
Enable real user monitoring (RUM)
Once a test has been run, you can enable RUM data in the test results page:
- Go to Observatory and select Enable RUM. You can choose to enable globally or enable everywhere except the EU.
- Once RUM data is running on your site, you can access Real user measurements on your test results page. Usually it takes less than five minutes to see the data coming in, but it will depend on traffic.
Refer to Understand test results for more information about the results provided by real user data.
Information collected
RUM uses a lightweight JavaScript beacon to collect the information Observatory uses. It does not use any client-side state, such as cookies or localStorage, to collect usage metrics.
Quotas
Quota limits for the number of tests you can run per month are currently the following:
| Plan | One-off tests | Recurring tests | Frequency of recurring tests |
|---|---|---|---|
| Pro | 50 | 5 | Daily |
| Business | 100 | 10 | Daily |
| Enterprise | 150 | 15 | Daily |
Available Regions (all plans):
| Region | Region | Region |
|---|---|---|
| Iowa, USA | Hamina, Finland | Changhua County, Taiwan |
| South Carolina, USA | Madrid, Spain | Tokyo, Japan |
| North Virginia, USA | St. Ghislain, Belgium | Osaka, Japan |
| Dallas, USA | Eemshaven, Netherlands | Jurong West, Singapore |
| Oregon, USA | Milan, Italy | Sydney, Australia |
| London, England | Paris, France | Mumbai, India |
| Frankfurt, Germany | Tel Aviv, Israel | São Paulo, Brazil |
Understand test results
The test result page shows you how your website performed regarding several key industry metrics. Some of these metrics are presented for synthetic tests and the real user monitoring, and others only apply to synthetic tests or only to real user monitoring.
Synthetic tests and real user monitoring metrics
These metrics are presented for the synthetic tests and they are also collected as part of the real user data.
| Metric | Definition |
|---|---|
| Time to First Byte (TTFB) | Measures the time between the request for a resource and when the first byte of a response begins to arrive. |
| First Contentful Paint (FCP) | Measures the time from when the page starts loading to when any part of the page's content is rendered on the screen. |
| Largest Contentful Paint (LCP) | CP reports the render time of the largest image or text block visible within the viewport. |
| Cumulative Layout Shift (CLS) | Measures the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifespan of a page. |
Synthetic tests metrics
These metrics result from the synthetic tests.
| Metric | Definition |
|---|---|
| Time to Interactive (TTI) | Measures the time from when the page starts loading to when its main sub-resources have loaded and it is capable of reliably responding to user input quickly. |
| Total Blocking Time (TBT) | Measures the total amount of time between First Contentful Paint (FCP) and Time to Interactive (TTI) where the main thread was blocked for long enough to prevent input responsiveness. |
| Speed index | Measures how quickly content is visually displayed during page load. |
Real user monitoring metrics
These metrics are collected as part of the real user data, as they require real user interaction with a page.
| Metric | Definition |
|---|---|
| Interaction to Next Paint (INP) | Aims to represent a page's overall responsiveness by measuring all click, tap, and keyboard interactions made with a page. |
Refer to Data and metrics for more information about the metrics you can find in the Real User Monitoring dashboard. You can find details about Core Web Vitals, the debug view and the data collected.
Network monitoring metrics
| Metric | Definition |
|---|---|
| Wait Time | Measures the time spent waiting for the server to send back the first byte of a response after a request is made. |
| Load Time | Measures the total time it takes for a web page to fully load in a user’s browser from the network. |
| Time to First Byte (TTFB) | Measures the duration between initiating a web page request and receiving the first byte from the server. |
| Server Response Time | Measures the time it takes for a server to respond to a request from a user's browser. |
| Connect Time | Measures the time taken to establish a connection between the user's browser and the web server. |
| TLS Time | Measures the time required to complete the TLS/SSL handshake between the user's browser and the web server. |
Settings
import { DirectoryListing } from "~/components"
The Optimization section will show you a list of Cloudflare products that are recommended for enhancing your website's performance.
Measurement
Enable measurement to track your traffic in a privacy-first manner, optimizing your site's speed tools. To access this feature, you need to enable Web Analytics on your website. This analytics tool leverages Real User Measurement (RUM) data, providing insights based on actual user interactions to enhance site performance effectively.
Recommendations
In the Recommendations tab, with one click you can enable all the recommended settings available for your plan. You can enable all the recommended settings at once or you can also just enable the ones you want.
Content compression
import { Stream, Render } from "~/components";
Cloudflare compresses content in two ways: between Cloudflare and your website visitors and between Cloudflare and your origin server.
Compression between Cloudflare and website visitors
In addition to Cloudflare's default caching behavior, Cloudflare supports Gzip, Brotli, and Zstandard compression when delivering content to website visitors.
:::note Customers can enable Zstandard compression through Compression Rules. :::
If supported by visitors' web browsers, Cloudflare will return Gzip, Brotli, or Zstandard-encoded responses for the following content types:
text/html
text/richtext
text/plain
text/css
text/x-script
text/x-component
text/x-java-source
text/x-markdown
application/javascript
application/x-javascript
text/javascript
text/js
image/x-icon
image/vnd.microsoft.icon
application/x-perl
application/x-httpd-cgi
text/xml
application/xml
application/rss+xml
application/vnd.api+json
application/x-protobuf
application/json
multipart/bag
multipart/mixed
application/xhtml+xml
font/ttf
font/otf
font/x-woff
image/svg+xml
application/vnd.ms-fontobject
application/ttf
application/x-ttf
application/otf
application/x-otf
application/truetype
application/opentype
application/x-opentype
application/font-woff
application/eot
application/font
application/font-sfnt
application/wasm
application/javascript-binast
application/manifest+json
application/ld+json
application/graphql+json
application/geo+json
Cloudflare's global network can deliver content to website visitors using Gzip compression, Brotli compression, Zstandard compression, or no compression, depending on:
- The values visitors provide in the
accept-encodingrequest header. - Your Cloudflare plan.
- Any configured compression rule that matches incoming requests.
For responses with error status codes, Cloudflare will only compress responses if their error status code is 403 or 404. For successful response status codes, Cloudflare will only compress responses if their status code is 200. Responses with other status codes will not be compressed.
You can override Cloudflare's default compression behavior using Compression Rules.
:::caution[Minimum response size for compression]
Cloudflare will only apply compression to responses with a minimum size when sending them to website visitors:
- For Gzip, responses must have a minimum size of 48 bytes.
- For Brotli and Zstandard, responses must have a minimum size of 50 bytes.
Smaller responses will not be compressed, regardless of their content type.
:::
Content-Length header handling
When Cloudflare compresses a response sent to the website visitor, it may omit the Content-Length HTTP header to avoid delivering incorrect length information caused by dynamic transformations. To preserve the Content-Length header set by the origin server, add cache-control: no-transform to the origin server's response. This directive prevents Cloudflare from altering compression on responses, allowing the Content-Length header to pass through as-is. The cache-control: no-transform header must be set by the origin — it cannot be added in client requests.
Content compression from origin servers to the Cloudflare network
When requesting content from your origin server, Cloudflare supports Brotli compression, Gzip compression, or no compression.
flowchart LR
accTitle: Compressed responses sent from the origin server
accDescr: Cloudflare accepts responses from origin server using Brotli compression, Gzip compression, or no compression.
A[Visitor browser]
B((Cloudflare))
C[(Origin server)]
A -.-> B == "Request<br>Accept-Encoding: br, gzip" ==> C
C == "Response<br>(Brotli / Gzip / No compression)" ==> B -.-> A
style A stroke-dasharray: 5 5
style B stroke: orange,fill: orange,color: black
style C stroke-width: 2px
linkStyle 1,2 stroke-width: 2px
linkStyle 0,3 stroke-width: 1px
If your origin server responds to a Cloudflare request using Brotli/Gzip compression, we will keep the same compression in the response sent to the website visitor if:
- You include a
content-encodingheader in your server response mentioning the compression being used (brorgzip). - The visitor browser (or client) supports the compression algorithm.
- You do not enable Cloudflare features that change the response content (refer to Notes about end-to-end compression for details).
Cloudflare's reverse proxy can also convert between compressed formats and uncompressed formats. Cloudflare can receive content from your origin server with Brotli or Gzip compression and serve it to visitors uncompressed (or vice versa), independently of caching.
If you do not want a particular response from your origin to be encoded with Brotli/Gzip when delivered to website visitors, you can disable this by including a cache-control: no-transform HTTP header in the response from your origin web server.
:::caution
Cloudflare will take into consideration the accept-encoding header value in website visitors' requests when sending responses to those visitors. However, when requesting content from your origin server, Cloudflare will send a different Accept-Encoding header, supporting Brotli and Gzip compression.
:::
Compression methods by plan
Between visitors and Cloudflare
By default, Cloudflare uses the following compression methods for content delivery, depending on the zone plan. However, the actual compression applied may also depend on what the visitor's browser requests via the accept-encoding header.
- Free Plan: Content is compressed by default using Zstandard.
- Pro and Business Plans: Content is compressed by default using Brotli.
- Enterprise Plan: Content is compressed by default using Gzip.
Between Cloudflare and the origin server
On all plans, Cloudflare requests content from the origin server using the accept-encoding: br, gzip header. This means that Cloudflare asks the origin to send the content compressed using Brotli or Gzip, depending on which method the origin server supports.
Content optimizations
import { DirectoryListing } from "~/components"
Prefetch URLs
import { Example, TabItem, Tabs, DashButton } from "~/components";
URL prefetching means that Cloudflare pre-populates the cache with content a visitor is likely to request next. This setting — when combined with additional setup — leads to a higher cache hit rate and thus a faster experience for the user.
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | No | No | No | Yes |
Setup
For Cloudflare to start prefetching URLs, you will need to enable the feature and include a list of URLs to prefetch.
Enable Prefetch URLs
To enable Prefetch URLs in the dashboard:
-
In the Cloudflare dashboard, go to the Speed > Settings page.
-
Go to Content Optimization.
-
For Prefetch URLs, switch the toggle to On.
To enable or disable Prefetch URLs with the API, send a PATCH request with prefetch_preload as the setting name in the URI path, and the value parameter set to your desired setting ("on" or "off").
Choose URLs to prefetch
After you enable the feature, you also need to indicate which URLs Cloudflare should prefetch.
To do this, include a Link HTTP response header pointing to a manifest file with the rel="prefetch" attribute and then serve the manifest file with text/plain as the Content-type response header.
`Link: ; rel="prefetch"`
Example manifest.txt file:
/static/fetch1
//other.example.com/fetch2
http://another.example.com/fetch3
The manifest file should contain URIs, protocol-relative URLs or full URLs, separated by new lines. These files must be on your websites that are on Cloudflare. If you reference HTML pages, only the HTML page itself will be pre-fetched - any sub-requests from that HTML will not be fetched unless they are also defined explicitly in your manifest.
:::note[Note]
The IP address used to make the prefetch request to the manifest file is logged as 127.0.0.1 in your Cloudflare logs.
:::
Prefetch files limits
The prefetch files limits are the following:
- The maximum number of manifest files is 16.
- The maximum number of files per manifest file is 100.
- A manifest file has a size limit of 1 MB.
Limitations
-
Cloudflare will only prefetch files listed in the manifest file if the resources are those cached by default.
-
Prefetch is not compatible with the custom cache key configuration. For more information, refer to Cache Key limitations.
Shared dictionaries
import { TabItem, Tabs, CURL, DashButton } from "~/components";
This is most effective for versioned assets that change incrementally between deploys, such as JavaScript bundles, CSS files, and framework chunks. After a deploy, returning visitors can receive the new asset as a small delta against the version they already have, instead of redownloading the full file.
Cloudflare supports shared dictionaries in passthrough mode: your origin manages dictionaries and produces delta-compressed responses. Cloudflare forwards the dictionary headers and dcb/dcz content encodings without modifying or recompressing them, and varies the cache so each delta-compressed variant is stored separately.
For background on the other compression algorithms Cloudflare supports, refer to Content compression.
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Yes (beta) | Yes (beta) | Yes (beta) | Yes (beta) |
Requirements
- The visitor's browser supports compression dictionary transport. Today, this is Chrome 130 or later, Edge 130 or later, or another Chromium browser at the same version.
- The browser request includes
dcbordczinAccept-Encodingand anAvailable-Dictionaryheader. - Your origin returns a delta-compressed response with
Content-Encoding: dcbordczand aVaryheader that includesAccept-Encoding, Available-Dictionary. - The dictionary, the delta response, and the request are served over HTTPS from the same origin. Per RFC 9842, Section 8, compression dictionary transport is HTTPS-only.
How shared dictionaries work
The protocol uses two new request and response headers and two new content encodings:
| Header | Direction | Purpose |
|---|---|---|
Use-As-Dictionary |
Origin → browser | Marks a response as usable as a dictionary for future requests matching the supplied match value. |
Available-Dictionary |
Browser → origin | Advertises the SHA-256 hash of a dictionary the browser already has for the request URL. |
Content-Encoding: dcb or dcz |
Origin → browser | Delta-compressed against the advertised dictionary, using Brotli (dcb) or Zstandard (dcz). |
The first response for a versioned asset includes Use-As-Dictionary, and the browser stores the response. On subsequent requests for assets matching the pattern, the browser sends Available-Dictionary: :<sha256>: and adds dcb, dcz to Accept-Encoding. Your origin compresses the new asset against the dictionary and returns it with Content-Encoding: dcb or dcz. The browser uses its stored copy to reconstruct the full response.
The match value in Use-As-Dictionary is a WHATWG URL Pattern, not a regular expression. Match patterns operate on the percent-encoded URL path and are scoped to the same origin as the dictionary.
The Available-Dictionary value is a Structured Field byte sequence: the base64-encoded SHA-256 hash wrapped in colons (for example, :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:). The colons are part of the syntax.
Enable shared dictionaries
- Turn on passthrough for your zone in Cloudflare. This tells Cloudflare to forward dictionary headers and vary cache entries correctly.
- Update your origin server to mark assets as dictionaries and return delta-compressed responses against them.
The work of creating dictionaries and compressing new responses against them happens at your origin, not at Cloudflare.
1. Enable passthrough in Cloudflare
-
In the Cloudflare dashboard, go to the Speed Settings page.
-
Go to Content Optimization.
-
Toggle Shared Dictionaries to On.
Use the following PATCH request to enable shared dictionaries:
<CURL url="https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/shared_dictionary_mode" method="PATCH" headers={{ Authorization: "Bearer $CLOUDFLARE_API_TOKEN", }} json={{ value: "passthrough", }} />
Valid values for this setting are:
| Value | Behavior |
|---|---|
passthrough |
Cloudflare forwards shared dictionary request and response headers, accepts dcb/dcz responses from the origin, and varies cache entries. |
disabled |
Cloudflare strips shared dictionary headers and does not cache dcb/dcz variants. |
You can configure shared dictionaries using the cloudflare_zone_settings_override resource. For more details, refer to the Terraform documentation.
:::note
Because shared_dictionary_mode is a zone setting, it is not compatible with Cloudflare Version Management. You can enable passthrough in a non-production version, validate that origin responses are correct end to end, and promote to production with a single deploy on a new zone.
:::
2. Mark assets as dictionaries at your origin
For each versioned asset you want to use as a dictionary, include a Use-As-Dictionary header on the first response:
Use-As-Dictionary: match="/static/app-*.js", type="raw"
Cache-Control: public, max-age=31536000, immutable
Content-Encoding: br
The match value tells the browser which future request URLs should advertise this dictionary. It is a WHATWG URL Pattern, does not support regular expressions, and must resolve to the same origin as the dictionary.
3. Compress new versions against the advertised dictionary
When a request arrives with an Available-Dictionary header, look up the dictionary by its SHA-256 hash. If you have it, compress the response against it and return:
Content-Encoding: dcz
Vary: Accept-Encoding, Available-Dictionary
Cache-Control: public, max-age=31536000, immutable
RFC 9842, Section 6.2 requires the Vary: Accept-Encoding, Available-Dictionary response header so that browser caches do not serve the wrong variant. Cloudflare's cache also varies on these headers when passthrough is on.
4. Fall back when no dictionary is available
When the browser does not advertise Available-Dictionary, the hash does not match a dictionary you have, or the browser does not advertise dcb/dcz, return the response with normal Brotli, Zstandard, or Gzip compression.
Implementation options
Cloudflare does not prescribe a specific origin implementation. Common starting points include:
- A reverse proxy. Configure NGINX, Caddy, or a similar proxy to attach
Use-As-Dictionaryheaders and produce delta responses with a sidecar process. - Native support in your application server. Extend your existing compression middleware to read
Available-Dictionaryand emitdcbordcz.
Test shared dictionaries
To confirm a request is using a shared dictionary, request the asset twice. The second request advertises the dictionary you received in the first response.
# Prime the dictionary.
curl -sI -H "Accept-Encoding: br, gzip, zstd, dcb, dcz" \
https://example.com/static/app.v1.js
# Request the next version, advertising the dictionary you just received.
# Replace <hash> with the base64-encoded SHA-256 of the first response.
# The surrounding colons are part of the Structured Field syntax
# and are required by RFC 9842, Section 2.2.
curl -sI -H "Accept-Encoding: br, gzip, zstd, dcb, dcz" \
-H "Available-Dictionary: :<hash>:" \
https://example.com/static/app.v2.js
The second response should include Content-Encoding: dcz (or dcb), Vary: Accept-Encoding, Available-Dictionary, and a Content-Length significantly smaller than a non-delta response.
You can also use canicompress.com to confirm your browser supports shared dictionaries and to inspect a working delta-compressed response.
Limitations
- Origin-side work is required. In passthrough mode, Cloudflare does not generate dictionaries or compute deltas. If your origin does not produce
dcb/dczresponses, no compression savings occur. - Body-modifying features are incompatible. Cloudflare features that rewrite response bodies do not work on delta-compressed responses. Turn these features off on dictionary-compressed paths, or set
cache-control: no-transformon the origin response. For details, refer to Content compression. - Browser support is partial. Visitors on browsers that do not request
dcbordczcontinue to receive Brotli, Zstandard, or Gzip per your existing Compression Rules and default compression behavior. - Same-origin only. Per RFC 9842, Section 9.3.1, dictionaries are scoped to the response origin. Cross-origin dictionary use is not supported.
Speed Brain
import { TabItem, Tabs, APIRequest, DashButton } from "~/components";
Speed Brain is a tool for improving web page performance by prefetching the most likely next navigation.
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Enabled by default | Yes | Yes | Yes |
Requirements
Speed Brain works under the following conditions:
- The Speed Brain feature is enabled in Cloudflare.
- The browser of the web page visitor is using a Chromium-based browser version 121 or later.
- The web page requested by the prefetch is eligible for cache.
- The page requested by the prefetch does not invoke a Worker.
What is Speed Brain?
The overall goal of Speed Brain is to try to download a webpage to the browser before a user navigates to it.
Cloudflare leverages the Speculation Rules API to improve web page performance by instructing the browser to consider prefetching future navigations. Speed Brain does not improve page load time for the first page that is visited on a website, but it can improve it for subsequent web pages that are navigated to on the same site.
By prefetching pages that the browser considers likely to be navigated to, Speed Brain can enhance key metrics like Largest Content Paint (LCP), Time to First Byte (TTFB) and overall page load time.
How Speed Brain works
When Cloudflare's Speed Brain feature is enabled, an HTTP header called Speculation-Rules is added to web page responses. The value for this header is a URL that hosts an opinionated Speculation-Rules configuration. This configuration instructs the browser to consider prefetching any future navigations with a conservative eagerness.
The configuration looks like this:
{
"prefetch": [
{
"source": "document",
"where": {
"and": [{ "href_matches": "/*", "relative_to": "document" }]
},
"eagerness": "conservative"
}
]
}
This configuration instructs the browser to initiate prefetch requests for future navigations. These prefetch requests will include the sec-purpose: prefetch HTTP request header. Prefetches that are not successful will respond with a 503 status code. Prefetches that are successful will respond with a 200 status code.
Test Speed Brain
To test that Speed Brain is enabled, you can check that your HTTP response headers for your web pages include the Speculation-Rules header. However, note that during the beta phase of Speed Brain, this behavior might not be 100% consistent.
To test whether your browser is making prefetch requests, open the Network tab in Chrome DevTools. Then, mouse-down on a link on a webpage with Speed Brain enabled. This action should initiate a prefetch request, which will be visible in the Network tab. However, note that there are several reasons why the browser might choose not to initiate a prefetch. Refer to the Chrome Limits guide for more details. For more general information about debugging Speculation-Rules, refer to the Chrome Speculation Debugging guide.
RUM integration
Speed Brain is designed to integrate with Web Analytics & Real User Measurements (RUM). This integration allows you to understand the web performance implications of Speed Brain within the Web Analytics interface in Cloudflare's Dashboard.
While you can use Speed Brain without RUM enabled, you will not have visibility into how the feature is affecting the performance of your web pages. For further details on how to set up RUM, refer to the Web Analytics & RUM documentation.
Enable and disable Speed Brain
Speed Brain is available in Cloudflare's Speed tab of the dashboard and also in the API.
To enable or disable Speed Brain in the dashboard:
-
In the Cloudflare dashboard, go to the Speed > Settings page.
-
Go to Content Optimization.
-
Toggle Speed Brain to On or Off.
Use the following PATCH request to enable Speed Brain:
<APIRequest path="/zones/{zone_id}/settings/speed_brain" method="PATCH" json={{ value: "on" }} />
To disable Speed Brain, set value: to "off".
You can also configure Speed Brain using Terraform. For more details, refer to the cloudflare_zone_settings_override resource in the Terraform documentation.
Caveats
-
Since prefetch responses are not guaranteed to be rendered by the browser, Speed Brain includes two safeguards to minimize the risk of unsafe prefetching:
-
Speed Brain will not prefetch on routes that run Workers. Without this safeguard, prefetch requests could inadvertently run Worker logic that assumes the incoming request is a normal (that is, not a prefetch) request. An example of this could be an incrementing page view counter running in a Worker. A page view counter should not increment if the page is not actually rendered in the browser.
-
Prefetch requests will never reach origin servers. Prefetch requests only serve content that is stored in Cloudflare’s Cache. If the content is not in Cache, the prefetch request will not continue to origin servers. Without this safeguard, origin server state could be modified despite the prefetch response not being rendered in the browser. An example of this could be a prefetch
GETrequest to a sign-out URL inadvertently triggering a sign-out action on the server.
-
-
If origin server responses include the
Speculation-Rulesheader, it will not be overridden. -
Speed Brain will not work with restrictive Content Security Policy configurations using
strict-dynamicornonce-{hash}attributes. -
Currently, Speed Brain is not compatible with websites that use or rely on
pages.dev.
FAQ
In the following sections, you can find frequently asked questions about performance, privacy, security, implementation and integration.
Performance
How does Cloudflare Fonts improve website performance?
By serving fonts from your own domain through Cloudflare's optimized infrastructure, Cloudflare Fonts reduces DNS lookups, TLS connection setups and latency. This leads to faster page load times, enhancing the overall performance of your website.
Privacy and security
Does Cloudflare Fonts collect or log user data?
No, Cloudflare Fonts does not collect or log user data during the font delivery process. Cloudflare is committed to a privacy-first approach, ensuring that your users' data remains confidential.
Implementation and integration
Do I need to host my font files separately when using Cloudflare Fonts?
No, Cloudflare Fonts simplifies the font delivery process. You do not need to host font files separately. The service works by rewriting the webpage’s HTML. It removes Google Fonts links and replaces them with inline CSS.
Are there any code changes required to use Cloudflare Fonts?
No, you do not need any code changes to use Cloudflare Fonts.
Can I see analytics of font files served via Cloudflare Fonts?
Yes, as Cloudflare will be serving these fonts via your zone, analytics will appear within your Cloudflare dashboard. This allows you to analyze requests for font files that you would not have otherwise known about without Cloudflare Fonts.
Which path are Cloudflare Fonts requests made to?
Font requests will be made to your origin with the /cf-fonts/ path prefix.
What other transformations are made?
Cloudflare will strip any preconnect headers for Google Fonts domains from the HTML response body. This will improve performance by removing unnecessary connections.
Cloudflare Fonts
import { GlossaryTooltip, Render, DashButton } from "~/components";
Cloudflare Fonts is a feature designed for websites that use Google Fonts. It rewrites Google Fonts to be delivered from a website’s own origin, eliminating the need to rely on third-party font providers. Cloudflare Fonts is tailored to improve website performance and user privacy without the need for any code changes or self-hosting of fonts.
How Cloudflare Fonts works
Cloudflare Fonts works by rewriting your webpage’s HTML. It removes Google Fonts links and replaces them with inline CSS. This CSS includes links to fonts from your own Cloudflare zone rather than from Google servers. This ensures that font files are served from your domain through Cloudflare's infrastructure, optimizing performance and enhancing user privacy.
Browser support
Cloudflare Fonts is compatible with browsers that support Unicode-range subsetting and WOFF or WOFF2 formats, including:
Chrome 36+
Edge 16+
Safari 10+
Firefox 44+
Opera 22+
IE 9+
Chrome for Android 115+
Safari on iOS 10+
Samsung Internet 5+
Get started
To enable Cloudflare Fonts for your entire domain:
-
In the Cloudflare dashboard, go to the Speed > Settings page.
-
Go to Content Optimization.
-
For Cloudflare Fonts, switch the toggle to On.
Limitations
While Cloudflare Fonts offers powerful font optimization capabilities, it is important to be aware of its limitations:
- Font transformation: Currently, Cloudflare Fonts exclusively supports Google Fonts transformation.
- APO compatibility: Cloudflare Fonts does not operate when Automatic Platform Optimization (APO) is enabled. Cloudflare APO automatically optimizes Google Fonts in a similar way.
- CSS import: Cloudflare Fonts is compatible only with the
<link>setup for Google Fonts and does not support the CSS@importmethod. - CSP headers: Cloudflare Fonts does not modify Content Security Policy (CSP) headers. Certain CSP configurations may make Cloudflare Fonts stop working, such as restrictions on inline styles through
style-src, or restriction of fonts originating from the site's own origin viafont-src. - Fallback mechanism: In cases where Cloudflare Fonts does not support a specific page, it will gracefully fallback to using Google Fonts.
Troubleshooting
To test that the Fonts feature is working correctly, follow these steps:
- With the Fonts feature disabled, navigate to your webpage and open the network panel in your browser's developer tools. For Chrome, right click on the webpage and select Inspect, which open the developer tools. Next, navigate to the Network tab within the console.
- Reload the page.
- In the Network tab, you should have a request to
fonts.googleapis.com, and a request tofonts.gstatic.com. This means that Google Fonts are being downloaded for this page. If you do not have these requests in the list, either your webpage is not using Google Fonts, or your hosting provider might be optimizing the Google Fonts in some other way. - Enable Cloudflare Fonts and wait for a few seconds.
- In the inspect window, toggle Disable cache on and reload the page.
- In the network panel, you should now have a request to your zone on the
/cf-fonts/path prefix. The requests tofonts.googleapis.comandfonts.gstatic.comshould have disappeared. This means the feature is working correctly.
Feature is not working
For the feature to work, the response HTML (when the feature is disabled) must include a link tag with href pointing to fonts.googleapis.com. You can check this on the browser by viewing the source code of the webpage. As an example of what to look for, the following link tag is for the Roboto Google Font:
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
If the tag does not exist in the HTML, but you are still sure that your page is using Google Fonts, it might be that your hosting provider is optimizing your Google Fonts on the server. This can prevent Cloudflare Fonts from working properly.
Other issues with Cloudflare Fonts
If you experience any issues or have questions while using Cloudflare Fonts, refer to the Cloudflare Community pages or contact Cloudflare Support for assistance.
Enable
import { Render, TabItem, Tabs, DashButton } from "~/components";
To enable or disable Rocket Loader, use the following instructions.
To enable or disable Rocket Loader in the dashboard:
-
In the Cloudflare dashboard, go to the Speed > Settings page.
-
Go to Content Optimization.
-
For Rocket Loader, switch the toggle to On.
To enable or disable Rocket Loader with the API, send a PATCH request with rocket_loader as the setting name in the URI path, and the value parameter set to "on" or "off".
Ignore JavaScripts
You can have Rocket Loader ignore individual scripts by adding the data-cfasync="false" attribute to the relevant script tag:
<script data-cfasync="false" src="/javascript.js"></script>
Rocket Loader will still optimize the loading of all other scripts on the page.
:::note
If Rocket Loader is only impacting a specific page, use a Configuration Rule to exclude that page by URL.
:::
Limitations
- Adding this attribute within JavaScript will not work if you wish to exclude the script from Rocket Loader.
- If the script you want Rocket Loader to ignore has dependency on other JavaScript(s) on the page, those dependencies must also have the
data-cfasync="false"attribute. - The
data-cfasyncattribute must be added before thesrcattribute. - Rocket Loader will recognize the tag when either single or double quotes are placed around the attribute value.
Rocket Loader
import { DirectoryListing, Render } from "~/components";
Rocket Loader prioritizes your website's content (text, images, fonts, and more) by deferring the loading of all of your JavaScript until after rendering.
This type of loading (known as asynchronous loading) leads to earlier rendering of your page content. Rocket Loader handles both inline and external scripts, while maintaining order of execution. Cloudflare will detect incompatible browsers and disable Rocket Loader.
On pages with JavaScript, this results in a much faster loading experience for your users and improves the following performance metrics:
- Time to First Paint (TTFP)
- Time to First Contentful Paint (TTFCP)
- Time to First Meaningful Paint (TTFMP)
- Document Load
How to
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Yes | Yes | Yes | Yes |
Limitations
Some of Cloudflare's optional features, including Rocket Loader and Email Obfuscation, use non standard tags that fail strict HTML validation via tools like w3.org. These failures do not correlate to issues for your site visitors.
If you observe JavaScript or jQuery issues for your website, disable Rocket Loader and retest your website.
Content encoding issues
If you are noticing any encoding errors with your HTML pages, we recommend verifying that the impacted pages are explicitly setting the correct charset in the Content-Type header from your origin for all text/html pages, for example Content-Type: text/html; charset=utf-8. This is particularly important if you are not using UTF-8 encoding standard for characters. Alternatively you can set the correct charset within the HTML.
If you believe these settings are correct, please inform us. You can find more information in setting the HTTP charset parameter and in HTML charset attribute.
Alternatively, you can use a Configuration Rule to disable features that rewrite HTML. This will send the content as-is to the browser.
You also have the option to turn off these features site-wide within the dashboard:
- Email Obfuscation, located in the Security > Settings section.
- Rocket Loader, located in Speed > Settings > Content Optimization section.
- Automatic HTTPS Rewrites, located in the SSL/TLS > Edge Certificates section.
Misconfiguring the Content-Type or charset within HTML, or leaving them unspecified can lead to unintended consequences. This can disrupt the intended content presentation, resulting in disorganized rendering and potentially unclear characters. Properly configuring these elements ensures consistent and accurate interpretation, correct HTML modifications, and accurate rendering for browsers. This creates a seamless user experience and aligns with best practices in web development.
Turn off Auto Minify via API
If your site is still using deprecated features for Auto Minify, turn off Auto Minify via API.
Before you begin
You will need an API token with the following permissions:
- Zone > Zone Settings > Edit
- Zone > Zone Settings > Read
(Optional) Check zone status
To check your zone's Auto Minify status, send a GET request to the /zones/{zone_id}/settings/minify endpoint.
curl "https://api.cloudflare.com/client/v4/zones/{zone_id}/settings/minify" \
--header "Authorization: Bearer <API_TOKEN>"
{
"result": {
"id": "minify",
"value": { "css": "off", "html": "off", "js": "off" },
"modified_on": null,
"editable": true
},
"success": true,
"errors": [],
"messages": []
}
If any of the values in the highlighted line are "on", then you need to turn them off.
Turn off Auto Minify using the API
To turn off Auto Minify for your zone, send a PATCH request to the /zones/{zone_id}/settings/minify endpoint. The value for success in the response should be true.
curl --request PATCH \
"https://api.cloudflare.com/client/v4/zones/{zone_id}/settings/minify" \
--header "Authorization: Bearer <API_TOKEN>" \
--header "Content-Type: application/json" \
--data '{ "value": { "css": "off","html": "off","js": "off" } }'
{
"result": {
"id": "minify",
"value": { "js": "off", "css": "off", "html": "off" },
"modified_on": "2024-11-15T19:32:20.882640Z",
"editable": true
},
"success": true,
"errors": [],
"messages": []
}
Troubleshooting
import { DirectoryListing } from "~/components"
Image optimization
import { DirectoryListing } from "~/components"
Cloudflare Mirage (deprecated)
:::caution[Deprecation notice] Mirage was deprecated on September 15, 2025 and is no longer available.
As an alternative, Cloudflare recommends using lazy loading and responsive images to optimize image performance for all devices. :::
What was Mirage?
Cloudflare Mirage was a mobile image optimization feature that reduced bandwidth usage and accelerated image loading on slow mobile connections and HTTP/1.
Mirage worked by:
- Replacing images with low-resolution thumbnails bundled together into one file.
- Acting as a lazy loader, deferring loading of higher-resolution images until they become visible.
Why was it deprecated?
Modern web standards and browser capabilities have evolved to provide native support for many of Mirage's features:
- Native lazy loading with the
loading="lazy"HTML attribute. - Responsive images using
srcsetand<picture>elements. - HTTP/2 and HTTP/3 providing better performance.
- Improved mobile networks reducing the need for aggressive optimization.
Migration path
Instead of Mirage, use:
- Polish - Seamlessly optimizes images for all browsers, not only mobile, and keeps images at full resolution.
- Image Resizing - Combined with
loading="lazy"andsrcsetHTML attributes, provides modern responsive image delivery. - Lazy loading guide - Learn how to implement native lazy loading.
- Responsive images guide - Create images that adapt to different devices.
Troubleshooting
import { DirectoryListing } from "~/components"
Image optimization on optimized images
Cloudflare's image optimization features will likely not help much if you are already optimizing your images in some way (Smush.it, etc.).
Cloudflare recommends not activating other services on top of Cloudflare, because this setup can lead to unexpected outcomes and potential issues.
Troubleshoot missing images
If images are missing from your website, other Cloudflare features may be interfering with those images.
To troubleshoot:
-
Perform one of the following actions:
- Purge cache for the URL of the missing image file.
- Temporarily pause Cloudflare.
- Disable Rocket Loader.
-
Retest the image load in a private browser tab.
-
If the issue is not fixed, try another of the actions suggested in Step 1.
0-RTT Connection Resumption
import { TabItem, Tabs, DashButton } from "~/components";
Zero round trip time resumption (0-RTT) improves performance for clients who have previously connected to your website, reducing latency for returning users. This feature is especially beneficial for those who frequently visit your application or connect over mobile networks.
We support 0-RTT for GET, HEAD, and OPTIONS requests, facilitating faster responses for these types of requests. Note that 0-RTT is not supported for POST requests.
In line with 0-RTT standards, we add the Early-Data: 1 header to 0-RTT requests, which allows origin servers to identify when a request has used 0-RTT resumption. Customers should be able to see the Early-Data: 1 header for any 0-RTT requests connecting to their origin.
For more information on 0-RTT, including its functionality and potential limitations, refer to our blog post.
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Yes | Yes | Yes | Yes |
Enable 0-RTT Connection Resumption
By default, 0-RTT Connection Resumption is not enabled on your Cloudflare application.
To enable 0-RTT Connection Resumption in the dashboard:
-
In the Cloudflare dashboard, go to the Speed > Settings page.
-
Go to the Protocol Optimization tab and under 0-RTT Connection Resumption, switch the toggle to On.
To adjust your 0-RTT Connection Resumption settings with the API, send a PATCH request with 0rtt as the setting name in the URI path, and the value parameter set to "on" or "off".
:::note The 0-RTT Connection Resumption is only established between the client and Cloudflare. It does not extend to the origin server. :::
Security considerations
0-RTT reduces latency by allowing requests before the connection handshake completes. By design, these requests can be replayed and, for QUIC, processed before the client source IP address is validated. Before enabling 0-RTT, evaluate whether these risks are compatible with your security requirements.
Enhanced HTTP/2 Prioritization
import { TabItem, Tabs } from "~/components";
With Enhanced HTTP/2 Prioritization, Cloudflare delivers resources in the optimal order for the fastest experience across all browsers. It also supports control of content delivery when used in conjunction with Workers.
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | No | Yes | Yes | Yes |
How it works
The speed of loading web content, from the user’s perspective, is dependent on the order in which the resources load. With HTTP/2, by default, Cloudflare will follow the order requested by the browser. This ordering varies from browser to browser, causing a significant difference in performance.
With Enhanced HTTP/2 Prioritization, Cloudflare overrides the default browser behavior to optimize the order of resource delivery, independent of the browser. The greatest improvements will be experienced by visitors using Safari and Edge browsers.
For more details, refer to the introductory blog post.
Enable Enhanced HTTP/2 Prioritization
To enable Enhanced HTTP/2 Prioritization in the Cloudflare dashboard:
- Log into the Cloudflare dashboard.
- Select your account and zone.
- Go to Speed > Settings.
- Go to Protocol Optimization.
- For Enhanced HTTP/2 Prioritization, switch the toggle to On.
To enable Enhanced HTTP/2 Prioritization using the Cloudflare API, send a PATCH request with h2_prioritization as the setting name in the URI path, and the value parameter set to "on".
HTTP/2 to Origin
import { Details, Render, APIRequest, DashButton, } from "~/components";
A protocol is a set of rules governing the exchange or transmission of data between devices. One of the most important protocols that run on the human-computer interaction layer, where applications can access the network services, is HTTP (Hypertext Transfer Protocol).
HTTP is a well established protocol that has several versions, and each version adds features that improve performance over the older one. HTTP/1.1 and HTTP/2 are widely deployed on the Internet today. HTTP/1.1 has been around for more than a decade, but in 2015 the IETF (Internet Engineering Task Force) introduced HTTP/2, which introduces several features to reduce page load times. To know more about the differences between HTTP/1.1 and HTTP/2, please refer to HTTP/2 versus HTTP/1.1.
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Yes | Yes | Yes | Yes |
Disable HTTP/2 to Origin
At Cloudflare, HTTP/2 connection to the origin is enabled by default.
If you wish to disable HTTP/2 to Origin, you can follow these steps:
-
In the Cloudflare dashboard, go to the Speed > Settings page.
-
Go to the Protocol Optimization tab and under HTTP/2 to Origin set the toggle to Off.
Connection multiplexing
Cloudflare supports HTTP/2 multiplexing from its global edge network to your origin servers. Instead of opening a new TCP connection for every incoming request, multiple HTTP/2 streams share a single long-lived TCP connection. This significantly reduces the cost of connection setup and teardown, improving efficiency and performance between Cloudflare and your origin.
By pooling many requests into fewer TCP connections, Cloudflare lowers the number of active connections your origin must maintain — particularly valuable for backends sensitive to connection overhead or resource limits.
How it works
When a new request arrives, Cloudflare attempts to reuse an existing HTTP/2 connection to the origin:
- If the connection has not reached its concurrent stream limit, Cloudflare multiplexes the request over that same connection.
- If the stream limit has been reached, Cloudflare opens a new TCP connection as needed.
Connections are kept alive and reused until they become idle or hit their concurrency limit.
Connection lifecycle
-
Connection reuse: Cloudflare maintains persistent (keep-alive) TCP connections to your origin. Reuse continues until the HTTP/2 stream limit is reached or the connection goes idle.
-
Idle timeout (900s): If a connection remains idle (no active streams) for 900 seconds, Cloudflare closes it. Attempting to reuse a closed connection may result in a
520error. -
Keep-alives: Cloudflare sends periodic TCP keep-alives to detect unresponsive origins. After two unanswered probes, the connection is reset.
- First probe after ~30 seconds of inactivity
- Second probe after 15 seconds
-
Connection tear-down: Connections may also close due to:
- Load balancing decisions
- Data center or node maintenance
- Reaching the maximum concurrency limit
- Origin or intermediary network closing idle connections
Benefits
| Advantage | Description |
|---|---|
| Fewer TCP handshakes | Multiple requests share a single long-lived TCP connection, minimizing connection churn. |
| Lower latency | Eliminates repeated TCP/TLS handshakes, reducing round-trip delays for new requests. |
| Reduced origin load | Fewer concurrent connections for the origin to manage, easing load on resource-constrained systems. |
| Adaptive scaling | During surges (for example, failovers), Cloudflare reuses available streams first, then opens new connections as needed. |
Default behavior by plan
| Plan | Default State | Max concurrent streams per connection | Configurable? |
|---|---|---|---|
| Free / Pro / Business | Enabled by default | 200 | No |
| Enterprise | Disabled by default (1 stream per connection) | 1–200+ | Yes |
- Free/Pro/Business: Multiplexing is automatically enabled. Each connection supports up to 200 concurrent streams.
- Enterprise: Multiplexing starts effectively disabled (1 stream). You can enable and configure concurrency per zone (up to 200+ concurrent streams).
Configuration
Connection multiplexing is enabled by default on Free, Pro and Business zones and uses up to 100 concurrent streams by default. Enterprise plans can explicitly configure the maximum number of concurrent streams (often called the “multiplexing ratio”) for a zone in the dashboard or via API.
- Log in to the Cloudflare dashboard and select your account.
- Choose the domain that will use HTTP/2 to Origin.
- Select Speed > Optimization.
- Open the Protocol Optimization tab.
- Under HTTP/2 to Origin, select Configure and adjust the stream settings as needed.
<APIRequest path="/zones/{zone_id}/settings/origin_h2_max_streams" method="PATCH" json={{ value: 100, }} />
Refer to the API documentation for more information.
resource "cloudflare_zone_setting" "example" {
zone_id = "<ZONE_ID>"
setting_id = "origin_h2_max_streams"
value = 50
}
:::note If your origin does not support multiplexing, enabling HTTP/2 to origin may result in 5xx errors, particularly 520s.
During the HTTP/2 handshake, our edge reads the SETTINGS_MAX_CONCURRENT_STREAMS that your origin advertises, and it will respect that lower limit if your origin is configured with a stricter concurrency cap than Cloudflare's setting. This allows you to control concurrency on a per-origin basis, while still benefiting from Cloudflare's multiplexing framework. :::
Timeouts and error codes
| Condition | Default / Range | Error code | Description |
|---|---|---|---|
| Proxy Read Timeout | 125s (up to 6000s for Enterprise) | 524 |
Origin took too long to respond. |
| Proxy Idle Timeout | 900s (fixed) | 520 |
Connection closed due to idleness. |
| TCP Keep-Alive Interval | 30s initial, 15s between probes | 520 |
After two missed probes, Cloudflare resets the connection. |
| TCP Handshake Timeout | 19s | 522 |
Origin did not complete the SYN handshake. |
| TCP ACK Timeout | 90s | 522 |
Origin stopped acknowledging data. |
Common scenarios
Failover events
When traffic shifts suddenly (for example, during origin failover), Cloudflare reuses active connections where possible. If concurrency limits are reached, it opens new ones. Active connection counts may spike temporarily, but overall total connections remain lower than without multiplexing.
Long-Lived or idle requests
- If your requests exceed 125 seconds (for example, streaming), increase the Proxy Read Timeout (Enterprise only).
- Origins that close connections faster than 900 seconds may experience connection churn, but Cloudflare automatically reestablishes new connections as needed.
Potential 5xx errors
Some 5xx errors, like 520 or 522, may be related to idle timeouts or unreachable origins. If concurrency is set too high for an underpowered origin, bursts of simultaneous requests can overwhelm it and lead to stream resets or short spikes of 5xx errors. Enterprise customers who encounter this can ask their Cloudflare account team or support to lower the concurrency limit, which reduces how many requests are sent to the origin at the same time and helps prevent overload.
FAQ
Does Cloudflare use a fixed multiplexing ratio?
Free, Pro, and Business plans use 200 concurrent streams per connection. Enterprise users can configure between 1–200+ streams.
How does Cloudflare scale connections during spikes or failovers?
Cloudflare first reuses existing keep-alive connections. If they reach concurrency limits, new connections are opened as needed. Even during surges, total connection count is typically lower than without multiplexing.
What if my backend is sensitive to parallel requests?
Enterprise users can lower the concurrency limit. Cloudflare also honors your origin's SETTINGS_MAX_CONCURRENT_STREAMS, allowing your server to enforce stricter limits. Cloudflare's CDN also provides Cache Locking, which helps avoid multiple parallel requests to your origin during revalidation. Refer to Revalidation for more information.
Can I gradually roll out higher concurrency?
Yes. You can adjust your origin's HTTP/2 settings or Cloudflare's zone setting incrementally to increase concurrency safely.
From where does Cloudflare connect to my origin?
Cloudflare operates a flat anycast network. Any data center may connect directly to your origin — there is no L1/L2 hierarchy. Origin connections may come from multiple data centers worldwide.
Does Cloudflare prewarm connections to origins?
No. Connections are created on demand and reused where possible. There is no persistent idle pool.
How are idle connections managed?
Idle connections are closed after 900 seconds of inactivity. They are not reopened proactively; new connections are created as traffic resumes.
Can Cloudflare close active TCP connections?
Only if the origin closes them, a network error occurs, or Cloudflare performs maintenance or load redistribution. There is no hard maximum lifetime for active connections.
Protocol compatibility
Note that if the origin does not support HTTP/2, Cloudflare will initiate an HTTP/1.1 connection. We connect to servers who announce support of HTTP/2 connections via ALPN.
If you are unsure if your server supports HTTP/2, we suggest checking your origin server's documentation or using a testing tool for HTTP/2 implementation (for example, h2spec).
HTTP/2
import { TabItem, Tabs } from "~/components";
HTTP/2 uses the TCP transport protocol and TLS to secure communications and improves page load times.
:::note
For more background on HTTP/2, visit the Learning Center.
:::
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Yes | Yes | Yes | Yes |
| Can customize | No | Yes | Yes | Yes |
Enable HTTP/2
HTTP/2 is enabled by default for all plans (though it does require an SSL certificate at Cloudflare’s edge network).
Disable HTTP/2
Domains on Free plans cannot disable Cloudflare's HTTP/2 setting.
To disable HTTP/2 in the dashboard:
- Log into the Cloudflare dashboard.
- Select your account and zone.
- Go to Speed > Settings.
- Go to Protocol Optimization.
- For HTTP/2, switch the toggle to Off.
To disable HTTP/2 with the API, send a PATCH request with http2 as the setting name in the URI path, and the value parameter set to "off".
ERR_HTTP2_PROTOCOL_ERROR
Requests proxied by Cloudflare may result in an error for visitors with the error code ERR_HTTP2_PROTOCOL_ERROR visible in the Developer Tools Console. These errors are usually due to an issue on the origin web server configuration, but might only materialize when requests are proxied by Cloudflare depending on the client browser's behavior. Some possible causes are:
Malformed HTTP response headers
The origin web server may be sending improperly formatted HTTP response headers.
Resolution
Make a request directly to your origin web server and inspect its HTTP response headers for anomalies. Make sure that the field values respect the following requirements:
Compression issues
Examples of compression issues include the origin web server serving gzip encoded compressed content but failing to update the Content-Length header, or the origin web server serving broken gzip compressed content.
Resolution
You can try to disable compression at your origin web server and rely on Cloudflare to compress content.
You can also review your origin server's compression settings to make sure the compression is working as expected.
HTTP/3 (with QUIC)
import { TabItem, Tabs } from "~/components";
HTTP/3 uses QUIC, which is a secure-by-default transport protocol. HTTP/3 improves page load times in a similar way to HTTP/2. However, the QUIC transport protocol solves TCP's head-of-line blocking problem, meaning that performance over lossy networks can be better.
:::note
For more background on HTTP/3, visit the Learning Center.
:::
:::note
This setting is for connection between the user and Cloudflare. HTTP/3 connection to the origin is not yet supported.
:::
Availability
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Availability | Yes | Yes | Yes | Yes |
Enable HTTP/3
HTTP/3 is available to all plans (though it does require an SSL certificate at Cloudflare’s edge network).
To enable HTTP/3 in the dashboard:
- Log into the Cloudflare dashboard.
- Select your account and zone.
- Go to Speed > Settings.
- Go to Protocol Optimization.
- For HTTP/3, switch the toggle to On.
To enable HTTP/3 with the API, send a PATCH request with http3 as the setting name in the URI path, and the value parameter set to "on".
Protocol optimization
import { DirectoryListing } from "~/components"
Enhanced HTTP/2 Prioritization negatively affects iOS/Safari devices
Occasionally, Enhanced HTTP/2 Prioritization can negatively affect the experience of visitors using Safari on macOS or any browser on iOS.
These visitors may notice not being able to load the site properly, such as images not displaying or content taking too long to load.
Solution
If visitors using using Safari on macOS or any browser on iOS are experiencing issues with your site loading properly, try disabling Enhanced HTTP/2 Prioritization.
:::note
Sometimes, HTTP/2 will cause Enhanced HTTP/2 Prioritization to be re-enabled automatically.
If you notice this happening, also disable HTTP/2.
:::
Troubleshooting
import { DirectoryListing } from "~/components"
Troubleshoot protocol issues
This guide covers common HTTP/2 and HTTP/3 issues, including origin incompatibility, multiplexing errors, and browser errors, with steps to diagnose and resolve them.
H2 to Origin - Origin incompatibility
- The origin's
max_concurrent_streamsis negotiated during the handshake process. - If a
GOAWAY(0)is received, it is likely due to a server restart or another reason causing the server to refuse new streams. - For more information, refer to RFC 9113 - SETTINGS_MAX_CONCURRENT_STREAMS.
H2 Multiplexing - Origin incompatibility/issues
- Multiplexing issues can arise due to incorrect server configurations.
- Use netlogs to identify
SETTINGS_MAX_CONCURRENT_STREAMSviolations or unexpectedGOAWAYframes. - For more information, refer to Stream Concurrency Issues.
Generic browser errors
Common browser errors include:
ERR_HTTP2_PROTOCOL_ERRORERR_HTTP3_PROTOCOL_ERRORERR_QUIC_PROTOCOL_ERROR
These errors do not necessarily indicate a protocol-level issue. Follow these steps:
- Attempt reproduction using HTTP/1.1.
- If the issue persists in HTTP/1.1, address the underlying error before testing HTTP/2 or HTTP/3.
- If the issue does not persist, analyze netlogs for HTTP/2 or HTTP/3-specific issues.
For more information, refer to Chromium URL Request Header.
Chrome stalls or fails only on HTTP/3
If the issue reproduces only in Chrome over HTTP/3 and disappears when HTTP/3 is disabled, the problem may be related to a browser-side QUIC handling issue rather than your origin server. This is a known Chrome issue (crbug.com/41161335) — Cloudflare's QUIC implementation is not the cause.
Symptoms can include:
- Large downloads stall unexpectedly.
- Pages with many concurrent requests hang for one to three minutes and then fail.
- Chrome reports
ERR_QUIC_PROTOCOL_ERRORorERR_HTTP3_PROTOCOL_ERRORafter the connection stops making progress. - Issue does not reproduce in Firefox or Safari.
- Issue resolves after disabling QUIC in
chrome://flags.
How to isolate the issue
- Temporarily disable HTTP/3 for the zone.
- Test the same request again over HTTP/2.
- If the issue disappears over HTTP/2, capture a NetLog for Chrome and compare the behavior.
Test immediately: In Chrome, go to chrome://flags, search for "QUIC", set it to Disabled, then relaunch Chrome.
Resolution
If the issue is limited to specific hostnames, you can apply a more targeted workaround: create a Response Header Modification Transform Rule to remove the Alt-Svc header for the affected hostname.
- In the Cloudflare dashboard, go to the Rules Overview page.
- Select Create rule > Response Header Transform Rule.
- Set the matching expression to your hostname:
(http.host eq "example.com"). - Under Modify response header, select Remove and enter
Alt-Svcas the header name.
This forces Chrome to use HTTP/2 for that hostname without disabling HTTP/3 globally. However, proxied hostnames can also advertise HTTP/3 through generated HTTPS records, so disabling HTTP/3 for the zone is the most reliable way to force HTTP/2 while you troubleshoot.
After changing Alt-Svc, remember that browsers may cache the advertised alternative service for up to 24 hours.
Troubleshooting
import { ResourcesBySelector } from "~/components"
The following topics are useful for troubleshooting Speed issues.
<ResourcesBySelector directory="speed" types={["faq", "troubleshooting"]} filterables={["pcx_content_type"]} showDescriptions={false} />
Troubleshooting a slow website
import { Details, DashButton, Tabs, TabItem, GlossaryTooltip } from "~/components";
This guide helps you identify and resolve performance issues affecting your website. It starts with basic diagnostics and progresses to advanced troubleshooting techniques.
Before you start: Verify traffic goes through Cloudflare
Before troubleshooting performance, confirm that your traffic is actually going through Cloudflare. If requests bypass Cloudflare, the issue is not related to Cloudflare and this guide will not help.
Check for the cf-ray header
Every response served through Cloudflare includes a cf-ray header. Check for this header:
If you see a cf-ray header (for example, cf-ray: 8a1b2c3d4e5f6g7h-SJC), your traffic is going through Cloudflare. If not, check your DNS configuration.
Verify DNS is pointing to Cloudflare
Your domain must resolve to Cloudflare IP addresses for traffic to be proxied:
```bash dig +short www.example.com ``` ```powershell Resolve-DnsName -Name www.example.com | Select-Object -ExpandProperty IPAddress ```The returned IP addresses should be Cloudflare IPs. If they point directly to your origin server, your DNS records are not proxied.
To fix this:
- Go to the Cloudflare dashboard.
- Find the DNS record for the slow hostname.
- Ensure the Proxy status is set to Proxied (orange cloud icon).
:::note If your DNS records are set to DNS only (gray cloud), Cloudflare does not proxy the traffic and cannot improve performance. The request goes directly to your origin server. :::
Gather information about the slow requests
Performance issues are easier to solve when you can pinpoint exactly what is slow. Start by gathering the following information:
- Identify specific slow requests - Determine which URLs, assets, or API endpoints are slow.
- Measure the slowness - Quantify the delay (for example, "this image takes 5 seconds to load").
- Reproduce the issue - Confirm the slowness is consistent and not a one-time occurrence.
Step 1: Use Observatory to analyze performance
Observatory provides synthetic tests and real user monitoring (RUM) data to assess your website's performance.
RUM is particularly important as these metrics are captured from your actual visitors' browsers so it's an objective view of how they are experiencing your website, rather than lab data, which is typically more detailed (useful for debugging) but doesn't always correlate with the devices or connectivity real people have access to.
Run a speed test
-
Go to the Cloudflare dashboard.
-
Select Observatory.
-
Enter the URL you want to test and select Run test.
Understand the results
Observatory reports key metrics:
| Metric | What it measures | Target |
|---|---|---|
| Largest Contentful Paint (LCP) | Time until the largest visible element loads | Under 2.5 seconds |
| First Contentful Paint (FCP) | Time until the first content appears | Under 1.8 seconds |
| Cumulative Layout Shift (CLS) | Visual stability during page load | Under 0.1 |
| Time to First Byte (TTFB) | Time until the first byte of response is received | Under 800 ms |
| Total Blocking Time (TBT) | Time the main thread is blocked | Under 200 ms |
Real User Monitoring reports similar metrics but you'll see Interaction to Next Paint (INP) in place of Total Blocking Time (TBT).
TBT only measures during page load but INP measures every interaction real visitors make with your website.
Enable recommended optimizations
Based on Observatory results, enable relevant Speed optimizations:
- Brotli compression - Compress responses for faster transfer
- Early Hints - Preload critical resources
- HTTP/2 and HTTP/3 - Use modern protocols with multiplexing, allowing multiple requests over a single connection instead of opening separate connections for each asset
- Image optimization - Automatically optimize and resize images
- Rocket Loader - Defer loading of JavaScript to improve paint times
Step 2: Identify slow resources
If Observatory and RUM data point to specific issues, use browser developer tools to investigate individual resources.
Use browser developer tools
- Open your browser's developer tools.
- Go to the Network tab.
- Reload the page and observe which requests take the longest.
- Sort by Time or Duration to identify the slowest assets.
- Note the specific URLs of slow resources.
Look for:
- Large images or videos
- Slow API calls
- Third-party scripts
- Render-blocking resources
Step 3: Analyze origin performance
If your website is slow, the issue may be at your origin server. Use Origin Analytics to understand how your origin is performing.
Check origin response times
In the Cloudflare dashboard:
-
Go to Speed > Origin Analytics.
-
Review the Origin Response Time metrics.
-
Look for patterns in slow responses (specific paths, times of day, or geographic regions).
High origin response times indicate your origin server is struggling. Consider:
- Upgrading your hosting plan
- Optimizing database queries
- Implementing server-side caching
For a full guide on available metrics, diagnostic flows, and how to interpret origin status codes, refer to Origin Analytics.
Check for slow Workers
If your zone has Cloudflare Workers deployed, they execute on every matching request and add to the total response time. A slow Worker is a common cause of high TTFB.
To check if Workers are affecting performance:
- Go to Workers & Pages in the Cloudflare dashboard.
- Review which Workers are deployed on your zone.
- Check the Analytics for each Worker to see execution times.
- Temporarily disable Workers to isolate whether they are causing the slowness.
If a Worker is slow, review its code for:
- Slow external API calls or
fetch()requests - Inefficient loops or data processing
- Missing
awaitstatements causing sequential instead of parallel execution
Step 4: Measure performance from the command line
For detailed timing metrics on specific requests, use command-line tools to measure performance.
Basic performance test
```bash curl -w "\n\nDNS Lookup: %{time_namelookup}s\nTCP Connect: %{time_connect}s\nTLS Handshake: %{time_appconnect}s\nTime to First Byte: %{time_starttransfer}s\nTotal Time: %{time_total}s\n" -o /dev/null -s https://www.example.com/slow-asset.jpg ``` ```powershell $url = "https://www.example.com/slow-asset.jpg" try { $timing = Measure-Command { $response = Invoke-WebRequest -Uri $url -ErrorAction Stop } Write-Host "Total Time: $($timing.TotalSeconds)s" Write-Host "Status: $($response.StatusCode)" } catch { if ($_.Exception.Response) { $statusCode = $_.Exception.Response.StatusCode.value__ Write-Host "Error Status: $statusCode" } Write-Host "Error: $($_.Exception.Message)" } ```Example output (bash):
DNS Lookup: 0.025s
TCP Connect: 0.045s
TLS Handshake: 0.120s
Time to First Byte: 0.350s
Total Time: 1.250s
Understand the metrics
The curl timing breakdown shows the following:
| Metric | Description | High value indicates |
|---|---|---|
| DNS Lookup | Time to resolve the domain name | DNS issues or slow resolver |
| TCP Connect | Time to establish TCP connection | Network latency or server distance |
| TLS Handshake | Time to complete SSL/TLS negotiation | Certificate chain issues or slow server |
| Time to First Byte (TTFB) | Time until first response byte | Slow origin processing |
| Total Time | Complete request duration | Large file size or slow transfer |
Test from different locations
To test from different geographic locations, use online tools like:
Step 5: Investigate caching
Caching is one of the most effective ways to improve website performance. When content is cached, Cloudflare serves it directly from a data center close to your visitors, eliminating the round trip to your origin server. This can reduce response times from hundreds of milliseconds to just a few milliseconds.
Uncached content must travel from the visitor to Cloudflare, then to your origin server, and back again. Use Cache Analytics to understand your cache performance and identify opportunities to cache more content.
Check if assets are cached
Check the cache status of a specific asset:
```bash curl -s -D- -o /dev/null https://www.example.com/asset.jpg | grep -i "cf-cache-status" ``` ```powershell (Invoke-WebRequest -Uri "https://www.example.com/asset.jpg" -Method Head).Headers["cf-cache-status"] ```Possible values:
| Status | Meaning | Action |
|---|---|---|
| HIT | Served from Cloudflare cache | No action needed |
| MISS | Not in cache, fetched from origin | May need cache rules |
| DYNAMIC | Not eligible for caching | Create a cache rule if static |
| BYPASS | Cache intentionally bypassed | Review cache rules |
| EXPIRED | Cached copy was stale | Increase Edge TTL |
| REVALIDATED | Cloudflare confirmed content is current | Increase Edge TTL |
For a complete list, refer to Cloudflare cache responses.
Use Cache Analytics
-
Go to the Cloudflare dashboard.
-
Review the Cache Performance section.
-
Filter by Cache status equals MISS or DYNAMIC to identify uncached content.
Investigate why static content is not cached
If static assets (images, CSS, JavaScript) show a cache status of DYNAMIC, BYPASS, or MISS, investigate the cause:
| Symptom | Likely cause | Solution |
|---|---|---|
DYNAMIC status |
Content type not in default file extensions | Create a Cache Rule to cache the content |
DYNAMIC status |
Origin sends Cache-Control: private or no-store |
Create a Cache Rule to override origin cache control |
BYPASS status |
A Cache Rule is bypassing cache | Review your Cache Rules configuration |
MISS on every request |
Response includes Set-Cookie header |
Configure your origin to not set cookies on static assets, or use a Cache Rule to ignore cookies |
MISS with query strings |
Different query strings create different cache entries | Use a custom cache key to ignore or normalize query strings |
Cache additional static content
By default, Cloudflare only caches certain file extensions. To cache additional static content:
- Go to Caching > Cache Rules.
- Create a rule to cache specific content.
- Set appropriate Edge TTLs.
:::caution Be careful when caching HTML or API responses. These often contain personalized or dynamic content that should not be cached. Only cache content you are certain is static. :::
Use Cloudflare Trace to debug cache rules
If your cache rules are not applying as expected, use Rules simulator to simulate a request and see exactly which rules match. Trace shows you how your Cloudflare configurations (including cache rules, page rules, and other settings) would affect a specific URL.
This is particularly useful when:
- A cache rule should be caching content but the response shows
DYNAMICorBYPASS - You are unsure which rule is taking precedence
- You want to test a "what-if" scenario before making changes
Step 6: Diagnose network issues
If curl shows high TCP Connect or TLS Handshake times, the issue may be network-related rather than application-related.
Test your Internet connection
Visit speed.cloudflare.com to test:
- Download and upload speeds
- Latency (ping)
- Jitter
- Packet loss
Poor results indicate issues with your local network or ISP.
Run MTR from your location to Cloudflare
MTR combines traceroute and ping to show latency and packet loss at each network hop.
mtr -rw www.example.com
Download WinMTR and run it with your domain as the target.
Look for:
- High latency at specific hops (indicates slow network segments)
- Packet loss (indicates network congestion or issues)
- Timeouts (may indicate firewalls or routing issues)
For more details, refer to How to read MTR.
Run MTR from your origin to Cloudflare
If you have access to your origin server, run MTR from the origin to a Cloudflare IP address to test the network path between your origin and Cloudflare.
mtr -rw 104.16.132.229
High latency or packet loss on this path affects all requests that miss the cache.
Step 7: Understand network routing
How requests are routed to Cloudflare data centers can significantly impact performance.
Identify which data center serves your requests
Add /cdn-cgi/trace to your domain to see which Cloudflare data center is serving your requests:
The colo field shows the three-letter airport code of the serving data center (for example, colo=SJC for San Jose). You can also check the cf-ray response header. The three-letter code at the end of the value identifies the data center that processed the request. You can find the full list of Cloudflare data centers and their codes on the Cloudflare status page.
Why routing matters
When a request reaches Cloudflare:
- The request is routed to a Cloudflare data center based on anycast routing. This is not always the data center closest geographically.
- If the content is cached, it is served immediately.
- If not cached, Cloudflare fetches from your origin server.
If your origin server is geographically distant from the Cloudflare data center serving your users, uncached requests will be slow.
Troubleshoot unexpected routing
Requests may be sent to data centers that are not the closest geographically. Cloudflare continuously adds capacity to its global network and improves its automated traffic engineering systems to manage congestion and other network events. Cloudflare aims to serve traffic from the closest location for the best performance, but reliability takes priority.
When performance and reliability conflict, Cloudflare's systems prioritize a stable connection over a local one.
Cloudflare does not pick a data center for each visitor. The visitor's Internet service provider (ISP) decides which Cloudflare data center receives the request, based on its own routing and peering policies. These policies do not always favor the geographically closest location. For example, an ISP may send traffic to a distant city where it has a direct connection with Cloudflare instead of a nearby one where it does not.
Cloudflare's traffic engineering can influence these paths across the network as a whole, but it cannot direct individual visitors to a specific data center. Data center selection cannot be configured per zone, per account, or by support request.
For more details, refer to Cloudflare traffic not being sent to the geographically closest data center.
Common causes of unexpected routing:
| Symptom | Explanation |
|---|---|
| Requests route to a distant data center | Cloudflare traffic engineering for reliability, or ISP routing decisions |
cf-ray shows a different location than a traceroute |
Traffic can enter Cloudflare's network at one location and be processed at another |
| Routing changes between requests | Normal behavior - routing adapts to network conditions or ISP load balancing |
| Consistent routing to a distant region | ISP peering location or Cloudflare capacity management |
| High latency despite nearby data center | Network congestion on the path |
Solutions for origin distance
Consider these solutions based on your needs:
| Solution | Description | Best for |
|---|---|---|
| Improve cache hit ratio | Cache more content to reduce origin fetches | All sites |
| Tiered Cache | Use upper-tier data centers to reduce origin requests | Sites with global traffic |
| Argo Smart Routing | Route traffic over faster network paths | Sites with slow origin connections |
| Move origin closer | Deploy origin servers in multiple regions | Large-scale applications |
Enable Argo Smart Routing
Argo Smart Routing analyzes network conditions in real-time and routes traffic over the fastest paths, reducing latency by an average of 30%.
Argo Smart Routing is part of Smart Shield, which bundles multiple Cloudflare performance and reliability features.
To enable Argo Smart Routing:
- Go to the Cloudflare dashboard.
- Follow the Smart Shield setup guide to enable the feature.
Argo is particularly effective when:
- Your origin is far from your users
- Network congestion affects certain paths
- You need consistent performance globally
For detailed information about how Argo Smart Routing works, refer to the Argo Smart Routing documentation.
Contact Support if the problem persists
If you have followed the steps above and the performance issue persists, contact Cloudflare Support for assistance.
When contacting Support, provide as much evidence as possible to help diagnose the issue:
- HAR file - Generate a HAR file that captures the slow requests. This provides detailed timing information for every request.
- Observatory results - Share screenshots or links to your Observatory test results.
- RUM data - If you have Web Analytics enabled, share relevant metrics showing the performance issue.
- curl output - Include the timing breakdown from
curl --write-outfor the slow assets. - MTR results - If you suspect network issues, include MTR output from your location to the affected domain.
- Specific URLs - List the exact URLs that are slow, along with the expected and actual response times.
The more evidence you provide showing the slowness, the faster Support can identify and resolve the issue.
Related resources
- Observatory - Test and monitor website performance
- Cache Analytics - Analyze cache hit rates
- Cache Rules - Control what gets cached
- Argo Smart Routing - Optimize network routing
- Gathering information for troubleshooting - Collect diagnostic data