
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Tue, 07 Apr 2026 13:49:30 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Introducing Timing Insights: new performance metrics via our GraphQL API]]></title>
            <link>https://blog.cloudflare.com/introducing-timing-insights/</link>
            <pubDate>Tue, 20 Jun 2023 13:00:47 GMT</pubDate>
            <description><![CDATA[ If you care about the performance of your website or APIs, it’s critical to understand why things are slow.  Today we're introducing new analytics tools to help you understand what is contributing to "Time to First Byte" (TTFB) of Cloudflare and your origin ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1OastOs9G4xxa9jwrnKl3V/b50435c06e0316b8bf78cef88bce6888/xi31J0JmYNP5dcB-gEsTujRYG1gyFUsod_Fx7XPsjPwwxTQBIOFwTy9m0jPNQabe0bi5oUSwJHo5ubAq9rcAhgTXsqlTcoi9rpLM5pwoAwY-Yj8vuothGdHJHJbz.png" />
            
            </figure><p>If you care about the performance of your website or APIs, it’s critical to understand why things are slow.</p><p>Today we're introducing new analytics tools to help you understand what is contributing to "Time to First Byte" (TTFB) of Cloudflare and your origin. TTFB is just a simple timer from when a client sends a request until it receives the first byte in response. Timing Insights breaks down TTFB from the perspective of our servers to help you understand <i>what</i> is slow, so that you can begin addressing it.</p><p>But wait – maybe you've heard that <a href="/ttfb-time-to-first-byte-considered-meaningles/">you should stop worrying about TTFB</a>? Isn't Cloudflare <a href="/ttfb-is-not-what-it-used-to-be/">moving away</a> from TTFB as a metric? Read on to understand why there are still situations where TTFB matters.</p>
    <div>
      <h3>Why you may need to care about TTFB</h3>
      <a href="#why-you-may-need-to-care-about-ttfb">
        
      </a>
    </div>
    <p>It's true that TTFB on its own can be a misleading metric. When measuring web applications, metrics like <a href="https://web.dev/vitals/">Web Vitals</a> provide a more holistic view into user experience. That's why we offer Web Analytics and Lighthouse within <a href="/cloudflare-observatory-generally-available/">Cloudflare Observatory</a>.</p><p>But there are two reasons why you still may need to pay attention to TTFB:</p><p><b>1. Not all applications are websites</b>More than half of Cloudflare traffic is for APIs, and many customers with API traffic don't control the environments where those endpoints are called. In those cases, there may not be anything you can <a href="https://www.cloudflare.com/application-services/solutions/app-performance-monitoring/">monitor</a> or improve besides TTFB.</p><p><b>2. Sometimes TTFB is the problem</b>Even if you are measuring Web Vitals metrics like LCP, sometimes the reason your site is slow is because TTFB is slow! And when that happens, you need to know why, and what you can do about it.</p><p>When you need to know why TTFB is slow, we’re here to help.</p>
    <div>
      <h3>How Timing Insights can help</h3>
      <a href="#how-timing-insights-can-help">
        
      </a>
    </div>
    <p>We now expose performance data through our <a href="https://developers.cloudflare.com/analytics/graphql-api/">GraphQL Analytics API</a> that will let you query TTFB performance, and start to drill into what contributes to TTFB.</p><p>Specifically, customers on our Pro, Business, and Enterprise plans can now query for the following fields in the <code>httpRequestsAdaptiveGroups</code> dataset:</p><p><b>Time to First Byte</b> (edgeTimeToFirstByteMs)</p><p>What is the time elapsed between when Cloudflare started processing the first byte of the request received from an end user, until when we started sending a response?</p><p><b>Origin DNS lookup time</b> (edgeDnsResponseTimeMs)</p><p>If Cloudflare had to <a href="https://developers.cloudflare.com/dns/zone-setups/partial-setup/setup/">resolve a CNAME</a> to reach your origin, how long did this take?</p><p><b>Origin Response Time</b> (originResponseDurationMs)</p><p>How long did it take to reach, and receive a response from your origin?</p><p>We are exposing each metric as an average, median, 95th, and 99th percentiles (i.e. P50 / P95 / P99).</p><p>The <code>httpRequestAdaptiveGroups</code> dataset powers the <a href="https://dash.cloudflare.com/?to=/:account/:zone/analytics/traffic">Traffic</a> analytics page in our dashboard, and represents all of the HTTP requests that flow through our network. The upshot is that this dataset gives you the ability to filter and “group by” any aspect of the HTTP request.</p>
    <div>
      <h3>An example of how to use Timing Insights</h3>
      <a href="#an-example-of-how-to-use-timing-insights">
        
      </a>
    </div>
    <p>Let’s walk through an example of how you’d actually use this data to pinpoint a problem.</p><p>To start with, I want to understand the lay of the land by querying TTFB at various quantiles:</p>
            <pre><code>query TTFBQuantiles($zoneTag: string) {
  viewer {
    zones(filter: {zoneTag: $zoneTag}) {
      httpRequestsAdaptiveGroups(limit: 1) {
        quantiles {
          edgeTimeToFirstByteMsP50
          edgeTimeToFirstByteMsP95
          edgeTimeToFirstByteMsP99
        }
      }
    }
  }
}

Response:
{
  "data": {
    "viewer": {
      "zones": [
        {
          "httpRequestsAdaptiveGroups": [
            {
              "quantiles": {
                "edgeTimeToFirstByteMsP50": 32,
                "edgeTimeToFirstByteMsP95": 1392,
                "edgeTimeToFirstByteMsP99": 3063,
              }
            }
          ]
        }
      ]
    }
  }
}</code></pre>
            <p>This shows that TTFB is over 1.3 seconds at P95 – that’s fairly slow, given that <a href="https://web.dev/lcp/">best practices</a> are for 75% of pages to <i>finish rendering</i> within 2.5 seconds, and TTFB is just one component of LCP.</p><p>If I want to dig into why TTFB, it would be helpful to understand <i>which URLs</i> are slowest. In this query I’ll filter to that slowest 5% of page loads, and now look at the <i>aggregate</i> time taken – this helps me understand which pages contribute most to slow loads:</p>
            <pre><code>query slowestURLs($zoneTag: string, $filter:filter) {
  viewer {
    zones(filter: {zoneTag: $zoneTag}) {
      httpRequestsAdaptiveGroups(limit: 3, filter: {edgeTimeToFirstByteMs_gt: 1392}, orderBy: [sum_edgeTimeToFirstByteMs_DESC]) {
        sum {
          edgeTimeToFirstByteMs
        }
        dimensions {
          clientRequestPath
        }
      }
    }
  }
}

Response:
{
  "data": {
    "viewer": {
      "zones": [
        {
          "httpRequestsAdaptiveGroups": [
            {
              "dimensions": {
                "clientRequestPath": "/api/v2"
              },
              "sum": {
                "edgeTimeToFirstByteMs": 1655952
              }
            },
            {
              "dimensions": {
                "clientRequestPath": "/blog"
              },
              "sum": {
                "edgeTimeToFirstByteMs": 167397
              }
            },
            {
              "dimensions": {
                "clientRequestPath": "/"
              },
              "sum": {
                "edgeTimeToFirstByteMs": 118542
              }
            }
          ]
        }
      ]
    }
  }
}</code></pre>
            <p>Based on this query, it looks like the <code>/api/v2</code> path is most often responsible for these slow requests. In order to know how to fix the problem, we need to know <i>why</i> these pages are slow. To do this, we can query for the average (mean) DNS and origin response time for queries on these paths, where TTFB is above our P95 threshold:</p>
            <pre><code>query originAndDnsTiming($zoneTag: string, $filter:filter) {
  viewer {
    zones(filter: {zoneTag: $zoneTag}) {
      httpRequestsAdaptiveGroups(filter: {edgeTimeToFirstByteMs_gt: 1392, clientRequestPath_in: [$paths]}) {
        avg {
          originResponseDurationMs
          edgeDnsResponseTimeMs
        }
      }
    }
}

Response:
{
  "data": {
    "viewer": {
      "zones": [
        {
          "httpRequestsAdaptiveGroups": [
            {
              "average": {
                "originResponseDurationMs": 4955,
                "edgeDnsResponseTimeMs": 742,
              }
            }
          ]
        }
      ]
    }
  }
}</code></pre>
            <p>According to this, most of the long TTFB values are actually due to resolving DNS! The good news is that’s something we can fix – for example, by setting longer TTLs with my DNS provider.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Coming soon, we’ll be bringing this to Cloudflare Observatory in the dashboard so that you can easily explore timing data via the UI.</p><p>And we’ll be adding even more granular metrics so you can see exactly which components are contributing to high TTFB. For example, we plan to separate out the difference between origin “connection time” (how long it took to establish a TCP and/or TLS connection) vs “application response time” (how long it took an HTTP server to respond).</p><p>We’ll also be making improvements to our GraphQL API to allow more flexible querying – for example, the ability to query arbitrary percentiles, not just 50th, 95th, or 99th.</p><p>Start using the <a href="https://developers.cloudflare.com/analytics/graphql-api/">GraphQL API</a> today to get Timing Insights, or hop on the discussion about our Analytics products in <a href="https://discord.com/channels/595317990191398933/1115387663982276648">Discord</a>.</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Performance]]></category>
            <category><![CDATA[Analytics]]></category>
            <category><![CDATA[GraphQL]]></category>
            <guid isPermaLink="false">1vitH7RVlSZWDB2VUyPmVA</guid>
            <dc:creator>Jon Levine</dc:creator>
            <dc:creator>Miki Mokrysz</dc:creator>
        </item>
        <item>
            <title><![CDATA[How Cloudflare instruments services using Workers Analytics Engine]]></title>
            <link>https://blog.cloudflare.com/using-analytics-engine-to-improve-analytics-engine/</link>
            <pubDate>Fri, 18 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Learn how Cloudflare uses our own Workers Analytics Engine product to capture analytics about our own products! ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/16jjPVsiGz8fzNxVYIgsbR/8c4c93497cd82108d0d74efaf52a96ad/image1-62.png" />
            
            </figure><p>Workers Analytics Engine is a new tool, <a href="/workers-analytics-engine/">announced earlier this year</a>, that enables developers and product teams to build time series analytics about anything, with high dimensionality, high cardinality, and effortless scaling. We built Analytics Engine for teams to gain insights into their code running in Workers, provide analytics to end customers, or even build usage based billing.</p><p>In this blog post we’re going to tell you about how we use Analytics Engine to build Analytics Engine. We’ve instrumented our own Analytics Engine SQL API using Analytics Engine itself and use this data to find bugs and prioritize new product features. We hope this serves as inspiration for other teams who are looking for ways to instrument their own products and gather feedback.</p>
    <div>
      <h3>Why do we need Analytics Engine?</h3>
      <a href="#why-do-we-need-analytics-engine">
        
      </a>
    </div>
    <p>Analytics Engine enables you to generate events (or “data points”) from Workers with <a href="https://developers.cloudflare.com/analytics/analytics-engine/get-started/">just a few lines of code</a>. Using the GraphQL or <a href="https://developers.cloudflare.com/analytics/analytics-engine/sql-api/">SQL API</a>, you can query these events and create useful insights about the business or technology stack. For more about how to get started using Analytics Engine, check out our <a href="https://developers.cloudflare.com/analytics/analytics-engine/">developer docs</a>.</p><p>Since we released the <a href="/analytics-engine-open-beta/">Analytics Engine open beta</a> in September, we’ve been adding new features at a rapid clip based on feedback from developers. However, we’ve had two big gaps in our visibility into the product.</p><p>First, our engineering team needs to answer <a href="https://www.cloudflare.com/learning/performance/what-is-observability/">classic observability questions</a>, such as: how many requests are we getting, how many of those requests result in errors, what are the nature of these errors, etc. They need to be able to view both aggregated data (like average error rate, or p99 response time) and drill into individual events.</p><p>Second, because this is a newly launched product, we are looking for product insights. By instrumenting the SQL API, we can understand the queries our customers write, and the errors they see, which helps us prioritize missing features.</p><p>We realized that Analytics Engine would be an amazing tool for both answering our technical observability questions, and also gathering product insight. That’s because we can log an event for every query to our SQL API, and then query for both aggregated performance issues as well as individual errors and queries that our customers run.</p><p>In the next section, we’re going to walk you through how we use Analytics Engine to monitor that API.</p>
    <div>
      <h2>Adding instrumentation to our SQL API</h2>
      <a href="#adding-instrumentation-to-our-sql-api">
        
      </a>
    </div>
    <p>The Analytics Engine SQL API lets you query events data in the same way you would an ordinary database. For decades, SQL has been the most common language for querying data. We wanted to provide an interface that allows you to immediately start asking questions about your data without having to learn a new query language.</p><p>Our SQL API parses user SQL queries, transforms and validates them, and then executes them against backend database servers. We then write information about the query back into Analytics Engine so that we can run our own analytics.Writing data into Analytics Engine from a Cloudflare Worker is very simple and <a href="https://developers.cloudflare.com/analytics/analytics-engine/get-started/">explained in our documentation</a>. We instrument our SQL API in the same way our users do, and this code excerpt shows the data we write into Analytics Engine:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/L30suydy27OFKzv6ua9ML/c49d03afbb62a1e3df7229e6c30e087c/carbon--3--1.png" />
            
            </figure><p>With that data now being stored in Analytics Engine, we can then pull out insights about every field we’re reporting.</p>
    <div>
      <h2>Querying for insights</h2>
      <a href="#querying-for-insights">
        
      </a>
    </div>
    <p>Having our analytics in an SQL database gives you the freedom to write any query you might want. Compared to using something like metrics which are often predefined and purpose specific, you can define any custom dataset desired, and interrogate your data to ask new questions with ease.</p><p>We need to support datasets comprising trillions of data points. In order to accomplish this, we have implemented a sampling method called <a href="/explaining-cloudflares-abr-analytics/">Adaptive Bit Rate</a> (ABR). With ABR, if you have large amounts of data, your queries may be returned sampled events in order to respond in reasonable time. If you have more typical amounts of data, Analytics Engine will query all your data. This allows you to run any query you like and still get responses in a short length of time. Right now, you have to <a href="https://developers.cloudflare.com/analytics/analytics-engine/sql-api/#sampling">account for sampling in how you make your queries</a>, but we are exploring making it automatic.</p><p>Any data visualization tool can be used to visualize your analytics. At Cloudflare, we heavily use Grafana (<a href="https://developers.cloudflare.com/analytics/analytics-engine/grafana/">and you can too!</a>). This is particularly useful for observability use cases.</p>
    <div>
      <h3>Observing query response times</h3>
      <a href="#observing-query-response-times">
        
      </a>
    </div>
    <p>One query we pay attention to gives us information about the performance of our backend database clusters:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/q8KADDDRyASR7nWPQHoKc/c633325aca2b64e464fc820abfd5e653/image2-45.png" />
            
            </figure><p>As you can see, the 99% percentile (corresponding to the 1% most complex queries to execute) sometimes spikes up to about 300ms. But on average our backend responds to queries within 100ms.</p><p>This visualization is itself generated from an SQL query:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UchtUYBtnDuXwKO7afWUc/1a584c18a7ce7fb74bcc2599756ed6f7/carbon--2-.png" />
            
            </figure>
    <div>
      <h3>Customer insights from high-cardinality data</h3>
      <a href="#customer-insights-from-high-cardinality-data">
        
      </a>
    </div>
    <p>Another use of Analytics Engine is to draw insights out of customer behavior. Our SQL API is particularly well-suited for this, as you can take full advantage of the power of SQL. Thanks to our ABR technology, even expensive queries can be carried out against huge datasets.</p><p>We use this ability to help prioritize improvements to Analytics Engine. Our SQL API supports a fairly standard dialect of SQL but isn’t feature-complete yet. If a user tries to do something unsupported in an SQL query, they get back a structured error message. Those error messages are reported into Analytics Engine. We’re able to aggregate the kinds of errors that our customers encounter, which helps inform which features to prioritize next.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/AmDjwutzQH089GhoJHvzw/b734eaa557a88f2d513968f20f10f28a/image3-36.png" />
            
            </figure><p>The SQL API returns errors in the format of <code>type of error: more details</code>, and so we can take the first portion before the colon to give us the type of error. We group by that, and get a count of how many times that error happened and how many users it affected:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Z1KYNLPlcb3rYTPJ9Fi8f/78ac0462fa7b5b1ae2db27d1dfd67d2b/Screenshot-2022-11-18-at-08.33.57.png" />
            
            </figure><p>To perform the above query using an ordinary metrics system, we would need to represent each error type with a different metric. Reporting that many metrics from each microservice creates scalability challenges. That problem doesn’t happen with Analytics Engine, because it’s designed to handle high-cardinality data.</p><p>Another big advantage of a high-cardinality store like Analytics Engine is that you can dig into specifics. If there’s a large spike in SQL errors, we may want to find which customers are having a problem in order to help them or identify what function they want to use. That’s easy to do with another SQL query:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5ZghZO2Jyk153qPnvS13Mk/05891f4f5db7f1b3247e615c7d2373e1/carbon-3.png" />
            
            </figure><p>Inside Cloudflare, we have historically relied on querying our backend database servers for this type of information. Analytics Engine’s SQL API now enables us to open up our technology to our customers, so they can easily gather insights about their services at any scale!</p>
    <div>
      <h2>Conclusion and what’s next</h2>
      <a href="#conclusion-and-whats-next">
        
      </a>
    </div>
    <p>The insights we gathered about usage of the SQL API are a super helpful input to our product prioritization decisions. We already added <a href="https://developers.cloudflare.com/analytics/analytics-engine/sql-reference/">support for <code>substring</code> and <code>position</code> functions</a> which were used in the visualizations above.</p><p>Looking at the top SQL errors, we see numerous errors related to selecting columns. These errors are mostly coming from some usability issues related to the Grafana plugin. Adding support for the DESCRIBE function should alleviate this because without this, the Grafana plugin doesn’t understand the table structure. This, as well as other improvements to our Grafana plugin, is on our roadmap.</p><p>We also can see that users are trying to query time ranges for older data that no longer exists. This suggests that our customers would appreciate having extended data retention. We’ve recently extended our retention from 31 to 92 days, and we will keep an eye on this to see if we should offer further extension.</p><p>We saw lots of errors related to common mistakes or misunderstandings of proper SQL syntax. This indicates that we could provide better examples or error explanations in our documentation to assist users with troubleshooting their queries.</p><p>Stay tuned into our <a href="https://developers.cloudflare.com/analytics/analytics-engine/">developer docs</a> to be informed as we continue to iterate and add more features!</p><p>You can start using Workers Analytics Engine Now! Analytics Engine is now in open beta with free 90-day retention. <a href="https://dash.cloudflare.com/?to=/:account/workers/analytics-engine">Start using it  today</a> or <a href="https://discord.gg/cloudflaredev">join our Discord community</a> to talk with the team.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Analytics]]></category>
            <category><![CDATA[Logs]]></category>
            <category><![CDATA[Data]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">5Vbtic7QOMABAMIJbPSm7v</guid>
            <dc:creator>Jen Sells</dc:creator>
            <dc:creator>Miki Mokrysz</dc:creator>
        </item>
    </channel>
</rss>