<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shidhin</title>
    <description>The latest articles on DEV Community by Shidhin (@shidhincr).</description>
    <link>https://dev.to/shidhincr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg</url>
      <title>DEV Community: Shidhin</title>
      <link>https://dev.to/shidhincr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shidhincr"/>
    <language>en</language>
    <item>
      <title>Declarative Partial Updates: Streaming HTML Where It Matters Most</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Fri, 25 Sep 2026 12:31:48 +0000</pubDate>
      <link>https://dev.to/shidhincr/declarative-partial-updates-streaming-html-where-it-matters-most-3aho</link>
      <guid>https://dev.to/shidhincr/declarative-partial-updates-streaming-html-where-it-matters-most-3aho</guid>
      <description>&lt;p&gt;Since I joined the Dashboard team at Xendit, I've been taking care of frontend platform work like this. And I keep coming back to one question: what does the user see first, and how long do they wait for it? A typical dashboard page has a header, a side navigation, a few summary cards and a big table of recent transactions. The header and the navigation are ready in a few milliseconds. The table depends on a slow query. And because HTML is delivered top to bottom, the fast parts of the page often end up waiting for the slow one.&lt;/p&gt;

&lt;p&gt;We usually solve this with JavaScript. Render a skeleton, fetch the data on the client, and swap the content in when it arrives. It works, but it means more JavaScript, more round trips, and more code to maintain for something the server already knew how to render.&lt;/p&gt;

&lt;p&gt;Chrome recently shipped a set of platform features under the name &lt;strong&gt;Declarative Partial Updates&lt;/strong&gt;. They let the server stream HTML out of order, and let JavaScript stream HTML into an existing page. In this blog post, we'll explore how these features work, look at a streaming dashboard example, combine both APIs into an SPA-style navigation, and see how to use them today with polyfills.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: HTML is delivered in order
&lt;/h2&gt;

&lt;p&gt;The HTML parser reads a document from top to bottom. If the transactions table sits in the middle of the page, everything after it has to wait until the server finishes rendering that table. The server can flush the header early, but it can't send the footer before the table, because the footer comes later in the document.&lt;/p&gt;

&lt;p&gt;To work around this, we usually pick one of these options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wait for the whole page to be ready, and send it in one go. Simple, but the slowest part decides the speed of the whole page.&lt;/li&gt;
&lt;li&gt;Send a skeleton and fetch the slow parts with JavaScript. Fast first paint, but the data needs an extra round trip after the JavaScript loads.&lt;/li&gt;
&lt;li&gt;Use a framework that streams HTML out of order. Frameworks like React do this with hidden containers and small inline scripts that move the content into place. It works well, but it's framework machinery for something HTML can't express on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part is that, in all three cases, the server already knows the content. The only thing stopping it from sending the content early is the order of the document.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Declarative Partial Updates?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/WICG/declarative-partial-updates" rel="noopener noreferrer"&gt;Declarative Partial Updates&lt;/a&gt; is a project from the Chrome team, incubated in the WICG. The first two pieces of it are now available:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Out-of-order streaming.&lt;/strong&gt; A &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; element with a new &lt;code&gt;for&lt;/code&gt; attribute can patch content into named placeholders, anywhere earlier in the document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New HTML insertion and streaming methods.&lt;/strong&gt; A consistent set of JavaScript methods like &lt;code&gt;setHTML()&lt;/code&gt;, &lt;code&gt;appendHTML()&lt;/code&gt; and &lt;code&gt;streamHTML()&lt;/code&gt;, with streaming versions that accept a &lt;code&gt;WritableStream&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first one needs no JavaScript at all. The second one fills the gap for content that can't come from the initial HTML response. Let's look at each of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Out-of-order streaming with &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Out-of-order streaming uses two building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Processing instructions&lt;/strong&gt; as named placeholders. They look like &lt;code&gt;&amp;lt;?marker name="x"&amp;gt;&lt;/code&gt;. XML has had processing instructions for a long time, but HTML used to treat them as comments. They are now part of the HTML standard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;template for="x"&amp;gt;&lt;/code&gt;&lt;/strong&gt; as the patch. When the parser reaches the template, it looks up the placeholder with the same name and puts the template's content there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are three kinds of placeholders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;?marker name="x"&amp;gt;&lt;/code&gt; is an insertion point.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;?start name="x"&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; wrap a range of fallback content, which gets replaced.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example 1: A simple marker
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;marker&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"greeting"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ...rest of the page... --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"greeting"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Here is some &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;HTML content&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&lt;/span&gt;!
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After parsing, the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; contains the content of the template. The template itself doesn't stay in the DOM.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example 2: Fallback content with start and end
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"summary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"summary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Loading summary…
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ...later in the same response... --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"summary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Volume: 1,204 · Success rate: 98.2%&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user sees &lt;code&gt;Loading summary…&lt;/code&gt; until the template arrives. Then the range is replaced with the real content. This is the pattern I'd use for dashboard cards.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example 3: Appending items one by one
&lt;/h4&gt;

&lt;p&gt;A template can include a new marker with the same name. This lets the next template continue from where the last one stopped:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Loading…
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Result One&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;marker&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Result Two&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;marker&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final DOM has both list items, followed by one &lt;code&gt;&amp;lt;?marker name="results"&amp;gt;&lt;/code&gt;, ready for more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why processing instructions, and not elements?
&lt;/h3&gt;

&lt;p&gt;This was my first question too. Why not use &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; or another element as the placeholder? The answer is that processing instructions don't affect the DOM structure. So you can use them in places where an element isn't allowed. For example, inside &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; to update the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, or inside a &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; to add rows. An earlier version of the proposal used elements, and the design moved to processing instructions as it evolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 4: Streaming a dashboard from a Node server
&lt;/h2&gt;

&lt;p&gt;Let's put this together with a small Node server. The page shell goes out right away. The summary card and the transaction rows are patched in as their data becomes ready, all in the same HTTP response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Fake data sources with different speeds&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSummary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1,204&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;successRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;98.2%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;getTransactions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TX-1001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TX-1002&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TX-1003&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html; charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Send the shell immediately, with named placeholders&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;Dashboard&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;header&amp;gt;My Dashboard&amp;lt;/header&amp;gt;
  &amp;lt;section&amp;gt;&amp;lt;?start name="summary"&amp;gt;Loading summary…&amp;lt;?end&amp;gt;&amp;lt;/section&amp;gt;
  &amp;lt;table&amp;gt;
    &amp;lt;tbody&amp;gt;&amp;lt;?start name="rows"&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Loading…&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;?end&amp;gt;&amp;lt;/tbody&amp;gt;
  &amp;lt;/table&amp;gt;
  &amp;lt;footer&amp;gt;Footer is here already!&amp;lt;/footer&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Patch the summary as soon as it is ready&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSummary&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;template for="summary"&amp;gt;
    &amp;lt;p&amp;gt;Volume: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; · Success rate: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;successRate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;
  &amp;lt;/template&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Each row leaves a fresh marker for the next one&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;getTransactions&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;template for="rows"&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;?marker name="rows"&amp;gt;&amp;lt;/template&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Close the document only after the last template&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The footer reaches the user before the slow data, even though it comes after the table in the layout.&lt;/li&gt;
&lt;li&gt;The templates are written as direct children of &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. This matters, as we'll see in the next section.&lt;/li&gt;
&lt;li&gt;In a real app, escape any user data before writing it into the HTML.&lt;/li&gt;
&lt;li&gt;Streaming only helps if the bytes actually reach the browser in chunks. Check that your compression middleware, proxy or CDN doesn't buffer the whole response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Chrome team also has a &lt;a href="https://github.com/GoogleChromeLabs/web-perf-demos/blob/main/patching-demos/photo-album-server.js" rel="noopener noreferrer"&gt;photo album demo&lt;/a&gt; that streams the status and the photos into the page after the initial layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restrictions and gotchas
&lt;/h2&gt;

&lt;p&gt;Out-of-order streaming has a few rules worth knowing before you use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same parent only.&lt;/strong&gt; For security reasons, a &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; can only patch placeholders inside its own parent element. A template placed directly in &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; can reach the whole document, including the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; is optional.&lt;/strong&gt; Without it, everything from &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; to the end of the containing element is replaced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't move placeholders mid-stream.&lt;/strong&gt; If you move a processing instruction after a template has started streaming into it, the new content keeps streaming into the old location.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;innerHTML&lt;/code&gt; and &lt;code&gt;setHTML()&lt;/code&gt; patch in place.&lt;/strong&gt; When you insert &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; with these methods, the parser works on an intermediate document fragment. So the template can't touch the existing DOM. The streaming methods in the next section don't have this limitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The response is the update window.&lt;/strong&gt; Patching only works while the server is still writing the document. Once the response ends, further updates need JavaScript or a new navigation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's also worth being clear about what this is not. It doesn't replace client-side state. Filters, inline edits and anything else that reacts to user input after the page has loaded still needs JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new HTML insertion and streaming methods
&lt;/h2&gt;

&lt;p&gt;Not every update can come from the initial HTML response. For those cases, we already have many ways to insert HTML with JavaScript: &lt;code&gt;innerHTML&lt;/code&gt;, &lt;code&gt;outerHTML&lt;/code&gt;, &lt;code&gt;insertAdjacentHTML&lt;/code&gt;, &lt;code&gt;createContextualFragment&lt;/code&gt;, &lt;code&gt;setHTML&lt;/code&gt; and &lt;code&gt;setHTMLUnsafe&lt;/code&gt;. Each of them behaves a little differently. Does it overwrite or append? Does it sanitize? Do scripts run? How does it work with Trusted Types? Honestly, I can't answer all of these without checking MDN.&lt;/p&gt;

&lt;p&gt;There is also a bigger limitation. All these methods need the full HTML string up front. You can't stream into them, even though streaming is one of the best things about HTML.&lt;/p&gt;

&lt;p&gt;The new set of methods fixes both problems, with consistent names and a streaming version of each:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Static&lt;/th&gt;
&lt;th&gt;Streaming&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Set the contents of the element&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setHTML(html, options)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;streamHTML(options)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace the whole element&lt;/td&gt;
&lt;td&gt;&lt;code&gt;replaceWithHTML(html, options)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;streamReplaceWithHTML(options)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert before the element&lt;/td&gt;
&lt;td&gt;&lt;code&gt;beforeHTML(html, options)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;streamBeforeHTML(options)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert as the first child&lt;/td&gt;
&lt;td&gt;&lt;code&gt;prependHTML(html, options)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;streamPrependHTML(options)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert as the last child&lt;/td&gt;
&lt;td&gt;&lt;code&gt;appendHTML(html, options)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;streamAppendHTML(options)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert after the element&lt;/td&gt;
&lt;td&gt;&lt;code&gt;afterHTML(html, options)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;streamAfterHTML(options)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each method also has an &lt;code&gt;Unsafe&lt;/code&gt; version, like &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt;. The safe versions run the HTML through the &lt;a href="https://developer.mozilla.org/docs/Web/API/HTML_Sanitizer_API" rel="noopener noreferrer"&gt;Sanitizer API&lt;/a&gt; by default. The &lt;code&gt;Unsafe&lt;/code&gt; versions skip the sanitizer by default, and accept a &lt;code&gt;runScripts&lt;/code&gt; option (default &lt;code&gt;false&lt;/code&gt;) if you want scripts to execute. The word "unsafe" is a reminder to think about how much you trust the input, not a sign that you shouldn't use them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example 5: Static insertion with a custom sanitizer
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Only allow basic formatting&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sanitizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Sanitizer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;em&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p&amp;gt;Hello &amp;lt;strong&amp;gt;world&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sanitizer&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 6: Streaming a fetch response into an element
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/partials/transactions.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoderStream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chrome 151 also added a &lt;code&gt;textStream()&lt;/code&gt; convenience method, which removes the &lt;code&gt;TextDecoderStream&lt;/code&gt; step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textStream&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nice part is that &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt; works much like the main parser. It processes &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; as the templates arrive, and it doesn't use an intermediate fragment. So streamed templates can patch content that already exists in the page.&lt;/p&gt;

&lt;p&gt;If you use Trusted Types, streaming needs a new &lt;code&gt;createParserOptions&lt;/code&gt; method to inject a sanitizer. The &lt;a href="https://github.com/WICG/declarative-partial-updates/blob/main/dynamic-markup-revamped-explainer.md#trusted-types-integration" rel="noopener noreferrer"&gt;explainer&lt;/a&gt; has the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using both together: an SPA-style navigation
&lt;/h2&gt;

&lt;p&gt;This is where things get interesting. The two APIs are separate, but they work really well together. If you stream &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; elements into the page, each template finds its own placeholder. You don't need a separate DOM reference for every part of the page you want to update.&lt;/p&gt;

&lt;p&gt;Here is the idea: load a page shell with named placeholders once. On navigation, fetch the next page as a set of templates and stream them into the bottom of &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example 7: The page shell
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Dashboard&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/overview"&lt;/span&gt; &lt;span class="na"&gt;data-partial&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Overview&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/transactions"&lt;/span&gt; &lt;span class="na"&gt;data-partial&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Transactions&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading…&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/router.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 8: A partial response from the server
&lt;/h4&gt;

&lt;p&gt;Each template re-emits its own &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt;, so the next navigation can replace the range again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Transactions&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Transactions&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example 9: The router
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// router.js&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a[data-partial]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/partials&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Templates land as direct children of &amp;lt;body&amp;gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// so they can patch anything in the document, including &amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textStream&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipeTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamAppendHTMLUnsafe&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what's missing here. There is no client-side templating, no diffing, and no code that knows which element to update. The server decides what changes, and the HTML parser applies it as the bytes arrive. Because the templates are appended to &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, the same-parent rule lets them update the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; too.&lt;/p&gt;

&lt;p&gt;This is a sketch, not a production router. A real one would handle the back button, cancel an in-flight request when the user clicks again, and manage focus for accessibility. The &lt;a href="https://developer.mozilla.org/docs/Web/API/Navigation_API" rel="noopener noreferrer"&gt;Navigation API&lt;/a&gt; is a good fit for the first two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it today with polyfills
&lt;/h2&gt;

&lt;p&gt;The Chrome team has released two polyfills, so you don't have to wait for other browsers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/GoogleChromeLabs/template-for-polyfill" rel="noopener noreferrer"&gt;template-for-polyfill&lt;/a&gt;&lt;/strong&gt; (&lt;a href="https://www.npmjs.com/package/template-for-polyfill" rel="noopener noreferrer"&gt;npm&lt;/a&gt;) adds &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; support. It can't change the browser's HTML parser, so it has &lt;a href="https://github.com/GoogleChromeLabs/template-for-polyfill#limitations" rel="noopener noreferrer"&gt;some limitations&lt;/a&gt;, but it covers the common use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/GoogleChromeLabs/html-setters-polyfill" rel="noopener noreferrer"&gt;html-setters-polyfill&lt;/a&gt;&lt;/strong&gt; (&lt;a href="https://www.npmjs.com/package/html-setters-polyfill" rel="noopener noreferrer"&gt;npm&lt;/a&gt;) adds the new insertion and streaming methods. Note that it doesn't actually stream. It buffers the content and applies it when the stream completes. So treat it as a polyfill for the API shape, not for the performance benefit. The safe methods also depend on &lt;code&gt;setHTML()&lt;/code&gt; and the Sanitizer API, which Safari doesn't support yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good news is that out-of-order streaming degrades reasonably. Without support, the fallback content between &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; simply stays on the page. So test the experience in Firefox and Safari, and make sure the fallback is something the user can live with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser support
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Chrome / Edge&lt;/th&gt;
&lt;th&gt;Firefox&lt;/th&gt;
&lt;th&gt;Safari&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; out-of-order streaming&lt;/td&gt;
&lt;td&gt;150 (on by default)&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New insertion and streaming methods&lt;/td&gt;
&lt;td&gt;Behind a flag from 148, planned for 155&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;textStream()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;151&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To try the streaming methods today, enable &lt;code&gt;chrome://flags/#enable-experimental-web-platform-features&lt;/code&gt;. The &lt;code&gt;for&lt;/code&gt; attribute on &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; is already part of the HTML standard, and the new methods are &lt;a href="https://github.com/whatwg/html/pull/12758" rel="noopener noreferrer"&gt;being added to the spec&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's coming next
&lt;/h2&gt;

&lt;p&gt;The Chrome team is exploring a few more additions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-side includes&lt;/strong&gt;, like &lt;code&gt;&amp;lt;template for="footer" src="/partials/footer.html"&amp;gt;&lt;/code&gt;. This one is already behind the experimental flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning&lt;/strong&gt;, so content that hasn't changed isn't overwritten and keeps its state between route changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanitizing while patching&lt;/strong&gt;, like &lt;code&gt;&amp;lt;template for="icon" safe&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/web-platform/declarative-partial-updates" rel="noopener noreferrer"&gt;Declarative partial updates (Chrome for Developers)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WICG/declarative-partial-updates" rel="noopener noreferrer"&gt;WICG Declarative Partial Updates repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WICG/declarative-partial-updates/blob/main/patching-explainer.md" rel="noopener noreferrer"&gt;Patching explainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WICG/declarative-partial-updates/blob/main/dynamic-markup-revamped-explainer.md" rel="noopener noreferrer"&gt;Dynamic markup explainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/template#for" rel="noopener noreferrer"&gt;MDN: the template &lt;code&gt;for&lt;/code&gt; attribute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://html.spec.whatwg.org/multipage/syntax.html#processing-instructions" rel="noopener noreferrer"&gt;HTML spec: processing instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;For a long time, the order of the HTML document decided the order in which users saw things. Declarative Partial Updates change that. With &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; and processing instructions, the server can send the fast parts of a page first and patch in the slow parts later, without any JavaScript. With the new streaming methods, JavaScript can stream HTML into an existing page too. Put them together and you get SPA-style updates where the server decides what changes and the browser's parser does the work.&lt;/p&gt;

&lt;p&gt;For dashboards like the ones I work on, that means the user sees the page layout and the quick numbers right away, while the slow tables fill in as soon as their data is ready.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The &lt;geolocation&gt; Element Changed How I Think About Permissions</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Mon, 26 Jan 2026 14:27:58 +0000</pubDate>
      <link>https://dev.to/shidhincr/the-element-changed-how-i-think-about-permissions-36nn</link>
      <guid>https://dev.to/shidhincr/the-element-changed-how-i-think-about-permissions-36nn</guid>
      <description>&lt;p&gt;I've been building web apps that need location data for years. And honestly? I've always dreaded the geolocation code. Not because the API is complicated—it's actually pretty simple—but because of everything &lt;em&gt;around&lt;/em&gt; it. The permission prompts that fire before users even know why they need to share their location. The dead-end when someone clicks "Block" by accident. The awkward dance of trying to explain "please go to your browser settings and reset permissions."&lt;/p&gt;

&lt;p&gt;Chrome 144 shipped something that made me genuinely excited: the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element. It's a declarative, HTML-first approach to location permissions, and after playing with it, I'm convinced this is how permissions should have worked all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Old Way Was Painful
&lt;/h2&gt;

&lt;p&gt;Let's be honest about the traditional &lt;code&gt;navigator.geolocation.getCurrentPosition()&lt;/code&gt; API. It &lt;em&gt;works&lt;/em&gt;, but it creates problems.&lt;/p&gt;

&lt;p&gt;The permission prompt fires whenever your JavaScript decides to call the function. Users see a popup before they've even clicked anything. They don't know &lt;em&gt;why&lt;/em&gt; your app wants their location, and the natural instinct is to click "Block." I've watched user testing sessions where people blocked location access reflexively, then complained the app didn't work.&lt;/p&gt;

&lt;p&gt;Once blocked, there's no recovery. Your code can't re-trigger the prompt. You're stuck showing a sad "please go to Settings &amp;gt; Privacy &amp;gt; Site Settings &amp;gt; Location" message that 95% of users will never follow.&lt;/p&gt;

&lt;p&gt;The browser also has no way to know if the request came from genuine user intent or from some sketchy script trying to harvest location data on page load.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; Element Does Differently
&lt;/h2&gt;

&lt;p&gt;The core idea is simple: instead of &lt;em&gt;JavaScript&lt;/em&gt; triggering the permission flow, the &lt;em&gt;user&lt;/em&gt; triggers it by clicking a browser-controlled button. The browser renders a styled button with localized text (something like "Use Location" in English, "Standort verwenden" in German). When the user clicks it, they're providing an explicit signal: "Yes, I want to share my location."&lt;/p&gt;

&lt;p&gt;Let's see the most basic version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"requestLocationFallback()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Share Location&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content inside the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is fallback for browsers that don't support it yet. In Chrome 144+, the browser replaces this with its own trusted button.&lt;/p&gt;

&lt;p&gt;Here's what happens when you wire it up with JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geoElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geoElement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Lat: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Lng: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is pretty simple to understand. We're listening for the &lt;code&gt;location&lt;/code&gt; event on the element, then reading the &lt;code&gt;position&lt;/code&gt; attribute directly from it. No callbacks, no separate success/error handlers—just straightforward property access.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JavaScript Interface
&lt;/h2&gt;

&lt;p&gt;The element exposes a clean interface that's worth understanding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;HTMLGeolocationElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;GeolocationPosition&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;GeolocationPositionError&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;PermissionState&lt;/span&gt; &lt;span class="nx"&gt;permissionStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="nx"&gt;autolocate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;EventHandler&lt;/span&gt; &lt;span class="nx"&gt;onlocation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;EventHandler&lt;/span&gt; &lt;span class="nx"&gt;onpromptaction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="nx"&gt;EventHandler&lt;/span&gt; &lt;span class="nx"&gt;onpromptdismiss&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;permissionStatus&lt;/code&gt; property is particularly useful. It tells you whether permission is &lt;code&gt;granted&lt;/code&gt;, &lt;code&gt;denied&lt;/code&gt;, or &lt;code&gt;prompt&lt;/code&gt;—so you can build UI that responds appropriately without guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different Kinds of Location Tracking
&lt;/h2&gt;

&lt;p&gt;The element supports two modes through attributes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-time location&lt;/strong&gt; is the default. User clicks, location fires once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"geo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Get My Location&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Continuous tracking&lt;/strong&gt; uses the &lt;code&gt;watch&lt;/code&gt; attribute. It's like &lt;code&gt;watchPosition()&lt;/code&gt; but declarative:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"tracker"&lt;/span&gt; &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Track Me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Auto-locate&lt;/strong&gt; is interesting. If you add the &lt;code&gt;autolocate&lt;/code&gt; attribute &lt;em&gt;and&lt;/em&gt; the user has already granted permission, the element will fetch location automatically on page load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"geo"&lt;/span&gt; &lt;span class="na"&gt;autolocate&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Share Location&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great for apps where location is central—like a delivery tracker where returning users have already opted in.&lt;/p&gt;

&lt;h2&gt;
  
  
  A More Complete Example
&lt;/h2&gt;

&lt;p&gt;Let me show something closer to real-world usage. Here's a location card that displays coordinates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"location-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;📍 Your Location&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"coordinates"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"coords"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Click the button to share your location
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"geoElement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"fallbackLocation()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Share Location (Fallback)&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geoElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geoElement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coordsDisplay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;coords&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;coordsDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
        Lat: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;br&amp;gt;
        Lng: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
      `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;coordsDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;geoElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Fallback for unsupported browsers&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fallbackLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;coordsDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
          Lat: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;br&amp;gt;
          Lng: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
        `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;coordsDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the fallback button inside &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; uses the traditional API. Progressive enhancement at its finest—old browsers get the old behavior, new browsers get the better UX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security That's Actually Built-In
&lt;/h2&gt;

&lt;p&gt;The element has some clever security measures that I didn't have to think about (which is the point).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visibility validation&lt;/strong&gt;: The element must be fully visible in the viewport. No hiding it behind other elements or positioning it off-screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Movement detection&lt;/strong&gt;: If you programmatically move the element, it's temporarily disabled for 500ms. This prevents clickjacking attacks where the element slides under the cursor right before a click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Style constraints&lt;/strong&gt;: You can't make the element invisible or heavily disguise it. The browser maintains control over its appearance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trusted events only&lt;/strong&gt;: Only actual user clicks work. Synthetic JavaScript events won't trigger the permission flow.&lt;/p&gt;

&lt;p&gt;I used to write custom code to prevent some of these attacks. Now the browser handles it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting Support
&lt;/h2&gt;

&lt;p&gt;Since this is Chrome-only for now, you need feature detection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isGeolocationElementSupported&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HTMLGeolocationElement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Or the prototype check&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkSupport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geolocation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;testElement&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;HTMLGeolocationElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can conditionally render different UI or rely on the fallback content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old vs. New: A Quick Comparison
&lt;/h2&gt;

&lt;p&gt;Here's the traditional approach with all its ceremony:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;requestLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;permission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geolocation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;denied&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;showPermissionDeniedUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;enableHighAccuracy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Permission API not supported&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's the new approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;geolocation&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"geo"&lt;/span&gt; &lt;span class="na"&gt;autolocate&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Share Location&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/geolocation&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;geo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;handleSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;handleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Less code, better UX, built-in security. I'll take that trade every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra Points
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;onpromptdismiss&lt;/code&gt; event fires when a user closes the permission prompt without making a choice. This lets you show contextual help instead of leaving them confused.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;lang&lt;/code&gt; attribute controls button text localization. The browser handles translation automatically, but you can override it if needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't use &lt;code&gt;autolocate&lt;/code&gt; on first visit. It only works when permission is already granted, but the intent is for returning users—not to spam new visitors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The element is disabled inside fenced frames for security reasons. If you're building embedded widgets, keep this in mind.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is what I wish we'd had from the start. It turns a JavaScript-triggered, easily-blocked, no-recovery permission flow into a user-initiated, browser-trusted, properly-recoverable experience. Once other browsers adopt this pattern, geolocation in web apps will feel a lot less hostile to users—and a lot less painful for developers. :)&lt;/p&gt;

</description>
      <category>geolocation</category>
      <category>html</category>
      <category>chrome</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ship Faster, Debug Smarter: My Take on the New Chrome DevTools AI</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Thu, 04 Dec 2025 13:24:56 +0000</pubDate>
      <link>https://dev.to/shidhincr/ship-faster-debug-smarter-my-take-on-the-new-chrome-devtools-ai-4h4m</link>
      <guid>https://dev.to/shidhincr/ship-faster-debug-smarter-my-take-on-the-new-chrome-devtools-ai-4h4m</guid>
      <description>&lt;p&gt;I recently had the incredible opportunity to speak at GDG Coimbatore about a shift that is fundamentally changing how we build for the web: the integration of AI directly into Chrome DevTools. We all want to "Ship Faster," but the real challenge has always been how to "Debug Smarter."&lt;/p&gt;

&lt;p&gt;If you missed the session, I wanted to write up a quick summary of the key updates. We are moving away from blindly staring at timelines and guessing, to having Gemini help us with styling, network issues, and performance without ever leaving the tab.&lt;/p&gt;

&lt;p&gt;Here is the breakdown of what I covered and what you need to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality Check: It’s Not About Your Laptop
&lt;/h2&gt;

&lt;p&gt;I started the session with a quote that I think every frontend engineer needs to tape to their monitor:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Performance isn't about your laptop; it's about theirs."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We often build on high-end machines with fiber internet, but the data tells a completely different story. When you look at Core Web Vitals like LCP (Largest Contentful Paint) and INP (Interaction to Next Paint), there is a massive gap between desktop and phone performance. For example, while desktop pass rates for INP might be decent, mobile users are often struggling with responsiveness.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febc97edd5kzl8uzlgnz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febc97edd5kzl8uzlgnz6.png" alt=" " width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we want to fix this, we have to stop debugging in a vacuum. I always recommend using the &lt;strong&gt;Throttling&lt;/strong&gt; settings in DevTools. Don't just test on "No throttling." Try mimicking a "Slow 4G" network and slowing down your CPU by 4x or 6x to really feel what your user feels.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fapbs2km1q8whqtc1eu36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fapbs2km1q8whqtc1eu36.png" alt=" " width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Performance Panel is Evolving
&lt;/h2&gt;

&lt;p&gt;One of the biggest friction points for us developers has always been context switching—running a Lighthouse audit in one tab and then trying to map those findings to a Performance trace in another.&lt;/p&gt;

&lt;p&gt;That’s changing. The standalone "Insights" panel is actually being deprecated. Instead, Lighthouse is moving to insight-based audits directly inside the Performance panel.&lt;/p&gt;

&lt;p&gt;Now, when you record a trace, you get &lt;strong&gt;"Insights Annotations"&lt;/strong&gt; baked right in. You can drill down into specific metrics like "LCP by phase" or investigate "Layout shift culprits" immediately. It’s designed so we spend "Less Searching, More Finding."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mjmu7rrrq49kyasejz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mjmu7rrrq49kyasejz6.png" alt=" " width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the AI: A Helper, Not a Replacement
&lt;/h2&gt;

&lt;p&gt;This is the part everyone is excited about. We now have &lt;strong&gt;"Ask AI"&lt;/strong&gt; integrated directly into the Console and other panels. It’s powered by Gemini and designed to help us navigate the parts of web development that usually require opening ten new Google tabs.&lt;/p&gt;

&lt;p&gt;Here are the three main ways I’ve been using it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Fixing Styling Bugs:&lt;/strong&gt; CSS can be a nightmare. You can now ask the AI to explain a specific element's styles or help you fix layout bugs—like finally figuring out why that one element won't center.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Analyzing Network Requests:&lt;/strong&gt; Instead of manually parsing headers, you can ask the AI to look at a failed request or explain what a specific response header implies.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Understanding Source Files:&lt;/strong&gt; Let’s be honest, it’s rare that we wrote 100% of the code on our websites. If you are looking at a minified or unfamiliar script, the AI can explain what that file is actually doing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuxpgzvnoh8llifihad2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuxpgzvnoh8llifihad2.png" alt=" " width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Enable It (And a Word of Caution)
&lt;/h2&gt;

&lt;p&gt;To get these features, you generally need to head into your DevTools &lt;strong&gt;Settings&lt;/strong&gt;, go to &lt;strong&gt;Experiments&lt;/strong&gt; (or the &lt;strong&gt;AI innovations&lt;/strong&gt; tab in newer versions), and toggle on "AI assistance".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2fmyexe6683tx9f4fcr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2fmyexe6683tx9f4fcr.png" alt=" " width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, I have to end with a "Be Careful" warning.&lt;/p&gt;

&lt;p&gt;This is Generative AI. It can be wrong. The tool is experimental and might provide inaccurate info, so you should always validate the AI's suggestions with a new recording. My rule of thumb? Keep your fixes small and reversible. Also, keep in mind that your prompts and inspected page data are sent to Google, so be mindful if you are working with sensitive enterprise data.&lt;/p&gt;

&lt;p&gt;It’s an exciting time to be building for the web. If you want to dive deeper, check out the official &lt;a href="https://developer.chrome.com/docs/devtools#ai" rel="noopener noreferrer"&gt;Chrome docs on AI assistance.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tooling</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Beyond the Flame Chart: Chrome DevTools' New AI Instantly Pinpoints Your Site's Performance Issues</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Wed, 05 Nov 2025 16:23:14 +0000</pubDate>
      <link>https://dev.to/shidhincr/beyond-the-flame-chart-chrome-devtools-new-ai-instantly-pinpoints-your-sites-performance-issues-m3</link>
      <guid>https://dev.to/shidhincr/beyond-the-flame-chart-chrome-devtools-new-ai-instantly-pinpoints-your-sites-performance-issues-m3</guid>
      <description>&lt;p&gt;If you're a web developer, you know the ritual. Your site feels slow, so you open the Chrome DevTools "Performance" panel, hit "record," and brace yourself.&lt;/p&gt;

&lt;p&gt;What you get is a powerful, but incredibly dense, "wall of data." A complex, multi-colored flame chart, a dense network waterfall, and a dozen metrics you have to cross-reference. For many, this is where the debugging process stalls. Is the problem a Long Task? A render-blocking resource? A late-discovered LCP element? Interpreting this data correctly is a specialized skill.&lt;/p&gt;

&lt;p&gt;But what if you didn't have to? What if you could have an expert performance engineer look over your shoulder, analyze that entire trace in seconds, and just tell you what to fix?&lt;/p&gt;

&lt;p&gt;That's exactly what Google is now building directly into Chrome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet Your New "AI Assistance"
&lt;/h3&gt;

&lt;p&gt;Buried within the latest DevTools is a new feature that fundamentally changes this workflow. Instead of manually scrubbing the timeline and deciphering the chart, you can now simply ask for help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok3x6ur8s0a5skajqluw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok3x6ur8s0a5skajqluw.png" alt="AI Assistance" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the new workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Run Your Trace:&lt;/strong&gt; You start by recording a Performance trace just as you always have, capturing the page load or interaction you want to debug.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Open "Debug with AI":&lt;/strong&gt; Once the trace is complete, you go to the main three-dot menu in the corner of DevTools. There's a new option: &lt;strong&gt;"Debug with AI."&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Ask the Right Questions:&lt;/strong&gt; This opens a new "AI assistance" panel directly beside your trace. This panel is context-aware; it "sees" your performance data and provides suggested prompts to get you started, such as:

&lt;ul&gt;
&lt;li&gt;"What performance issues exist with my page?"&lt;/li&gt;
&lt;li&gt;"What can I do to reduce the LCP time for this page load?"&lt;/li&gt;
&lt;li&gt;"Why is LCP discovery time important?"&lt;/li&gt;
&lt;li&gt;"How can I prevent layout shifts on this page?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  From "Wall of Data" to Actionable Insights
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens. When you select a prompt like &lt;strong&gt;"What performance issues exist with my page?"&lt;/strong&gt;, the AI doesn't give you a generic checklist. It performs a specific analysis of &lt;em&gt;your&lt;/em&gt; trace and delivers a prioritized, human-readable report.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/I9aNacMzD9M" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;br&gt;
Based on a recent trace, here is the kind of powerful, specific feedback this AI can provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LCP Render Delay (602 ms):&lt;/strong&gt; It doesn't not just say "LCP is slow." It identifies the &lt;em&gt;exact&lt;/em&gt; problem: "A significant portion of your Largest Contentful Paint (LCP) time is spent in the render delay phase. This indicates that the LCP element was ready to be painted but was &lt;strong&gt;blocked by other rendering work&lt;/strong&gt;." This immediately narrows your focus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image Delivery (3.7 MB wasted):&lt;/strong&gt; It provides a specific, quantifiable problem: "There are &lt;strong&gt;unoptimized images&lt;/strong&gt; on your page, leading to &lt;strong&gt;3.7 MB of wasted data transfer&lt;/strong&gt;." This is a direct instruction to go and compress your images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long Tasks on Main thread:&lt;/strong&gt; It connects the dots to user interaction metrics. It will identify "several long tasks" and explain that these "can &lt;strong&gt;block the browser from responding to user input&lt;/strong&gt;, negatively affecting Interaction to Next Paint (INP)."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render-Blocking Resources:&lt;/strong&gt; It flags the classic bottleneck of "resources that are &lt;strong&gt;blocking the page's initial render&lt;/strong&gt;," another clear-cut problem to solve.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why This is a Game-Changer
&lt;/h3&gt;

&lt;p&gt;This feature isn't just a gimmick; it represents a fundamental shift in developer tooling.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It Lowers the Barrier to Entry:&lt;/strong&gt; Junior developers or those who don't specialize in performance can now get the same high-level analysis that would previously have required a seasoned expert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It Saves Massive Amounts of Time:&lt;/strong&gt; For senior developers, this AI acts as an incredibly fast assistant. It performs the initial 10-15 minutes of data triage in about two seconds, letting you jump straight to implementing the fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It Shifts Your Focus:&lt;/strong&gt; You can spend less time trying to &lt;em&gt;interpret data&lt;/em&gt; and more time &lt;em&gt;solving problems&lt;/em&gt;. The tool even encourages this by providing follow-up prompts, like "Tell me more about the LCP render delay," allowing you to drill down interactively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the future of developer tooling: not a replacement for your skills, but a powerful augment that handles the tedious work, letting you focus on what matters—building a faster, better web experience.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>ai</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using the fetchLater() API</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Thu, 26 Jun 2025 14:22:08 +0000</pubDate>
      <link>https://dev.to/shidhincr/using-the-fetchlater-api-2omm</link>
      <guid>https://dev.to/shidhincr/using-the-fetchlater-api-2omm</guid>
      <description>&lt;h2&gt;
  
  
  Using the fetchLater() API: Reliable Beaconing for the Modern Web
&lt;/h2&gt;

&lt;p&gt;Chrome 135, released in April 2025, introduces a powerful new addition to web developers' toolkit: the &lt;code&gt;fetchLater()&lt;/code&gt; API. This feature solves a long-standing challenge of reliably sending data to servers when a user leaves a page. In this post, we'll explore what the API offers, why it matters, and how to start using it in your applications today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Page Unload Beaconing
&lt;/h2&gt;

&lt;p&gt;Web developers often need to send critical data back to servers when users leave a page. Analytics services, performance metrics, and user interaction tracking all rely on this capability. Traditionally, developers have used a combination of approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listening for &lt;code&gt;beforeunload&lt;/code&gt;, &lt;code&gt;pagehide&lt;/code&gt;, or &lt;code&gt;visibilitychange&lt;/code&gt; events&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;navigator.sendBeacon()&lt;/code&gt; or &lt;code&gt;fetch()&lt;/code&gt; with the &lt;code&gt;keepalive&lt;/code&gt; option&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, these methods face reliability issues, especially on mobile devices where events may not fire consistently. Even with the best practices, developers could only achieve around 82% reliability for unload beaconing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter fetchLater()
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;fetchLater()&lt;/code&gt; API provides a cleaner, more reliable solution. It allows you to queue up requests that will be sent either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the page is unloaded (tab closed, navigation away, etc.)&lt;/li&gt;
&lt;li&gt;After a specified timeout&lt;/li&gt;
&lt;li&gt;When the browser decides it's time to send it&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Basic Usage
&lt;/h2&gt;

&lt;p&gt;The API syntax is designed to feel familiar to developers who use &lt;code&gt;fetch()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Basic usage - will send when page unloads&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetchLater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/analytics-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sessionData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;collectSessionData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Check if the request has been sent&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false initially, true after sending&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding a Timeout
&lt;/h2&gt;

&lt;p&gt;You can specify an &lt;code&gt;activateAfter&lt;/code&gt; option (in milliseconds) to ensure the request is sent after a certain time, even if the page hasn't been unloaded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Send after 1 minute OR when page unloads (whichever comes first)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oneMinute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;fetchLater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/analytics-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sessionData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;collectSessionData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;activateAfter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;oneMinute&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Updating Data Before Sending
&lt;/h2&gt;

&lt;p&gt;One of the most powerful features is the ability to update the queued request before it's sent. This is perfect for analytics that accumulate data over time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;analyticsData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;pageViews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fetchLaterResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;queueAnalyticsBeacon&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Abort any existing request&lt;/span&gt;
  &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Queue a new request with the latest data&lt;/span&gt;
  &lt;span class="nx"&gt;fetchLaterResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetchLater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/analytics-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;analyticsData&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;activateAfter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="c1"&gt;// 1 hour&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Initial queue&lt;/span&gt;
&lt;span class="nf"&gt;queueAnalyticsBeacon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Update when user interacts&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;recordInteraction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interactionType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;analyticsData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;interactionType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Update the queued beacon&lt;/span&gt;
  &lt;span class="nf"&gt;queueAnalyticsBeacon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Example: Web Vitals Reporting
&lt;/h2&gt;

&lt;p&gt;Here's how you might use &lt;code&gt;fetchLater()&lt;/code&gt; to send Core Web Vitals data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onCLS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onINP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onLCP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-vitals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fetchLaterResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Clear already-sent metrics if request was activated&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchLaterResult&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;activated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Add the new/updated metric&lt;/span&gt;
  &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Prepare the data payload&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Abort any existing fetchLater() and queue a new one&lt;/span&gt;
  &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;fetchLaterResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetchLater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/vitals-analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;activateAfter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="c1"&gt;// 1 hour timeout for regular sending&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register the web vitals callbacks&lt;/span&gt;
&lt;span class="nf"&gt;onCLS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateMetrics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;onINP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateMetrics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;onLCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateMetrics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Error Handling
&lt;/h2&gt;

&lt;p&gt;It's good practice to handle potential errors, especially quota limitations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetchLater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/analytics-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;analyticsData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;QuotaExceededError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle quota exceeded&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Analytics beacon quota exceeded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle other errors&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error queueing analytics beacon:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding Quotas and Limitations
&lt;/h2&gt;

&lt;p&gt;To prevent abuse, browsers enforce limits on &lt;code&gt;fetchLater()&lt;/code&gt; usage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total bandwidth for a top-level document is capped at 640KB&lt;/li&gt;
&lt;li&gt;Each reporting origin is limited to 64KB&lt;/li&gt;
&lt;li&gt;All pending requests are flushed when a document enters the browser's back/forward cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Browser Support
&lt;/h2&gt;

&lt;p&gt;As of May 2025:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chrome: Supported since version 135 (April 2025)&lt;/li&gt;
&lt;li&gt;Firefox: Under consideration&lt;/li&gt;
&lt;li&gt;Safari: Not yet implemented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For browsers that don't support &lt;code&gt;fetchLater()&lt;/code&gt;, you can implement a fallback using the traditional approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendAnalytics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchLater&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fetchLater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetchLater failed, falling back to sendBeacon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Fallback to sendBeacon&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendBeacon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/analytics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register traditional unload handlers as fallback&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pagehide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;sendAnalytics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;analyticsData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visibilitychange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibilityState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sendAnalytics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;analyticsData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1ngc1pqp389o6k87zwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1ngc1pqp389o6k87zwb.png" alt=" " width="799" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have built a simple Demo page for the fetchLater API here: &lt;a href="https://www.undefinednull.com/fetch-later-demo/" rel="noopener noreferrer"&gt;https://www.undefinednull.com/fetch-later-demo/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;fetchLater()&lt;/code&gt; API represents a significant improvement for web developers who need reliable beaconing. It simplifies code, improves reliability, and provides a more declarative approach to handling page unload data transmission.&lt;/p&gt;

&lt;p&gt;By adopting this API (with appropriate fallbacks), developers can ensure their analytics, metrics, and other critical data have the best chance of making it back to servers, regardless of how users exit their web applications.&lt;/p&gt;

&lt;p&gt;For more details, check the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/fetchLater_API" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; and consider experimenting with the API in your applications today.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Harnessing AI to Debug and Optimize Web Performance: A Guide to Chrome DevTools AI Assistance</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Mon, 28 Apr 2025 16:21:09 +0000</pubDate>
      <link>https://dev.to/shidhincr/harnessing-ai-to-debug-and-optimize-web-performance-a-guide-to-chrome-devtools-ai-assistance-5h1p</link>
      <guid>https://dev.to/shidhincr/harnessing-ai-to-debug-and-optimize-web-performance-a-guide-to-chrome-devtools-ai-assistance-5h1p</guid>
      <description>&lt;p&gt;In the ever-evolving landscape of web development, staying on top of performance issues and debugging challenges can be time-consuming and complex. Google Chrome has introduced an exciting experimental feature in DevTools that can transform how developers approach these tasks: AI assistance. This powerful addition brings the capabilities of Google's Gemini AI directly into your development workflow, helping you understand, debug, and optimize your web applications more efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Chrome DevTools AI Assistance?
&lt;/h2&gt;

&lt;p&gt;AI assistance in Chrome DevTools is an experimental feature available in Chrome Canary (version 131 and later) that integrates Gemini AI directly into your browser's development environment. Instead of spending hours deciphering cryptic error messages or manually analyzing performance bottlenecks, you can now chat with an AI assistant that has context about your webpage and can provide targeted insights and solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbglmvdiptf59k7k8k7vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbglmvdiptf59k7k8k7vo.png" alt="AI Assistance" width="799" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI assistant can help with various aspects of web development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Styling analysis&lt;/strong&gt;: Understand why elements are displayed in specific ways and how they interact with each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network request debugging&lt;/strong&gt;: Analyze the origin, timing, and potential issues with network requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source code examination&lt;/strong&gt;: Get insights into the purpose and functionality of loaded files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance optimization&lt;/strong&gt;: Identify and address performance bottlenecks in your application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started with AI Assistance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;Before diving in, ensure you meet these requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're at least 18 years old and in a supported location&lt;/li&gt;
&lt;li&gt;You're using the latest version of Chrome (Canary for full feature access)&lt;/li&gt;
&lt;li&gt;You're signed into Chrome with your Google account&lt;/li&gt;
&lt;li&gt;You have English (US) selected in DevTools settings&lt;/li&gt;
&lt;li&gt;You've enabled AI Innovations in DevTools settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Opening the AI Assistance Panel
&lt;/h3&gt;

&lt;p&gt;There are several ways to access the AI assistance panel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;From specific panels&lt;/strong&gt;: Right-click on an element, network request, or performance activity and select "Ask AI"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using the Command Menu&lt;/strong&gt;: Press Ctrl+Shift+P (or Cmd+Shift+P on Mac), type "AI", and select "Show AI assistance"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From the More Tools menu&lt;/strong&gt;: Click on More options (⋮) &amp;gt; More tools &amp;gt; AI assistance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qgjtf87ko476c8gflvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qgjtf87ko476c8gflvp.png" alt=" " width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use AI Assistance for Debugging and Optimization
&lt;/h2&gt;

&lt;p&gt;Let's explore how to leverage this powerful feature for different aspects of web development:&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging CSS and Styling Issues
&lt;/h3&gt;

&lt;p&gt;When confronting styling challenges, AI assistance can be a game-changer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your webpage in Chrome&lt;/li&gt;
&lt;li&gt;Right-click on the problematic element in the Elements panel&lt;/li&gt;
&lt;li&gt;Select "Ask AI" from the context menu&lt;/li&gt;
&lt;li&gt;Ask questions like:

&lt;ul&gt;
&lt;li&gt;"Why is this element overlapping with the header?"&lt;/li&gt;
&lt;li&gt;"How can I fix the responsive behavior of this component?"&lt;/li&gt;
&lt;li&gt;"Why isn't my flexbox layout working as expected?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2ue686erfoxmjlfi1jc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2ue686erfoxmjlfi1jc.png" alt=" " width="799" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI will analyze the context, including CSS inheritance, conflicting styles, and layout interactions, providing explanations and potential solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing Network Performance
&lt;/h3&gt;

&lt;p&gt;For network-related issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the Network panel in DevTools&lt;/li&gt;
&lt;li&gt;Record network activity while loading your page&lt;/li&gt;
&lt;li&gt;Right-click on a slow or problematic request&lt;/li&gt;
&lt;li&gt;Select "Ask AI"&lt;/li&gt;
&lt;li&gt;Ask specific questions like:

&lt;ul&gt;
&lt;li&gt;"Why is this request taking so long?"&lt;/li&gt;
&lt;li&gt;"How can I optimize this API call?"&lt;/li&gt;
&lt;li&gt;"What's causing these multiple similar requests?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgshvaie5qol6xl51dmx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgshvaie5qol6xl51dmx4.png" alt=" " width="658" height="657"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI will analyze request headers, timing, and the request initiator chain to give you insights and optimization suggestions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc5znndtyiuno6ha7il1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc5znndtyiuno6ha7il1.png" alt=" " width="750" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Analyzing Runtime Performance
&lt;/h3&gt;

&lt;p&gt;Performance bottlenecks can be particularly challenging to identify. Here's how AI assistance can help:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Performance panel&lt;/li&gt;
&lt;li&gt;Record a performance profile while interacting with your site&lt;/li&gt;
&lt;li&gt;Right-click on activities that appear to be problematic&lt;/li&gt;
&lt;li&gt;Select "Ask AI"&lt;/li&gt;
&lt;li&gt;Ask questions like:

&lt;ul&gt;
&lt;li&gt;"What's causing this long task?"&lt;/li&gt;
&lt;li&gt;"How can I reduce the time spent on JavaScript execution?"&lt;/li&gt;
&lt;li&gt;"Why are there so many layout recalculations?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbhwr1q1zzysqiq4vu8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbhwr1q1zzysqiq4vu8o.png" alt=" " width="799" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI analyzes the call tree and timings to identify optimization opportunities and explain the root causes of performance issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examining Source Code
&lt;/h3&gt;

&lt;p&gt;Understanding unfamiliar code is much easier with AI assistance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the Sources panel&lt;/li&gt;
&lt;li&gt;Open the file you want to understand&lt;/li&gt;
&lt;li&gt;Right-click on specific sections of code&lt;/li&gt;
&lt;li&gt;Ask the AI questions like:

&lt;ul&gt;
&lt;li&gt;"What is this function doing?"&lt;/li&gt;
&lt;li&gt;"How does this code affect the page rendering?"&lt;/li&gt;
&lt;li&gt;"What could be improved in this code segment?"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aeeqymoq8sk2e9oop62.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aeeqymoq8sk2e9oop62.png" alt=" " width="789" height="854"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for Effective AI Assistance
&lt;/h2&gt;

&lt;p&gt;To get the most out of Chrome DevTools AI assistance, consider these tips:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Ask Specific Questions
&lt;/h3&gt;

&lt;p&gt;The more specific your questions, the more targeted and useful the AI's responses will be. Instead of asking "Why is my page slow?" try "What's causing the long task at the 2-second mark in my performance profile?"&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Provide Context
&lt;/h3&gt;

&lt;p&gt;Ensure you've selected the relevant element, request, or performance activity before asking questions. The AI uses this context to provide accurate answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Follow Up with Clarifications
&lt;/h3&gt;

&lt;p&gt;If the initial answer doesn't fully address your question, ask follow-up questions to drill deeper. The AI maintains conversation history and builds on previous interactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Combine AI Insights with Your Expertise
&lt;/h3&gt;

&lt;p&gt;AI assistance is a powerful tool, but it works best when combined with your development knowledge. Use AI suggestions as a starting point, then apply your understanding of your specific codebase and requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Provide Feedback
&lt;/h3&gt;

&lt;p&gt;Since this is an experimental feature, your feedback is valuable. Use the thumbs up/down buttons to rate answers and help improve the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Optimization Scenarios
&lt;/h2&gt;

&lt;p&gt;Let's explore some practical scenarios where AI assistance can significantly streamline your workflow in the future:&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 1: Fixing Layout Shifts
&lt;/h3&gt;

&lt;p&gt;Cumulative Layout Shift (CLS) issues can be frustrating for users. AI assistance can help pinpoint the cause:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Record a performance profile capturing the layout shift&lt;/li&gt;
&lt;li&gt;Right-click on the relevant layout recalculation activity&lt;/li&gt;
&lt;li&gt;Ask: "What's causing this layout shift and how can I fix it?"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AI might identify that images without defined dimensions are causing the shift and suggest adding width and height attributes to prevent the browser from recalculating layout during image loading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2: Reducing JavaScript Bundle Size
&lt;/h3&gt;

&lt;p&gt;If your page load time is slow due to large JavaScript bundles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the Coverage panel to identify unused JavaScript&lt;/li&gt;
&lt;li&gt;Right-click on a specific JavaScript file with low usage&lt;/li&gt;
&lt;li&gt;Ask: "How can I optimize this JavaScript to reduce bundle size?"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AI might suggest techniques like code splitting, tree shaking, or lazy loading specific components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 3: Optimizing Render Blocking Resources
&lt;/h3&gt;

&lt;p&gt;For pages with render-blocking resources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the Network panel, right-click on a render-blocking CSS or JavaScript file&lt;/li&gt;
&lt;li&gt;Ask: "How can I prevent this resource from blocking rendering?"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AI could recommend using &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt; attributes for scripts, inlining critical CSS, or using resource hints like &lt;code&gt;preload&lt;/code&gt; and &lt;code&gt;preconnect&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Considerations
&lt;/h2&gt;

&lt;p&gt;While the AI assistance feature is powerful, it's important to be aware of its limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Experimental Status&lt;/strong&gt;: As an experimental feature, it may not always provide perfect answers and is subject to change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Usage&lt;/strong&gt;: The feature sends contextual data about your webpage to Google's servers for analysis. Sensitive information in headers is automatically redacted, but be cautious with proprietary code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Potential Inaccuracies&lt;/strong&gt;: Like all AI systems, it may occasionally generate incorrect or misleading information. Always verify critical suggestions before implementation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Language Limitations&lt;/strong&gt;: Currently, the feature is optimized for English (US) and may not work as effectively in other languages.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Chrome DevTools AI assistance represents a significant leap forward in how developers can approach debugging and performance optimization. By bringing AI capabilities directly into the browser development environment, it helps bridge the gap between identifying problems and implementing solutions.&lt;/p&gt;

&lt;p&gt;As web applications grow increasingly complex, tools that can analyze and explain intricate interactions become invaluable. AI assistance in Chrome DevTools doesn't replace developer expertise, but it does augment it in powerful ways, helping you work more efficiently and make informed decisions about optimizing your web applications.&lt;/p&gt;

&lt;p&gt;While still experimental, this feature offers a glimpse into the future of development tools where AI partners with developers to solve challenges and create better web experiences. As you incorporate AI assistance into your workflow, remember to provide feedback to help improve the system and shape the future of AI-powered development tools.&lt;/p&gt;

&lt;p&gt;Start exploring this powerful feature in Chrome Canary today, and experience a new dimension of productivity in your web development process.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Inspecting Speculation rules with Chrome Devtools</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Thu, 20 Mar 2025 16:29:40 +0000</pubDate>
      <link>https://dev.to/shidhincr/inspecting-speculation-rules-with-chrome-devtools-29c9</link>
      <guid>https://dev.to/shidhincr/inspecting-speculation-rules-with-chrome-devtools-29c9</guid>
      <description>&lt;p&gt;[WIP]&lt;/p&gt;

&lt;p&gt;Come back later ...&lt;/p&gt;

</description>
      <category>tooling</category>
    </item>
    <item>
      <title>Faster navigations with Speculations rules api</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Mon, 10 Mar 2025 17:49:40 +0000</pubDate>
      <link>https://dev.to/shidhincr/faster-navigations-with-speculations-rules-api-48n3</link>
      <guid>https://dev.to/shidhincr/faster-navigations-with-speculations-rules-api-48n3</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk" class="crayons-story__hidden-navigation-link"&gt;Speculation Rules API: A New Era of Faster Web Browsing&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shidhincr" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" alt="shidhincr profile" class="crayons-avatar__image" width="710" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shidhincr" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Shidhin
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Shidhin
                
                
              
              &lt;div id="story-author-preview-content-2191496" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shidhincr" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" class="crayons-avatar__image" alt="" width="710" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Shidhin&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 9 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk" id="article-link-2191496"&gt;
          Speculation Rules API: A New Era of Faster Web Browsing
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/speculationrulesapi"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;speculationrulesapi&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/instantnavigation"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;instantnavigation&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/prefetchprerender"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;prefetchprerender&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webperf"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webperf&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            10 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>speculationrulesapi</category>
      <category>instantnavigation</category>
      <category>prefetchprerender</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Speculation Rules API: A New Era of Faster Web Browsing</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Sun, 09 Mar 2025 13:22:19 +0000</pubDate>
      <link>https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk</link>
      <guid>https://dev.to/shidhincr/speculation-rules-api-a-new-era-of-faster-web-browsing-5hhk</guid>
      <description>&lt;p&gt;Imagine using the internet and seeing web pages load immediately, almost like magic. No more waiting or loading screens. This exciting idea is now possible thanks to a new feature called speculation rules. In this blog, we'll learn what speculation rules are, how they work, and see some practical examples you can use in your own projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Speculation rules API
&lt;/h2&gt;

&lt;p&gt;The Speculation rules API is a new web api to improve the navigation speed in multi-page applications. It basically prefetch or prerender the desired pages upon user-interaction or after pageload. By doing prefetching or prerendering, the navigation speed between multiple pages will be significantly reduced. &lt;/p&gt;

&lt;p&gt;Speculation rules give your browser hints about what pages to load next. Imagine hovering over a link, and the browser already starts loading that page in the background, even before you click. This dramatically speeds up browsing and removes frustrating waiting times.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;With speculation rules, browsers can to predict (speculate) which page you're likely to visit next to enhance your experience. This prediction is based on factors like where your mouse is hovering or the links present on the current page. By anticipating your next move, the browser can load pages more efficiently, reducing wait times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefetching vs. Prerendering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two primary methods browsers use to prepare the next page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prefetching&lt;/strong&gt;: This approach involves the browser downloading the basic blueprint of the page—the HTML content—but not rendering it. It's a lighter method that uses fewer resources, ensuring that when you navigate to the page, it loads faster than if it hadn't been prefetched.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prerendering&lt;/strong&gt;: In this method, the browser goes a step further by downloading all resources, such as images and fonts, and fully rendering the page in a hidden tab. This means that when you click the link, the page appears instantly, providing a seamless experience. However, prerendering consumes more resources compared to prefetching.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Setting the Rules with JSON&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Website developers can guide browsers on which pages to prefetch or prerender using the Speculation Rules API, defined in JSON format. This code can be embedded directly into the webpage or delivered via HTTP headers from the web server. The JSON structure specifies the URLs to target and the conditions under which the browser should act. For instance, developers can set the "eagerness" parameter to control how proactively the browser should prefetch or prerender pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;immediate&lt;/strong&gt;: The browser starts prefetching or prerendering as soon as it encounters the rule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;eager&lt;/strong&gt;: Similar to immediate, but may be adjusted in future implementations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;moderate&lt;/strong&gt;: The browser waits until there's a reasonable indication, such as a brief hover over a link, before acting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;conservative&lt;/strong&gt;: The browser waits until you actually click or tap on a link before initiating the prefetch or prerender.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By fine-tuning these settings, developers can optimize resource usage and enhance user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of Speculation Rules in JSON&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's how developers can define speculation rules using JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;where&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href_matches&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eagerness&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moderate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prefetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next2.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;requires&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anonymous-client-ip-when-cross-origin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;referrer_policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-referrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;prerender&lt;/strong&gt; rule instructs the browser to prerender any same-origin link on the page upon hover, with a moderate eagerness setting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;prefetch&lt;/strong&gt; rule tells the browser to prefetch "next.html" and "next2.html", requires anonymization for cross-origin requests, and sets the referrer policy to "no-referrer".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By implementing these rules, developers can significantly improve page load times and provide a smoother browsing experience for users.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the existing &lt;code&gt;&amp;lt;link preload&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;link prefetch&amp;gt;&lt;/code&gt; and
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;link prerender&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2mmjw334rky9cy70e96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2mmjw334rky9cy70e96.png" alt=" " width="719" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Speculation Rules API introduces a more advanced and flexible approach to resource loading, enhancing the capabilities of traditional methods like &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;link rel="prefetch"&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;link rel="prerender"&amp;gt;&lt;/code&gt;. Here's how it improves upon these older mechanisms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; is utilized to load resources essential for the current page, such as fonts, images, and scripts, ensuring they're available when needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limitation&lt;/strong&gt;: It focuses solely on the current page's resources and doesn't anticipate the user's next navigation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speculation Rules Advantage&lt;/strong&gt;: The Speculation Rules API extends this concept by allowing developers to specify resources for subsequent pages the user is likely to visit, enhancing the overall navigation experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;link rel="prefetch"&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Functionality&lt;/strong&gt;: The traditional &lt;code&gt;&amp;lt;link rel="prefetch"&amp;gt;&lt;/code&gt; hint allows browsers to prefetch resources to the HTTP cache, potentially improving load times for future navigations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Challenges&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache-Control Limitations&lt;/strong&gt;: Prefetched resources can be blocked by &lt;code&gt;Cache-Control&lt;/code&gt; headers, limiting their effectiveness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Site Restrictions&lt;/strong&gt;: Cross-site prefetching is often restricted due to security and privacy concerns.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Speculation Rules Enhancement&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory Caching&lt;/strong&gt;: Speculation Rules utilize a per-document in-memory cache, ensuring prefetched documents are processed similarly to regular navigations but aren't rendered until needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Site Prefetching&lt;/strong&gt;: This API supports cross-site prefetching, offering more flexibility compared to the older &lt;code&gt;&amp;lt;link rel="prefetch"&amp;gt;&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bypassing Cache-Control&lt;/strong&gt;: Speculation Rules are not hindered by &lt;code&gt;Cache-Control&lt;/code&gt; headers, making them more reliable for prefetching purposes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;link rel="prerender"&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: The legacy &lt;code&gt;&amp;lt;link rel="prerender"&amp;gt;&lt;/code&gt; was deprecated in favor of NoState Prefetch, which fetched resources without fully rendering the page or executing JavaScript.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Speculation Rules Superiority&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Prerendering&lt;/strong&gt;: The Speculation Rules API enables developers to trigger complete prerendering of pages, including the execution of JavaScript and loading of subresources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Performance&lt;/strong&gt;: This comprehensive prerendering ensures that when a user navigates to the prerendered page, it loads instantly, providing a seamless experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Speculation Rules API Overview&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Target Audience&lt;/strong&gt;: The API is particularly beneficial for multi-page applications (MPAs), allowing developers to specify which documents should be prefetched or prerendered based on user behavior and site structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expressive Syntax&lt;/strong&gt;: It offers a more configurable and expressive syntax, enabling precise control over resource loading strategies to optimize performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By leveraging the Speculation Rules API, developers can implement more efficient and user-centric resource loading strategies, surpassing the capabilities of traditional methods like &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;link rel="prefetch"&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;link rel="prerender"&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The Speculation Rules API offers a structured approach to enhance web performance by enabling browsers to anticipate and load resources for pages users are likely to visit next. This proactive loading can significantly reduce perceived load times and improve user experience. Here's how to implement speculation rules in your HTML:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Embedding a &lt;code&gt;&amp;lt;script type="speculationrules"&amp;gt;&lt;/code&gt; Element&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To define speculation rules, you embed a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element with the attribute &lt;code&gt;type="speculationrules"&lt;/code&gt; directly within your HTML document. This script contains JSON-formatted rules that instruct the browser on prefetching or prerendering behaviors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Speculation Rules Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/next-page.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to My Website&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/next-page.html"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Go to Next Page&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the browser is instructed to prerender &lt;code&gt;/next-page.html&lt;/code&gt;, preparing it in the background so that navigation to it is instantaneous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Defining Rules in JSON Format&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;&amp;lt;script type="speculationrules"&amp;gt;&lt;/code&gt; element, rules are defined using JSON. Each rule specifies the action (&lt;code&gt;prefetch&lt;/code&gt; or &lt;code&gt;prerender&lt;/code&gt;), the source of the URLs, and the list of URLs to be processed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prefetch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/about.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/contact.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prerender"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/dashboard.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the browser is instructed to prefetch &lt;code&gt;/about.html&lt;/code&gt; and &lt;code&gt;/contact.html&lt;/code&gt;, and to prerender &lt;code&gt;/dashboard.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Specifying Pages to Prefetch or Prerender&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;urls&lt;/code&gt; array within each rule specifies which pages the browser should prefetch or prerender. These URLs should be chosen based on user navigation patterns to optimize performance effectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Setting Conditions for Triggering Prefetching or Prerendering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers can control when prefetching or prerendering occurs by setting the &lt;code&gt;eagerness&lt;/code&gt; property within each rule. This property determines how proactively the browser should load the specified resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eagerness Levels:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;immediate&lt;/strong&gt;: The browser starts prefetching or prerendering as soon as it processes the rule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;eager&lt;/strong&gt;: Similar to &lt;code&gt;immediate&lt;/code&gt;, but allows the browser some discretion based on resource availability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;moderate&lt;/strong&gt;: The browser waits until there's a reasonable indication of user interest, such as hovering over a link.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;conservative&lt;/strong&gt;: The browser waits until the user initiates navigation, such as clicking a link.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example with Eagerness Setting:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"speculationrules"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prerender&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;source&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;urls&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/promo.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eagerness&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moderate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the browser will prerender &lt;code&gt;/promo.html&lt;/code&gt; when it detects moderate user interest, such as a brief hover over a related link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Considerations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source Specification&lt;/strong&gt;: The &lt;code&gt;source&lt;/code&gt; property indicates how the URLs are determined. For instance, &lt;code&gt;"source": "list"&lt;/code&gt; means the URLs are explicitly listed, while other methods can derive URLs based on patterns or user behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser Support&lt;/strong&gt;: As of now, the Speculation Rules API is supported in Chromium-based browsers like Chrome, Edge, and Opera. It's advisable to implement fallback mechanisms for browsers that do not support this API.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By thoughtfully implementing the Speculation Rules API, developers can significantly enhance the responsiveness of their websites, leading to a smoother and more engaging user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the Browser Support
&lt;/h2&gt;

&lt;p&gt;As of now, the Speculation Rules API is supported in Chromium-based browsers, including Chrome, Edge, and Opera. However, it is not yet available in Firefox or Safari. Despite this limited support, implementing the Speculation Rules API is safe because browsers that do not recognize it will simply ignore the &lt;code&gt;&amp;lt;script type="speculationrules"&amp;gt;&lt;/code&gt; element without causing any issues.​&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported Browsers: Chrome, Edge, Opera (Chromium-based browsers).​
Unsupported Browsers: Firefox, Safari.​&lt;/li&gt;
&lt;li&gt;Market Coverage: Chromium-based browsers account for approximately 70% of the global browser market. ​&lt;/li&gt;
&lt;li&gt;Backward Compatibility: Non-supporting browsers will ignore the Speculation Rules API without any adverse effects. ​&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Debugging in Chrome browser
&lt;/h2&gt;

&lt;p&gt;To debug Speculation Rules in Chrome, use Chrome DevTools.&lt;/p&gt;

&lt;p&gt;Here’s how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Open DevTools:&lt;/strong&gt; Open Chrome DevTools before loading the page containing the speculation rules. This ensures speculations are captured correctly.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Navigate to the Speculative Loads Tab:&lt;/strong&gt; Go to the &lt;strong&gt;Application&lt;/strong&gt; panel, then &lt;strong&gt;Background Services&lt;/strong&gt;, and select the &lt;strong&gt;Speculative loads&lt;/strong&gt; tab. Then choose the &lt;strong&gt;Speculations pane&lt;/strong&gt;. If nothing appears, ensure you're on the correct page and DevTools was loaded before navigation; reload the page if necessary.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Inspect Speculations:&lt;/strong&gt; In the Speculations tab, you can view the URLs being prefetched or prerendered. Click on a line to see details if a page fails to prerender, including reasons for failure, such as incompatible JavaScript APIs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Check Speculative Loading Status:&lt;/strong&gt; To confirm whether a page was prerendered or prefetched, inspect the Application panel to see the &lt;strong&gt;Speculative loading status&lt;/strong&gt; for the current page.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Monitor Network Activity:&lt;/strong&gt; The &lt;strong&gt;Network track&lt;/strong&gt; in the &lt;strong&gt;Performance Panel&lt;/strong&gt; shows network activity related to prerendered resources without switching DevTools context.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sort by Status:&lt;/strong&gt; Sort the Speculations pane by the &lt;strong&gt;Status&lt;/strong&gt; column to identify pages that are prerendering as you hover over them. Clicking on them will show a quicker Largest Contentful Paint (LCP) time compared to non-prerendered pages.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Examine Chrome's Address Bar Predictions:&lt;/strong&gt; To view Chrome's predictions for URLs, go to the &lt;code&gt;chrome://predictors&lt;/code&gt; page. Green lines indicate sufficient confidence to trigger prerendering.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Use the Console to Test Prerendering:&lt;/strong&gt; After a page is activated, open DevTools and type &lt;code&gt;performance.getEntriesByType('navigation').activationStart&lt;/code&gt; in the console. A non-zero value indicates the page was prerendered.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Simulate Different Network Conditions:&lt;/strong&gt; Use the throttling options in the Network tab to simulate different network speeds and see how speculation rules perform under various conditions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Feature Detection&lt;/strong&gt; Use feature detection code to determine if the browser supports speculation rules. If the browser doesn't support speculation rules, implement older technologies such as &lt;code&gt;&amp;lt;link rel="prefetch"&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftoxhqxhwg8lkeyop6u9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftoxhqxhwg8lkeyop6u9b.png" alt=" " width="800" height="817"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpepiho9rqcgk8uvx0bcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpepiho9rqcgk8uvx0bcy.png" alt=" " width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Applications of the Speculation Rules API
&lt;/h2&gt;

&lt;p&gt;E-commerce platforms greatly benefit from the Speculation Rules API. On these platforms, users regularly browse through various product pages, category listings, and search results. By applying prefetching or prerendering to these pages, the shopping experience becomes smoother and quicker. This immediate responsiveness not only improves customer satisfaction but can also lead to higher conversion rates, as shoppers are less likely to abandon the site due to slow loading times.&lt;/p&gt;

&lt;p&gt;Blogs featuring multiple articles or content spread across multiple pages can similarly enhance user experience using this API. By prefetching or prerendering subsequent articles or pagination pages, readers experience seamless navigation. This approach encourages users to explore more content effortlessly, significantly improving their engagement and satisfaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Implementing Speculation Rules API
&lt;/h2&gt;

&lt;p&gt;A key advantage of using the Speculation Rules API is significantly reducing the perceived load times by preloading resources in advance. Prefetching resources or fully prerendering pages enables nearly instantaneous page transitions when navigating through the website, creating a smoother, more responsive browsing experience. Such improvements are crucial for retaining user interest and increasing their satisfaction.&lt;/p&gt;

&lt;p&gt;Enhanced performance resulting from prefetching and prerendering also has positive effects on user engagement metrics, such as reduced bounce rates and prolonged sessions. The smoother and more responsive user experience encourages visitors to explore additional content, increasing the likelihood of conversions and repeat visits. Additionally, these improvements in page performance can positively impact search engine optimization (SEO), helping websites rank better in search results.&lt;/p&gt;

&lt;p&gt;The Speculation Rules API also ensures efficient use of resources by allowing browsers to initiate prefetching only when sufficient resources, such as memory and network bandwidth, are available. Developers can fine-tune when resources are preloaded using eagerness settings (immediate, eager, moderate, conservative), ensuring effective utilization without wasteful preloading.&lt;/p&gt;

&lt;p&gt;Moreover, improvements in caching mechanisms mean that prefetched or prerendered resources are stored efficiently and reused when required. Even if speculated pages are not immediately accessed, these resources provide future benefits, further improving overall site performance and responsiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Considerations for Implementing Speculation Rules API
&lt;/h2&gt;

&lt;p&gt;When implementing the Speculation Rules API, it's important to understand both the API and your website's specific needs. Ensure you avoid applying rules to sensitive routes such as logout, language-switching, or shopping cart actions to prevent unintended consequences.&lt;/p&gt;

&lt;p&gt;Regularly monitoring and adjusting your preloading rules is crucial. Analyze user behavior using tools like Google Analytics and Real User Monitoring (RUM) to identify optimal preloading strategies. Adjust rules based on insights to balance effective resource use with performance gains.&lt;/p&gt;

&lt;p&gt;Lastly, be aware of the potential increased server load due to prefetching and prerendering. This can impact server resources, bandwidth, and costs. Use caching wisely and update client-side scripts carefully, particularly for personalized content, to ensure optimal and efficient performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In summary, the Speculation Rules API is a powerful tool for enhancing web performance, primarily in multi-page applications (MPAs), by proactively prefetching or prerendering potential next pages. It allows the browser to start loading a subsequent page before a user even clicks a link, making navigation feel nearly instantaneous. By strategically implementing this API, developers can significantly improve user experience and potentially boost Core Web Vitals&lt;/p&gt;

</description>
      <category>speculationrulesapi</category>
      <category>instantnavigation</category>
      <category>prefetchprerender</category>
      <category>webperf</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Sun, 09 Mar 2025 13:08:02 +0000</pubDate>
      <link>https://dev.to/shidhincr/-1a3b</link>
      <guid>https://dev.to/shidhincr/-1a3b</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" class="crayons-story__hidden-navigation-link"&gt;Live core web vitals (local metrics) in browser devtools&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shidhincr" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" alt="shidhincr profile" class="crayons-avatar__image" width="710" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shidhincr" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Shidhin
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Shidhin
                
                
              
              &lt;div id="story-author-preview-content-2169817" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shidhincr" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" class="crayons-avatar__image" alt="" width="710" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Shidhin&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 22 '24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" id="article-link-2169817"&gt;
          Live core web vitals (local metrics) in browser devtools
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devtools"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devtools&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/corewebvitals"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;corewebvitals&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/inp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;inp&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>devtools</category>
      <category>corewebvitals</category>
      <category>inp</category>
    </item>
    <item>
      <title>Core Web Vitals</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Sun, 09 Mar 2025 13:06:33 +0000</pubDate>
      <link>https://dev.to/shidhincr/-4998</link>
      <guid>https://dev.to/shidhincr/-4998</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3" class="crayons-story__hidden-navigation-link"&gt;Performance Audit: Analyzing Namshi’s Mobile Website with Live Core Web Vitals&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shidhincr" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" alt="shidhincr profile" class="crayons-avatar__image" width="710" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shidhincr" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Shidhin
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Shidhin
                
                
              
              &lt;div id="story-author-preview-content-2177559" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shidhincr" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" class="crayons-avatar__image" alt="" width="710" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Shidhin&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 27 '24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3" id="article-link-2177559"&gt;
          Performance Audit: Analyzing Namshi’s Mobile Website with Live Core Web Vitals
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devtools"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devtools&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/corewebvitals"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;corewebvitals&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>devtools</category>
      <category>corewebvitals</category>
      <category>performance</category>
    </item>
    <item>
      <title>Performance Audit: Analyzing Namshi’s Mobile Website with Live Core Web Vitals</title>
      <dc:creator>Shidhin</dc:creator>
      <pubDate>Fri, 27 Dec 2024 13:13:40 +0000</pubDate>
      <link>https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3</link>
      <guid>https://dev.to/shidhincr/perf-audit-namshis-mobile-website-using-live-core-web-vitals-1j3</guid>
      <description>&lt;p&gt;If you’re new to Live Core Web Vitals, check out my previous post:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" class="crayons-story__hidden-navigation-link"&gt;Live core web vitals (local metrics) in browser devtools&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/shidhincr" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" alt="shidhincr profile" class="crayons-avatar__image" width="710" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/shidhincr" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Shidhin
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Shidhin
                
                
              
              &lt;div id="story-author-preview-content-2169817" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/shidhincr" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F114922%2F41d6e8ce-a9c5-4f6e-9ce8-97a4dbb9cadb.jpeg" class="crayons-avatar__image" alt="" width="710" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Shidhin&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 22 '24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" id="article-link-2169817"&gt;
          Live core web vitals (local metrics) in browser devtools
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devtools"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devtools&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/corewebvitals"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;corewebvitals&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/inp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;inp&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/shidhincr/local-live-core-web-vital-metrics-in-the-devtools-2hlc#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  What Are We Going to Do?
&lt;/h2&gt;

&lt;p&gt;Namshi is one of the largest e-commerce websites in the UAE. Having worked at Namshi before, I was curious to test the Core Web Vitals scores of their mobile website and evaluate the user experience.&lt;/p&gt;

&lt;p&gt;I started with their most visited webpage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.namshi.com/uae-en/fashion/women-fashion/" rel="noopener noreferrer"&gt;Namshi: Women's Fashion&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpi5noscwo3aj26f9rbva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpi5noscwo3aj26f9rbva.png" alt="Namshi web vitals" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using a high-speed Wi-Fi network and an M3 Pro MacBook, I conducted the test without any network or CPU throttling. The LCP (Largest Contentful Paint) score was 2.84 seconds, indicating room for improvement. The LCP metric primarily points to the banner image in the carousel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Suggestions for improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use smaller placeholder images for banners.&lt;/li&gt;
&lt;li&gt;Preload banner images(using link preload directive).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I interacted with the page, the other metrics appeared satisfactory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs942kh1u6mj881w99q4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs942kh1u6mj881w99q4j.png" alt="Namshi web vitals" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding slowness
&lt;/h2&gt;

&lt;p&gt;Namshi’s website heavily relies on modal components for features like Sort, Filter, and Search. While most modals opened and closed quickly, I noticed occasional slowness patterns. The INP (Interaction to Next Paint) score fluctuated between 60-100ms, which is generally acceptable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkbnw1jkpzha64gypvxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkbnw1jkpzha64gypvxg.png" alt="Namshi web vitals" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, I discovered main-thread blocking code when toggling the “New Arrivals” modal and attempting to close it. This directly impacted the INP score. You can see the behavior in the video below:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/prFrqpwH_TM" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Worse Version?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, I found an even worse scenario where the INP score turned completely RED.&lt;/p&gt;

&lt;p&gt;This occurred when I opened the “Filter” modal, applied some filters, and then clicked “Reset Filters”. The page froze momentarily, resulting in a poor user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc2pzlrd9iwhzftjnzkc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc2pzlrd9iwhzftjnzkc.png" alt="Namshi web vitals" width="800" height="748"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Suggestions for improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid blocking the main thread during user interactions, especially while applying filters.&lt;/li&gt;
&lt;li&gt;Use Web Workers for computationally intensive tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Another Observation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/PxdoNdmKlWo" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;By recording a Performance Profile, the issue was clearly visible in the flame chart. This method is invaluable for identifying and addressing performance bottlenecks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cavs2y9hhsmykut0x9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cavs2y9hhsmykut0x9k.png" alt="Recording flame chart" width="592" height="1231"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devtools</category>
      <category>corewebvitals</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
