<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged chrome</title>
<link>https://coderlegion.com/tag/chrome</link>
<description>Powered by Question2Answer</description>
<item>
<title>Bridging Model Context Protocol (MCP) to Browser Agents via W3C WebMCP (document.modelContext)</title>
<link>https://coderlegion.com/32204/bridging-model-context-protocol-mcp-browser-agents-via-w3c-webmcp-document-modelcontext</link>
<description>&lt;p&gt;As AI agents move from local developer runtimes (like Claude Desktop and Cursor) into browser environments, developers face a major integration challenge: how to expose structured backend tools to client-side agents securely and without fragile DOM scraping.&lt;/p&gt;
&lt;p&gt;At SEOSiri, we solved this by implementing the W3C WebMCP specification (document.modelContext). Our central developer portal dynamically registers our entire autonomous tool catalog on boot, proxying execution requests seamlessly through secure, stateless Cloudflare Edge Gateways.&lt;/p&gt;
&lt;p&gt;Key Technical Implementation Highlights:&lt;/p&gt;
&lt;p&gt;Dynamic Universal Registry: Automatically loops through master component registers to bind server schemas into browser runtimes.&lt;br&gt;
Edge Proxying &amp;amp; Security: Ensures zero secret exposure by keeping backend encryption keys locked inside Cloudflare Worker environment variables while marshaling public JSON-RPC requests across HTTPS.&lt;br&gt;
Namespace Segregation: Explicitly namespaced tool identifiers prevent collision with browser default diagnostic suites.&lt;br&gt;
Native DevTools Debugging: Streamlines inspection and verification via the Chrome DevTools WebMCP application panel.&lt;/p&gt;
&lt;p&gt;Read the Full Engineering Walkthrough:&lt;br&gt;
🔗 &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.seosiri.com/2026/10/webmcp-chrome-mcp-tools-guide.html&quot;&gt;https://www.seosiri.com/2026/10/webmcp-chrome-mcp-tools-guide.html&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;coderlegion-webdev-aiagents-mcp-typescript-architecture-edgecomputing&quot;&gt;coderlegion #webdev #aiagents #mcp #typescript #architecture #edgecomputing&lt;/h2&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32204/bridging-model-context-protocol-mcp-browser-agents-via-w3c-webmcp-document-modelcontext</guid>
<pubDate>Fri, 23 Oct 2026 16:11:38 +0000</pubDate>
</item>
<item>
<title>Shipped: the FSCSS Browser IDE</title>
<link>https://coderlegion.com/31842/shipped-the-fscss-browser-ide</link>
<description>&lt;p&gt;&lt;strong&gt;Multi-file FSCSS in the browser — compile, preview, enable packages, export plain CSS.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No install required. Open &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/ide&quot;&gt;fscss.devtem.org/ide&lt;/a&gt; and work.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-it-is&quot;&gt;What it is&lt;/h3&gt;
&lt;p&gt;The FSCSS IDE is a single-page workspace for &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org&quot;&gt;Figured Shorthand CSS&lt;/a&gt;: write &lt;code&gt;.fscss&lt;/code&gt;, compile to standard CSS, preview HTML, and pull community modules without leaving the tab.&lt;/p&gt;
&lt;p&gt;It targets the same language as the CLI and CDN runtime (&lt;code&gt;fscss@1.2.6+&lt;/code&gt;). Prototypes stay in the browser; production still ships &lt;strong&gt;compiled CSS&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;layout-quick-map-&quot;&gt;Layout (quick map)&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Area &lt;/th&gt;&lt;th&gt;Role&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Top bar&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Run, Preview, Auto-compile, Export, Import, theme, settings&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Left&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Files, Components, Snippets, Tools&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Center&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Monaco editor + file tabs&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Right&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Compiled CSS / live Preview&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Bottom&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Terminal + Problems&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Compiler version, errors, cursor&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Drag the dividers. On phones the sidebar overlays and panes stack.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;quick-start&quot;&gt;Quick start&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open or create &lt;code&gt;main.fscss&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ctrl+Enter&lt;/strong&gt; — compile (CSS on the right).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ctrl+Shift+Enter&lt;/strong&gt; — compile and open preview.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Export&lt;/strong&gt; — CSS, minified CSS, HTML, ZIP, or JSON backup.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Autosave uses &lt;code&gt;localStorage&lt;/code&gt; (keys under &lt;code&gt;fside:&lt;/code&gt;). Export a backup if the browser blocks storage.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;multi-file-and-import&quot;&gt;Multi-file and &lt;code&gt;@import&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The workspace is a virtual file system. Local imports resolve against the importing file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@import((widget-root, widget-card) from &quot;./widgets.fscss&quot;)
@import((*) from st-core@v2)
@import((mirror, stagger) from fscss:micros)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Selective names, aliases (&lt;code&gt;as&lt;/code&gt;), wildcards, and registry-style names work the same way as in the CLI. Remote URLs need quotes; listed library names usually do not.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;packages-libck-libon-xfcmd&quot;&gt;Packages: &lt;code&gt;libck&lt;/code&gt; / &lt;code&gt;libon&lt;/code&gt; / xfcmd&lt;/h3&gt;
&lt;p&gt;Open the terminal (&lt;strong&gt;Ctrl+`&lt;/strong&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;libck st-core
yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or a full repo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;libck https://github.com/fscss-ttr/overlapui.fscss
yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The IDE loads &lt;code&gt;package.json&lt;/code&gt;, checks &lt;code&gt;fscss_version&lt;/code&gt;, downloads &lt;code&gt;file.modules&lt;/code&gt;, verifies &lt;code&gt;@define&lt;/code&gt; helpers, then runs the pack’s &lt;strong&gt;enable&lt;/strong&gt; script when you confirm. Typical enable flow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;snippets for public helpers  &lt;/li&gt;
&lt;li&gt;a small demo folder  &lt;/li&gt;
&lt;li&gt;compile + preview  &lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;liboff st-core
xfcmd list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Disable removes snippets; demo files stay unless you delete them. Authoring side: &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/xfcmds-guide&quot;&gt;xfcmds guide&lt;/a&gt; · &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/modules-guide&quot;&gt;modules guide&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-else-is-built-in&quot;&gt;What else is built in&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Monaco&lt;/strong&gt; — FSCSS highlighting, folding, snippets  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Component search&lt;/strong&gt; — registry helpers, one-click import  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compiler version&lt;/strong&gt; — load another &lt;code&gt;fscss@x.y.z&lt;/code&gt; from jsDelivr  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-compile&lt;/strong&gt; while typing (toggle)  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PWA-style&lt;/strong&gt; install chrome on supported browsers  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Console&lt;/strong&gt; — &lt;code&gt;window.xfscss&lt;/code&gt; for ad-hoc API checks  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Docs: &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/ide-guide&quot;&gt;IDE guide&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;example-three-lines-many-classes&quot;&gt;Example: three lines → many classes&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@arr classes[ count(1000, 1) ]
*Emails are not allowed*ses[] {
  margin: @arr.classes[]px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compile in the IDE and scroll the CSS pane — or open a prefilled buffer:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/ide#code=%40arr%20classes%5B%20count(1000%2C%201)%20%5D%0A.item-%40arr.classes%5B%5D%20%7B%0A%20%20%20%20margin%3A%20%40arr.classes%5B%5Dpx%3B%0A%20%20%7D&quot;&gt;Open in IDE&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;example-enable-a-pack&quot;&gt;Example: enable a pack&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;libck st-core
yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in a new &lt;code&gt;.fscss&lt;/code&gt; file (or the generated demo):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@import((*) from st-core@v2)
@st-root()
@arr data[42, 58, 65, 60, 78, 70, 92]
@st-chart-fill(.fill, data)
@st-chart-line(.line, data)
.chart {
  @st-chart-points(data)
  position: relative;
  height: 220px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HTML: a &lt;code&gt;.chart&lt;/code&gt; with &lt;code&gt;.fill&lt;/code&gt; and &lt;code&gt;.line&lt;/code&gt; children. Preview updates after compile. Same contract as the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/fscss-ttr/st-core.fscss&quot;&gt;st-core&lt;/a&gt; templates: JS only patches &lt;code&gt;--st-pN&lt;/code&gt; when data changes.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;ship-path&quot;&gt;Ship path&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Stage &lt;/th&gt;&lt;th&gt;Tool&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Learn / combine modules &lt;/td&gt;&lt;td&gt;IDE + runtime CDN&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Real multi-file project &lt;/td&gt;&lt;td&gt;IDE export ZIP or clone + CLI&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Production &lt;/td&gt;&lt;td&gt;&lt;code&gt;fscss in.fscss out.css&lt;/code&gt; — no browser compiler on the live site&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install -g fscss@1.2.6
fscss src/site.fscss dist/site.css
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;links&quot;&gt;Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IDE:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/ide&quot;&gt;fscss.devtem.org/ide&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IDE guide:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/ide-guide&quot;&gt;fscss.devtem.org/ide-guide&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;xfcmds:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/xfcmds-guide&quot;&gt;fscss.devtem.org/xfcmds-guide&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language docs:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/docs&quot;&gt;fscss.devtem.org/&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Libraries:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://fscss.devtem.org/libraries&quot;&gt;fscss.devtem.org/libraries&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core repo:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Figsh/xfscss&quot;&gt;github.com/Figsh/xfscss&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modules org:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/fscss-ttr&quot;&gt;github.com/fscss-ttr&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hub tutorial:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://hub.devtem.org/tutorial&quot;&gt;hub.devtem.org/tutorial&lt;/a&gt;  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;The IDE is meant to lower the cost of &lt;em&gt;trying&lt;/em&gt; FSCSS: multi-file imports, package enable in one terminal prompt, and a clear export to plain CSS. It does not replace the CLI for production builds—it shortens the path until you need one.&lt;/p&gt;
&lt;p&gt;Open it, hit &lt;strong&gt;Ctrl+Enter&lt;/strong&gt;, and if a pack has an enable script, &lt;code&gt;libon&lt;/code&gt;  is enough to see a demo.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31842/shipped-the-fscss-browser-ide</guid>
<pubDate>Tue, 20 Oct 2026 11:57:23 +0000</pubDate>
</item>
<item>
<title>Vue.js Web Browser Extension Template</title>
<link>https://coderlegion.com/29753/vue-js-web-browser-extension-template</link>
<description>&lt;p&gt;Starting out with browser extensions can often be a pain in the back.&lt;/p&gt;
&lt;p&gt;A while back, I was looking for a template I could use to build Epubespiar. Most of the ones I tried had the same problem: I couldn’t get them started and running. Since this was my first time building an extension, that was really frustrating.&lt;/p&gt;
&lt;p&gt;The instructions would say something like: &lt;em&gt;clone&lt;/em&gt; the project, &lt;em&gt;pnpm install&lt;/em&gt;, then &lt;em&gt;pnpm run dev&lt;/em&gt;. After that, Chrome would suddenly open and... voilà. A blank tab, staring at you as if asking, &quot;what are you doing, bruv?&quot; And if you didn't have Chrome installed and wanted to check the template UI in Firefox, hell broke loose. :P&lt;/p&gt;
&lt;p&gt;So you'd end up back in a 500+ line codebase, trying to figure out what was actually breaking and that can be demoralizing, yeah. Imagine signing up to a social platform and, on first impression... not being able to create posts or publish content the way you would on other apps. Sucks, right?&lt;/p&gt;
&lt;p&gt;After a few trials, I decided to build Epubespiar from the ground up with &lt;strong&gt;Vue.js&lt;/strong&gt;. Since then, life has been good.&lt;/p&gt;
&lt;p&gt;Recently, that experience stuck with me, so I built a browser extension template to help developers get their extensions up much quicker.&lt;/p&gt;
&lt;p&gt;All you need is the repo in your dev environment, then:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pnpm install&lt;/code&gt; thereafter, &lt;code&gt;pnpm run dev:all&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;What you see next should feel familiar, and if you're a web developer, it's even easier, because it follows the same flow you already use day to day. The UI runs on localhost which you can open in any browser, be it &lt;strong&gt;Chromium-based&lt;/strong&gt; or &lt;strong&gt;Gecko/Firefox&lt;/strong&gt; for testing.&lt;/p&gt;
&lt;p&gt;Try it here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/rezzcode/vuejs-extensions.git&quot;&gt;https://github.com/rezzcode/vuejs-extensions.git&lt;/a&gt; and tell me what you think.&lt;/p&gt;
</description>
<category>Launches</category>
<guid isPermaLink="true">https://coderlegion.com/29753/vue-js-web-browser-extension-template</guid>
<pubDate>Sun, 04 Oct 2026 18:51:54 +0000</pubDate>
</item>
<item>
<title>Put Chrome Stable on the same calendar as your deploys</title>
<link>https://coderlegion.com/28277/put-chrome-stable-on-the-same-calendar-as-your-deploys</link>
<description>&lt;p&gt;When field LCP moves and the app calendar is empty, the missing row is usually Chrome Stable, not a ghost commit.&lt;/p&gt;
&lt;p&gt;Field Largest Contentful Paint can move while your application release calendar stays empty. The spreadsheet already lists app deploys, CDN config changes, tag-manager publishes, and RUM or instrumentation bumps. From Chrome 153 Stable on 8 September 2026, Chrome ships a new Stable (and Beta) every two weeks on Desktop, Android, and iOS. Leave Chrome Stable off that same sheet and you will keep blaming ghost commits for shifts that are only population mix.&lt;/p&gt;
&lt;p&gt;The ritual fix is dull on purpose: browser Stable and Beta sit next to the changes you already annotate, one named owner writes the date before the graph moves, and the monthly pack stops inventing regressions. CrUX math and sample thresholds live on our Watcher how-to. Ownership of the calendar is the piece that makes those reports honest.&lt;/p&gt;
&lt;h3 id=&quot;why-chrome-stable-belongs-beside-deploys&quot;&gt;Why Chrome Stable belongs beside deploys&lt;/h3&gt;
&lt;p&gt;Chrome User Experience Report field data is a rolling blend of real Chrome sessions, not a snapshot of yesterday’s build. When a new Stable major enters that mix, paint timing, decoding, lazy-load heuristics, or interaction scheduling can shift for the same URL while your HTML and bundles stay byte-identical. Faster Stable cadence simply raises how often that mix changes inside one reporting window.&lt;/p&gt;
&lt;p&gt;Google’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/blog/chrome-two-week-release&quot;&gt;two-week release announcement&lt;/a&gt; is the schedule source. From Chrome 153, Beta and Stable promote every two weeks; Extended Stable keeps its eight-week enterprise cycle. Firefox has been running a similar fortnightly experiment around the same period. Agencies that only annotated application cuts in 2025 now need browser rows in 2026, or every Stable Tuesday becomes an unexplained ticket.&lt;/p&gt;
&lt;p&gt;Harry Roberts put the measurement framing cleanly in &lt;a rel=&quot;nofollow&quot; href=&quot;https://csswizardry.com/2026/08/web-perf-wednesday-006-faster-browser-releases-change-your-rum-population/&quot;&gt;Web-Perf Wednesday 006&lt;/a&gt;: faster browser releases change the RUM population you are averaging. The agency failure mode is narrower than the measurement essay. Teams open a regression hunt because the shared calendar never recorded that Chrome moved.&lt;/p&gt;
&lt;h3 id=&quot;what-belongs-on-one-shared-release-calendar&quot;&gt;What belongs on one shared release calendar&lt;/h3&gt;
&lt;p&gt;One calendar per client portfolio beats five tools that never meet. Useful rows are the changes that can move field percentiles, or look like they did. Share those rows on one sheet and a quiet week has a readable explanation instead of five disconnected notification emails.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Change type &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;What to record &lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Why it belongs&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Application deploy &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Environment, git SHA or release tag, money URLs touched &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Origin change you control&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;CDN / cache / edge &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Config version, purge scope, rule ID &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Delivery change without an app tag&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Tag manager / third-party &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Container version, publish time &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Main-thread and LCP side effects&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;RUM / instrumentation &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Library version, sampling or route rules &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Collection change that looks like a metric shift&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Chrome Stable / Beta &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Milestone, channel, scheduled date &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Browser population entering field windows&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Firefox Stable / Beta &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Milestone, channel, scheduled date &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Same population logic for Firefox-heavy audiences&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Extended Stable (if relevant) &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Cohort lag vs consumer Stable &lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Enterprise mix that updates on a different clock&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The browser date is an &lt;strong&gt;annotation&lt;/strong&gt;, not a claim that every visitor updated at once. First-party RUM helps here: version share beside that marker shows how fast the cohort actually moved. Dates belong on the sheet the same week you plan app cuts (from &lt;a rel=&quot;nofollow&quot; href=&quot;https://chromestatus.com/roadmap&quot;&gt;Chrome Status&lt;/a&gt;, Chromium dashboards, and the Firefox release calendar), not after a client asks why LCP went amber.&lt;/p&gt;
&lt;p&gt;Beta still earns a row. Chrome ships a Beta about three weeks before Stable, so there is time to check real journeys, metric completion, soft-navigation detection, and browser-specific dimensions. That is a routine rehearsal, not a late smoke test the day before Stable.&lt;/p&gt;
&lt;h3 id=&quot;name-an-owner-before-the-graph-moves&quot;&gt;Name an owner before the graph moves&lt;/h3&gt;
&lt;p&gt;Annotations without an owner die in the same week they are invented. The workable pattern is one named person (or rotating role) who adds Chrome and Firefox Stable and Beta dates &lt;strong&gt;before&lt;/strong&gt; field charts update. In most retainers that is the technical lead who already owns the monthly Core Web Vitals pack, not “whoever notices Slack first.”&lt;/p&gt;
&lt;p&gt;A workable weekly habit looks like this. On Monday, skim the next two Stable dates and paste them onto the shared calendar. After any app, CDN, tag, or RUM change, add that row the same day. When field LCP, INP, or CLS moves, the calendar opens &lt;strong&gt;before&lt;/strong&gt; the bug tracker: if a browser milestone sits inside the collection window and the origin rows are quiet, population mix is the first question, not a phantom deploy.&lt;/p&gt;
&lt;p&gt;Waiting until the percentile has already moved is too late. With a major every fortnight, “we will annotate when something looks weird” means the annotation arrives after the client argument has started. The calendar is useful when the date was already written the moment someone first noticed the amber band.&lt;/p&gt;
&lt;h3 id=&quot;when-field-lcp-shifts-with-no-deploy-check-population-mix-first&quot;&gt;When field LCP shifts with no deploy: check population mix first&lt;/h3&gt;
&lt;p&gt;Run a short triage before you escalate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Confirm the app, CDN, tag-manager, and instrumentation rows for the collection window are empty (or explain the ones that are not).&lt;/li&gt;
&lt;li&gt;Check whether a Chrome or Firefox Stable (or Extended Stable lag) sits inside the same dates.&lt;/li&gt;
&lt;li&gt;Look at version share and sample size before trusting a single-major p75 slice.&lt;/li&gt;
&lt;li&gt;Keep an &lt;strong&gt;unsegmented&lt;/strong&gt; field series as the executive headline; use browser-major slices as engineer appendix material.&lt;/li&gt;
&lt;li&gt;Pair with a scheduled lab run on the same money URLs so you can say the origin critical path did not move this week.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Population mix means the aggregate changed because the audience composition changed: more sessions on a new Stable, fewer on the previous major, or a campaign that shifted which templates dominate. Site regression is narrower. The same browser version and a similar journey got worse after a change you control. Confusing the two burns engineering time and weakens the next real alert.&lt;/p&gt;
&lt;p&gt;For the full field-window and sample-threshold treatment, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-lcp-moves-nobody-deployed-browser-release-cadence-28-day-field-window?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=put-chrome-stable-on-the-same-calendar-as-your-deploys&quot;&gt;When LCP Moves and Nobody Deployed: Browser Release Cadence and Your 28-Day Field Window&lt;/a&gt; owns the CrUX clocks and reporting templates. The job here is smaller. Put Chrome on the sheet before anyone argues about a ghost commit.&lt;/p&gt;
&lt;h3 id=&quot;browser-release-cadence-versus-crux-pipeline-lag&quot;&gt;Browser release cadence versus CrUX pipeline lag&lt;/h3&gt;
&lt;p&gt;Two different delays get conflated in client calls. &lt;strong&gt;Pipeline lag&lt;/strong&gt; is when a verified fix (or a real regression) takes time to appear in published CrUX / PageSpeed Insights field sections because collection and processing are not instant. &lt;strong&gt;Browser cadence inside the window&lt;/strong&gt; is different: the rolling 28-day mix already includes more than one Stable major, so the percentile can move with no origin change at all.&lt;/p&gt;
&lt;p&gt;“We shipped Friday and field still looks old” points at &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/crux-pipeline-delays-late-field-data-client-reports?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=put-chrome-stable-on-the-same-calendar-as-your-deploys&quot;&gt;CrUX pipeline delays and late field data in client reports&lt;/a&gt;. “Nobody deployed and LCP still moved” points at the shared calendar and population mix. Lab green beside field amber is a third conversation, so folding all three into one vague “CrUX is slow” answer helps nobody.&lt;/p&gt;
&lt;p&gt;Scheduled monitoring still helps. Same-week lab evidence on money URLs, portfolio alerts on your thresholds, and dated annotations clients can read without a statistics lecture make the calendar useful in the monthly pack. Watcher layers onto that workflow. It does not replace the release calendar you already maintain.&lt;/p&gt;
&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Does every Chrome Stable need a client email?&lt;/strong&gt;&lt;br&gt;
No. Most Stable dates are quiet annotations on the internal sheet. Client email makes sense when field bands move &lt;em&gt;and&lt;/em&gt; the calendar shows a browser milestone with no origin change, or when sample counts are large enough that a major-specific shift is worth explaining in the monthly pack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if we only have CrUX, not first-party RUM?&lt;/strong&gt;&lt;br&gt;
Stable and Beta still belong on the calendar. Without version share charts you cannot prove mix as tightly, so the honest pack leans on unsegmented field series, lab pairing, and careful wording (“browser release inside the collection window” rather than “Chrome 153 caused this”).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Should we slice every report by Chrome major?&lt;/strong&gt;&lt;br&gt;
Only when sample counts support it. Thin major slices manufacture weekly false regressions that look decisive in a slide and evaporate under scrutiny. Unsegmented headlines stay safer for leadership; major splits belong in engineering follow-up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where do Extended Stable clients fit?&lt;/strong&gt;&lt;br&gt;
On their own calendar row. They can lag consumer Stable for weeks, so a retail audience and a locked-down corporate audience on the same template can read different field bands with no deploy on either side. That lag is expected; it is not an unexplained regression until the calendar says otherwise.&lt;/p&gt;
&lt;h3 id=&quot;put-the-browser-on-the-sheet-this-week&quot;&gt;Put the browser on the sheet this week&lt;/h3&gt;
&lt;p&gt;The release calendar you already use for deploys is enough. Chrome Stable and Beta for the next month go on it now, Firefox too if that traffic matters, and the owner’s name sits at the top of the tab. Next time field LCP moves on a quiet week, you have a dated answer instead of a fictional commit. After the ritual sticks, the Watcher guides linked above carry the deeper reporting playbook; when the same annotations need to span a multi-client portfolio, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=put-chrome-stable-on-the-same-calendar-as-your-deploys&quot;&gt;start a Watcher trial&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/blog/chrome-two-week-release&quot;&gt;Get features faster with Chrome's two-week release cycle&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://csswizardry.com/2026/08/web-perf-wednesday-006-faster-browser-releases-change-your-rum-population/&quot;&gt;Web-Perf Wednesday 006 – Faster Browser Releases Change Your RUM Population&lt;/a&gt; (CSS Wizardry)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-lcp-moves-nobody-deployed-browser-release-cadence-28-day-field-window&quot;&gt;When LCP Moves and Nobody Deployed: Browser Release Cadence and Your 28-Day Field Window&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/crux-pipeline-delays-late-field-data-client-reports&quot;&gt;CrUX pipeline delays and late field data in client reports&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://chromestatus.com/roadmap&quot;&gt;Chrome Status roadmap&lt;/a&gt; (Chrome)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://devlog.apogeewatcher.com/put-chrome-stable-on-the-same-calendar-as-your-deploys&quot;&gt;Hashnode&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28277/put-chrome-stable-on-the-same-calendar-as-your-deploys</guid>
<pubDate>Wed, 23 Sep 2026 06:28:19 +0000</pubDate>
</item>
<item>
<title>Keep Search Clean: Block Search Engine Spam with uBlacklist and Community Rule Sets</title>
<link>https://coderlegion.com/27840/keep-search-clean-block-search-engine-spam-with-ublacklist-and-community-rule-sets</link>
<description>&lt;p&gt;If you use Google, DuckDuckGo, or Bing regularly, you have likely run into programmatic search spam: auto-generated &quot;doorway&quot; pages, scraper blogs stealing content, DGA (Domain Generation Algorithm) random domain networks, and affiliate redirects. They waste time, clutter search results, and occasionally host malicious scripts or phishing landers.&lt;/p&gt;
&lt;p&gt;While reporting these domains to registrars and search engines helps clean up the web for everyone, you can instantly eliminate them from your personal local browsing experience using &lt;strong&gt;uBlacklist&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-problem-does-ublacklist-solve-&quot;&gt;What Problem Does uBlacklist Solve?&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iorate/uBlacklist&quot;&gt;uBlacklist&lt;/a&gt; is a lightweight browser extension that filters specified sites from appearing in your search engine results.&lt;/p&gt;
&lt;p&gt;Instead of landing on low-quality scraper sites or clickbait doorway networks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hides Spam Results:&lt;/strong&gt; Blacklisted domains are automatically stripped or dimmed out directly in your search results.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Search Engine Support:&lt;/strong&gt; Works seamlessly across Google, Bing, DuckDuckGo, Ecosia, Startpage, and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community Rule Subscriptions:&lt;/strong&gt; Instead of manually blocking sites one by one, you can subscribe to crowdsourced community blocklists that sync automatically in the background.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-how-to-install-ublacklist-on-chrome&quot;&gt;Step 1: How to Install uBlacklist on Chrome&lt;/h3&gt;
&lt;p&gt;Installing the extension takes less than a minute:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Google Chrome&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Visit the &lt;a rel=&quot;nofollow&quot; href=&quot;https://chromewebstore.google.com/detail/ublacklist/pncfbmialoiaghdehhbnbhkkgmjanfhe&quot;&gt;uBlacklist page on the Chrome Web Store&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add to Chrome&lt;/strong&gt; and confirm by clicking &lt;strong&gt;Add extension&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;(Optional)&lt;/em&gt; Click the puzzle piece icon (Extensions) in your top-right toolbar and pin &lt;strong&gt;uBlacklist&lt;/strong&gt; for easy access.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-recommended-community-rule-sets&quot;&gt;Step 2: Recommended Community Rule Sets&lt;/h3&gt;
&lt;p&gt;To get maximum protection without needing to build your own list from scratch, subscribe to curated community rule sets listed on the &lt;a rel=&quot;nofollow&quot; href=&quot;https://ublacklist.github.io/rulesets?utm_source=gemini&quot;&gt;uBlacklist Rule Sets Directory&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I specifically recommend enabling these three subscriptions to target common web spam patterns:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Spam:&lt;/strong&gt; &lt;em&gt;Ad and tracking server domain list&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Blocks domain networks known for aggressive popups, tracking traps, and ad-heavy doorway pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spam:&lt;/strong&gt; &lt;em&gt;DGA &amp;amp; Random Subdomain Spam Blocklist&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Targets programmatically generated, short-lived domains (e.g., random character strings like &lt;code&gt;lwhiswfnuuiu.gay&lt;/code&gt; or &lt;code&gt;ohgssoigkcik.icu&lt;/code&gt;) frequently used by automated web spam rings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copycat Sites:&lt;/strong&gt; &lt;em&gt;uBlock-Origin-dev-filter&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Shields developers from scraper sites that duplicate StackOverflow, GitHub, and technical documentation with low-quality, ad-stuffed overlays.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-how-to-add-recommended-rule-sets-to-your-extension&quot;&gt;Step 3: How to Add Recommended Rule Sets to Your Extension&lt;/h3&gt;
&lt;p&gt;Before subscribing directly from the community directory, enable subscriptions in your local extension settings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enable Subscriptions:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Click the &lt;strong&gt;Extensions icon&lt;/strong&gt; (puzzle piece) in your Chrome toolbar.&lt;/li&gt;
&lt;li&gt;Find &lt;strong&gt;uBlacklist&lt;/strong&gt;, click the &lt;strong&gt;three dots (&quot;...&quot;)&lt;/strong&gt;, and select &lt;strong&gt;Options&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Scroll down to the &lt;strong&gt;Subscriptions&lt;/strong&gt; section and make sure the &lt;strong&gt;Enable subscriptions&lt;/strong&gt; toggle is switched &lt;strong&gt;ON&lt;/strong&gt; (Enabled).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscribe from the Community Directory:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Visit the &lt;a rel=&quot;nofollow&quot; href=&quot;https://ublacklist.github.io/rulesets?utm_source=gemini&quot;&gt;uBlacklist Rule Sets Directory&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Locate the recommended rule sets:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Spam:&lt;/strong&gt; &lt;em&gt;Ad and tracking server domain list&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spam:&lt;/strong&gt; &lt;em&gt;DGA &amp;amp; Random Subdomain Spam Blocklist&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copycat Sites:&lt;/strong&gt; &lt;em&gt;uBlock-Origin-dev-filter&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;&quot;+&quot; (Subscribe)&lt;/strong&gt; button next to each rule set.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confirm:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;uBlacklist will prompt you to confirm—click &lt;strong&gt;Subscribe&lt;/strong&gt; (or &lt;strong&gt;Add&lt;/strong&gt;) to finish adding the list.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-how-to-verify-it-s-working&quot;&gt;Step 4: How to Verify It’s Working&lt;/h3&gt;
&lt;p&gt;To ensure your rule sets are active and working as expected:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Check Subscription Status:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Click the &lt;strong&gt;Extensions icon&lt;/strong&gt; (puzzle piece) in your Chrome toolbar.&lt;/li&gt;
&lt;li&gt;Locate &lt;strong&gt;uBlacklist&lt;/strong&gt; in the list, click the &lt;strong&gt;three dots (&quot;...&quot;)&lt;/strong&gt; next to it, and select &lt;strong&gt;Options&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Scroll down to the &lt;strong&gt;Subscriptions&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;You should see a status or timestamp showing &lt;strong&gt;&quot;Updated [time]&quot;&lt;/strong&gt; alongside the total count of loaded rules/patterns for each subscribed list.&lt;/li&gt;
&lt;li&gt;You can click &lt;strong&gt;Update now&lt;/strong&gt; to manually trigger an initial sync.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test in Search Results:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Perform a search query on Google or DuckDuckGo.&lt;/li&gt;
&lt;li&gt;If a domain matching your blocklists appears in the raw index, uBlacklist will intercept it. &lt;/li&gt;
&lt;li&gt;Look at the bottom or top of your search results page—you will see a subtle indicator stating: &lt;strong&gt;&quot;uBlacklist has blocked N site(s)&quot;&lt;/strong&gt;. Click it to view or temporarily unhide blocked results.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By pairing direct reporting with local client-side filtering like uBlacklist, you get an immediate, pristine search experience free from automated spam networks.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27840/keep-search-clean-block-search-engine-spam-with-ublacklist-and-community-rule-sets</guid>
<pubDate>Sun, 20 Sep 2026 14:31:02 +0000</pubDate>
</item>
<item>
<title>From HTML to Legal Automation: Dhardingsea Developer’s Journey of Building Software That Solves Real</title>
<link>https://coderlegion.com/27044/from-html-legal-automation-dhardingsea-developers-journey-building-software-that-solves</link>
<description>&lt;p&gt;&lt;strong&gt;A CoderLegion Developer Story featuring &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/user/DHSeaDev&quot;&gt;Dhardingsea Developer&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interviewed and edited by Mehadi Hasan, Community &amp;amp; Editorial Team at CoderLegion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Some developers follow a straight path.&lt;/p&gt;
&lt;p&gt;Others follow problems.&lt;/p&gt;
&lt;p&gt;For Dhardingsea Developer, programming started with computers, HTML, and web development. From there, the journey moved through computer repair, malware removal, Chrome extensions, Windows tools, games, production automation, and AI tooling.&lt;/p&gt;
&lt;p&gt;Today, that work spans very different kinds of software — from browser games to automation for the legal-process-serving industry.&lt;/p&gt;
&lt;p&gt;At first, those projects might seem unrelated.&lt;/p&gt;
&lt;p&gt;But there is a common thread:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Finding ways to use computers to mend, improve, and simplify things encountered in real life.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That approach has also shaped a particular engineering philosophy: build locally when possible, respect user privacy, minimize unnecessary permissions, listen to users, and encode knowledge into software so it doesn't disappear when people do.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;it-started-with-computers&quot;&gt;It Started With Computers&lt;/h3&gt;
&lt;p&gt;As a child, computers were something Dhardingsea Developer naturally connected with.&lt;/p&gt;
&lt;p&gt;They were understandable.&lt;/p&gt;
&lt;p&gt;They were something that could be explored.&lt;/p&gt;
&lt;p&gt;The first real attraction was HTML and web development.&lt;/p&gt;
&lt;p&gt;That eventually expanded into computer repair and malware removal, giving them exposure to computers from a different perspective.&lt;/p&gt;
&lt;p&gt;Programming wasn't isolated from the rest of technology.&lt;/p&gt;
&lt;p&gt;It was connected to understanding how computers worked, what could go wrong, and how problems could be fixed.&lt;/p&gt;
&lt;p&gt;That practical experience became an important foundation for everything that came later.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;turning-real-life-problems-into-software&quot;&gt;Turning Real-Life Problems Into Software&lt;/h3&gt;
&lt;p&gt;One of the defining characteristics of the journey has been finding ways to use computers to improve things encountered in everyday life.&lt;/p&gt;
&lt;p&gt;With a background spanning marketing and web development, combined with experience working at a small computer company, Dhardingsea Developer gradually developed a broad understanding of technology.&lt;/p&gt;
&lt;p&gt;Instead of focusing on a single category of software, they kept finding different problems that could potentially be solved with computers.&lt;/p&gt;
&lt;p&gt;That led to a wide range of projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chrome extensions&lt;/li&gt;
&lt;li&gt;Windows desktop tools&lt;/li&gt;
&lt;li&gt;Browser games&lt;/li&gt;
&lt;li&gt;Production automation&lt;/li&gt;
&lt;li&gt;AI tooling&lt;/li&gt;
&lt;li&gt;Developer tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The technologies may be different.&lt;/p&gt;
&lt;p&gt;The underlying approach isn't.&lt;/p&gt;
&lt;p&gt;Find something that could work better.&lt;/p&gt;
&lt;p&gt;Understand the problem.&lt;/p&gt;
&lt;p&gt;Build something.&lt;/p&gt;
&lt;p&gt;Then learn from what happens.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;when-software-has-real-world-consequences&quot;&gt;When Software Has Real-World Consequences&lt;/h3&gt;
&lt;p&gt;One of the biggest differences between Dhardingsea Developer's personal projects and professional work is the environment in which the software operates.&lt;/p&gt;
&lt;p&gt;Their work in the legal-process-serving industry comes with consequences that a game or experimental project simply doesn't have.&lt;/p&gt;
&lt;p&gt;A small mistake can have significant financial consequences.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;An error, a small click of a button can send duplication of filing fees and a loss of thousands.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That changes the engineering process.&lt;/p&gt;
&lt;p&gt;In a creative project, you can experiment and recover from mistakes relatively easily.&lt;/p&gt;
&lt;p&gt;In legal-process software, the consequences of a mistake can affect real documents, filings, fees, and workflows.&lt;/p&gt;
&lt;p&gt;As a result, simulation and review become extremely important.&lt;/p&gt;
&lt;p&gt;Before launching something, it is necessary to think through what could happen.&lt;/p&gt;
&lt;p&gt;And even after launch, there is another challenge:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;maintenance.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Software doesn't simply need to work once.&lt;/p&gt;
&lt;p&gt;It needs to continue working as the surrounding environment changes.&lt;/p&gt;
&lt;p&gt;For Dhardingsea Developer, this is very different from building a game or creative project.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The purpose is function; the other is function of purpose.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The distinction is important.&lt;/p&gt;
&lt;p&gt;One environment demands correctness and reliability.&lt;/p&gt;
&lt;p&gt;The other gives more room for experimentation and creative expression.&lt;/p&gt;
&lt;p&gt;Both teach valuable lessons.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;encoding-institutional-knowledge-into-software&quot;&gt;Encoding Institutional Knowledge Into Software&lt;/h3&gt;
&lt;p&gt;One of the most interesting ideas in Dhardingsea Developer's profile is the concept of &lt;strong&gt;encoding institutional knowledge into software&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What does that actually mean?&lt;/p&gt;
&lt;p&gt;It starts with understanding how people solve problems.&lt;/p&gt;
&lt;p&gt;Someone who has spent years working in a particular environment develops knowledge that may never be written down.&lt;/p&gt;
&lt;p&gt;They know how to untangle a problem.&lt;/p&gt;
&lt;p&gt;They know what tends to go wrong.&lt;/p&gt;
&lt;p&gt;They know what to check before something breaks.&lt;/p&gt;
&lt;p&gt;They know why a particular decision was made.&lt;/p&gt;
&lt;p&gt;That knowledge can disappear when the person leaves.&lt;/p&gt;
&lt;p&gt;Software can preserve some of it.&lt;/p&gt;
&lt;p&gt;For Dhardingsea Developer, comments, telemetry, documentation, and implementation details can capture not only what the software does, but why it does it.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;I find it valuable to put the why for someone to have the opportunity to learn even if it's to change.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That last part is important.&lt;/p&gt;
&lt;p&gt;Documentation isn't necessarily about making decisions permanent.&lt;/p&gt;
&lt;p&gt;It is about making the reasoning visible so that someone else can understand it, question it, and improve it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-chromium-autofiler-that-started-something-bigger&quot;&gt;The Chromium Autofiler That Started Something Bigger&lt;/h3&gt;
&lt;p&gt;One of the projects that taught Dhardingsea Developer the most was &lt;strong&gt;Chromium Autofiler&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It was one of their early projects, but its impact went beyond the project itself.&lt;/p&gt;
&lt;p&gt;Working on it introduced them to areas such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database storage&lt;/li&gt;
&lt;li&gt;Encryption&lt;/li&gt;
&lt;li&gt;Browser tooling&lt;/li&gt;
&lt;li&gt;Software architecture&lt;/li&gt;
&lt;li&gt;Building their own website&lt;/li&gt;
&lt;li&gt;Creating games&lt;/li&gt;
&lt;li&gt;Working with different tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The project became a starting point.&lt;/p&gt;
&lt;p&gt;Not necessarily because it was the most successful thing they built, but because it opened the door to everything that came afterward.&lt;/p&gt;
&lt;p&gt;Sometimes an early project matters because of what it teaches you rather than what it becomes.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;learning-the-hard-way-with-a-chrome-extension&quot;&gt;Learning the Hard Way With a Chrome Extension&lt;/h3&gt;
&lt;p&gt;One of the more recent projects was a local-first Dota 2 companion built as a Chrome extension.&lt;/p&gt;
&lt;p&gt;Dota 2 provides an API for gathering information, while also having a large social gaming community.&lt;/p&gt;
&lt;p&gt;The project forced Dhardingsea Developer to think carefully about something that is easy to overlook:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The user doesn't necessarily understand the technical limitations behind the software.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A user may not know about API rate limits.&lt;/p&gt;
&lt;p&gt;They may simply expect the software to work.&lt;/p&gt;
&lt;p&gt;That creates an interesting responsibility for developers.&lt;/p&gt;
&lt;p&gt;Should software automatically impose restrictions on behalf of users?&lt;/p&gt;
&lt;p&gt;Should it assume that users don't understand the consequences?&lt;/p&gt;
&lt;p&gt;Or should it allow the system to behave according to the capabilities available?&lt;/p&gt;
&lt;p&gt;Dhardingsea Developer describes this tension candidly.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Imposing a limit on a user's behalf for safety is a weird call, who am I to be so arrogant?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The experience ultimately reinforced another lesson:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consider the user's needs before they become problems.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Building a tool isn't only about making the technology work.&lt;/p&gt;
&lt;p&gt;It is about understanding how people will actually use it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;shipping-something-before-it-s-perfect&quot;&gt;Shipping Something Before It's Perfect&lt;/h3&gt;
&lt;p&gt;Another lesson that has become important to Dhardingsea Developer is knowing when to ship.&lt;/p&gt;
&lt;p&gt;Developers can spend months working toward an idea.&lt;/p&gt;
&lt;p&gt;During that time, motivation can disappear.&lt;/p&gt;
&lt;p&gt;Budgets can change.&lt;/p&gt;
&lt;p&gt;Opinions can change.&lt;/p&gt;
&lt;p&gt;The original idea itself can change.&lt;/p&gt;
&lt;p&gt;And sometimes the only people who can tell you whether the software is useful are the people actually using it.&lt;/p&gt;
&lt;p&gt;That changed the way Dhardingsea Developer thinks about incomplete software.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;The user will say, the user will know.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead of waiting for every feature to be perfect, shipping something allows users to provide feedback.&lt;/p&gt;
&lt;p&gt;That feedback can become part of the development process.&lt;/p&gt;
&lt;p&gt;An incomplete product can sometimes teach you more than a perfect product that nobody has seen.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;It's easier to ship something incomplete, you can find so much more feedback from users looking to help play a role.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Dhardingsea Developer, shipping isn't necessarily the end of development.&lt;/p&gt;
&lt;p&gt;It's the beginning of another feedback loop.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;privacy-is-a-requirement-not-a-feature&quot;&gt;Privacy Is a Requirement, Not a Feature&lt;/h3&gt;
&lt;p&gt;A strong theme across the projects is privacy.&lt;/p&gt;
&lt;p&gt;Dhardingsea Developer's approach emphasizes local-first software, minimal permissions, and avoiding unnecessary accounts or telemetry.&lt;/p&gt;
&lt;p&gt;The reasoning is simple.&lt;/p&gt;
&lt;p&gt;Users are becoming increasingly tired of giving away their data.&lt;/p&gt;
&lt;p&gt;They don't necessarily want their history, behavior, or personal information collected simply because they use a piece of software.&lt;/p&gt;
&lt;p&gt;And with AI becoming more deeply integrated into technology, that concern becomes even more important.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;It's important to me to hold user security as a priority.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The goal isn't to build a system around advertising or tracking clicks.&lt;/p&gt;
&lt;p&gt;It's to build software for people.&lt;/p&gt;
&lt;p&gt;That means treating the user as something more important than a source of telemetry.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-shortcut-they-refuse-to-take&quot;&gt;The Shortcut They Refuse to Take&lt;/h3&gt;
&lt;p&gt;Every developer has shortcuts they are willing to take.&lt;/p&gt;
&lt;p&gt;And every developer has some shortcuts they refuse to take.&lt;/p&gt;
&lt;p&gt;For Dhardingsea Developer, one of those is &lt;strong&gt;cross-analysis and continuous learning&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Their current workflow involves sending files between different character accounts to review information from different perspectives.&lt;/p&gt;
&lt;p&gt;The data can then go through a kind of &quot;levelup&quot; process designed to identify gaps in skills or processes and make improvements.&lt;/p&gt;
&lt;p&gt;It consumes time.&lt;/p&gt;
&lt;p&gt;It consumes processing power.&lt;/p&gt;
&lt;p&gt;It would be much easier to simply accept the current state.&lt;/p&gt;
&lt;p&gt;But Dhardingsea Developer considers the process non-negotiable.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;We must learn.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That philosophy fits closely with their broader approach to software.&lt;/p&gt;
&lt;p&gt;The system isn't supposed to simply produce an answer.&lt;/p&gt;
&lt;p&gt;It should help identify weaknesses and improve over time.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-lesson-they-wish-they-learned-earlier&quot;&gt;The Lesson They Wish They Learned Earlier&lt;/h3&gt;
&lt;p&gt;Sometimes the biggest lessons aren't architectural.&lt;/p&gt;
&lt;p&gt;Sometimes they're surprisingly small.&lt;/p&gt;
&lt;p&gt;For Dhardingsea Developer, one of those lessons is:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spelling really matters.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A random &lt;code&gt; &lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An unexpected capital letter.&lt;/p&gt;
&lt;p&gt;A small typo.&lt;/p&gt;
&lt;p&gt;Something that looks insignificant can become the reason you spend time debugging something that should have worked.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Debugging is an endless task at times.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Looking back, they wish they had paid more attention to spelling much earlier.&lt;/p&gt;
&lt;p&gt;It's a humorous lesson, but also a very real one.&lt;/p&gt;
&lt;p&gt;Computers don't care what you meant.&lt;/p&gt;
&lt;p&gt;They care what you actually wrote.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;learning-databases-for-the-next-stage&quot;&gt;Learning Databases for the Next Stage&lt;/h3&gt;
&lt;p&gt;Looking ahead, one of the areas Dhardingsea Developer wants to explore more deeply is databases and structured data.&lt;/p&gt;
&lt;p&gt;They describe having relatively little experience in this area and increasingly feeling that it is limiting what they can build.&lt;/p&gt;
&lt;p&gt;In particular, it becomes important when thinking about MMO-style games.&lt;/p&gt;
&lt;p&gt;Games with persistent worlds require more than interfaces and mechanics.&lt;/p&gt;
&lt;p&gt;They require systems capable of storing, retrieving, updating, and organizing large amounts of structured information.&lt;/p&gt;
&lt;p&gt;For Dhardingsea Developer, learning more about databases is therefore not simply about learning another technology.&lt;/p&gt;
&lt;p&gt;It's about removing a limitation on what they can build next.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-advice-have-fun&quot;&gt;The Advice: Have Fun&lt;/h3&gt;
&lt;p&gt;For developers who feel stuck or believe they aren't progressing quickly enough, Dhardingsea Developer doesn't recommend obsessing over speed.&lt;/p&gt;
&lt;p&gt;The advice is much simpler:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Have fun.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Joy is an important part of learning.&lt;/p&gt;
&lt;p&gt;If you're struggling, that doesn't necessarily mean you're failing.&lt;/p&gt;
&lt;p&gt;It can mean you're already doing something valuable.&lt;/p&gt;
&lt;p&gt;You're learning something difficult.&lt;/p&gt;
&lt;p&gt;You're pushing against the limits of what you currently understand.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;If you are struggling, that means you are already succeeding.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The important thing is to keep the curiosity alive.&lt;/p&gt;
&lt;p&gt;Learn something new.&lt;/p&gt;
&lt;p&gt;Try a different approach.&lt;/p&gt;
&lt;p&gt;Even if the new approach is simply a different way of doing something as basic as &lt;code&gt;2 + 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The point isn't always immediate productivity.&lt;/p&gt;
&lt;p&gt;Sometimes the point is discovering another way to think.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;you-can-succeed-at-anything-if-you-luck-out-hard-enough&quot;&gt;You Can Succeed at Anything — If You Luck Out Hard Enough&lt;/h3&gt;
&lt;p&gt;There is one line on Dhardingsea Developer's profile that stands out:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;You can succeed at anything, if you just luck out hard enough.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The phrase comes from &lt;em&gt;Futurama&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But for Dhardingsea Developer, it also carries a deeper meaning.&lt;/p&gt;
&lt;p&gt;Success isn't entirely controlled by effort.&lt;/p&gt;
&lt;p&gt;There is timing.&lt;/p&gt;
&lt;p&gt;There is circumstance.&lt;/p&gt;
&lt;p&gt;There is being in the right place at the right moment.&lt;/p&gt;
&lt;p&gt;There are things outside our control.&lt;/p&gt;
&lt;p&gt;But that doesn't mean effort is meaningless.&lt;/p&gt;
&lt;p&gt;Instead, the idea is to keep putting yourself in situations where luck has a chance to find you.&lt;/p&gt;
&lt;p&gt;As they put it:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;I'm just a guy, but maybe with some effort we can luck out hard enough haha.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's a surprisingly fitting conclusion to this journey.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;building-through-curiosity&quot;&gt;Building Through Curiosity&lt;/h3&gt;
&lt;p&gt;Looking at Dhardingsea Developer's journey, the projects may initially seem scattered.&lt;/p&gt;
&lt;p&gt;Chrome extensions.&lt;/p&gt;
&lt;p&gt;Games.&lt;/p&gt;
&lt;p&gt;Windows tools.&lt;/p&gt;
&lt;p&gt;Legal automation.&lt;/p&gt;
&lt;p&gt;AI tooling.&lt;/p&gt;
&lt;p&gt;Databases.&lt;/p&gt;
&lt;p&gt;Browser APIs.&lt;/p&gt;
&lt;p&gt;But there is a common thread.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Curiosity.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A problem appears.&lt;/p&gt;
&lt;p&gt;Something doesn't work.&lt;/p&gt;
&lt;p&gt;There is an opportunity to make it better.&lt;/p&gt;
&lt;p&gt;So they build.&lt;/p&gt;
&lt;p&gt;The result isn't always perfect.&lt;/p&gt;
&lt;p&gt;Sometimes it ships incomplete.&lt;/p&gt;
&lt;p&gt;Sometimes the platform has unexpected restrictions.&lt;/p&gt;
&lt;p&gt;Sometimes the software creates new problems.&lt;/p&gt;
&lt;p&gt;Sometimes a tiny spelling mistake creates hours of debugging.&lt;/p&gt;
&lt;p&gt;But every project becomes another source of knowledge.&lt;/p&gt;
&lt;p&gt;And that knowledge gets carried into the next thing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-comes-next&quot;&gt;What Comes Next&lt;/h3&gt;
&lt;p&gt;The next chapter is likely to involve more databases, structured data, automation, AI, and increasingly ambitious software projects.&lt;/p&gt;
&lt;p&gt;But the underlying philosophy seems unlikely to change.&lt;/p&gt;
&lt;p&gt;Build things that solve real problems.&lt;/p&gt;
&lt;p&gt;Listen to users.&lt;/p&gt;
&lt;p&gt;Protect their privacy.&lt;/p&gt;
&lt;p&gt;Document the reasoning.&lt;/p&gt;
&lt;p&gt;Don't be afraid to ship something incomplete.&lt;/p&gt;
&lt;p&gt;Keep learning.&lt;/p&gt;
&lt;p&gt;And, most importantly, keep enjoying the process.&lt;/p&gt;
&lt;p&gt;Because sometimes the best thing a developer can do is simply keep building long enough to &lt;strong&gt;luck out hard enough&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;about-dhardingsea-developer&quot;&gt;About Dhardingsea Developer&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/user/DHSeaDev&quot;&gt;Dhardingsea Developer&lt;/a&gt; is an independent developer and builder based in Iowa.&lt;/p&gt;
&lt;p&gt;Their work spans Manifest V3 Chrome extensions, Windows desktop tools, idle games, production automation, and AI tooling for the legal-process-serving industry.&lt;/p&gt;
&lt;p&gt;Their broader development philosophy centers around encoding institutional knowledge into software — turning schemas, workflows, compliance rules, and practical experience into tools that can consistently reproduce that knowledge.&lt;/p&gt;
&lt;p&gt;They are particularly interested in local-first software, privacy, minimal permissions, automation, browser extensions, games, AI tooling, and structured data.&lt;/p&gt;
&lt;p&gt;You can follow their work on &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/user/DHSeaDev&quot;&gt;CoderLegion&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;http://dhseadev.online/&quot;&gt;DHSeaDev.online&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;about-this-developer-story&quot;&gt;About This Developer Story&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Developer:&lt;/strong&gt; Dhardingsea Developer&lt;br&gt;
&lt;strong&gt;Username:&lt;/strong&gt; @DHSeaDev&lt;br&gt;
&lt;strong&gt;Series:&lt;/strong&gt; CoderLegion Developer Stories&lt;br&gt;
&lt;strong&gt;Interview format:&lt;/strong&gt; Q&amp;amp;A&lt;br&gt;
&lt;strong&gt;Interviewed and edited by:&lt;/strong&gt; Mehadi Hasan, Community &amp;amp; Editorial Team at CoderLegion&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This story was created from Dhardingsea Developer's own answers and experiences shared during the CoderLegion Developer Stories Q&amp;amp;A. The article preserves the developer's personal perspective and intentionally keeps the informal character of their responses.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27044/from-html-legal-automation-dhardingsea-developers-journey-building-software-that-solves</guid>
<pubDate>Sun, 13 Sep 2026 08:19:22 +0000</pubDate>
</item>
<item>
<title>Modern Chrome Extension Development: Manifest V3 Architecture &amp; Best Practices</title>
<link>https://coderlegion.com/26963/modern-chrome-extension-development-manifest-v3-architecture-best-practices</link>
<description>&lt;p&gt;Hey devs! I put together a practical guide covering the fundamentals of building Chrome extensions with Manifest V3.&lt;/p&gt;
&lt;p&gt;Core highlights:&lt;/p&gt;
&lt;p&gt;Transitioning from persistent background pages to event-driven service workers&lt;/p&gt;
&lt;p&gt;Two-way communication across popups, background workers, and injected content scripts&lt;/p&gt;
&lt;p&gt;Safe storage persistence and permission management for smooth store approval&lt;/p&gt;
&lt;p&gt;Check out the complete write-up on SunnyWriteUps! Have you migrated your existing extensions to MV3 yet, or are you starting any new extension side projects?&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://sunnyblog.apexmansunny.workers.dev/posts/how-to-create-a-chrome-extension-with-best-practices/&quot;&gt;https://sunnyblog.apexmansunny.workers.dev/posts/how-to-create-a-chrome-extension-with-best-practices/&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26963/modern-chrome-extension-development-manifest-v3-architecture-best-practices</guid>
<pubDate>Sat, 12 Sep 2026 11:27:07 +0000</pubDate>
</item>
<item>
<title>I built a local-first Dota 2 companion as a Chrome extension — and learned what &quot;minimum permissions&quot; actually means</title>
<link>https://coderlegion.com/26265/built-local-first-companion-chrome-extension-learned-minimum-permissions-actually-means</link>
<description>&lt;p&gt;Building a no-account, no-API-key Dota 2 stats extension, and three Chrome/Steam lessons that cost me a Web Store rejection.&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://dhseadev.online/projects/dota-companion/&quot;&gt;https://dhseadev.online/projects/dota-companion/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most Dota 2 stat sites answer &quot;how did that game go?&quot; I wanted one that answers a harder question: &lt;strong&gt;am I actually getting better?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So I built &lt;a rel=&quot;nofollow&quot; href=&quot;https://chromewebstore.google.com/detail/dota-companion/gnnamhmenhhlgjmanoofngmfeddmfbej&quot;&gt;Dota Companion&lt;/a&gt; — a Chrome extension that lives in your toolbar. No account, no API key, no signup. Paste a Steam profile URL and it works.&lt;/p&gt;
&lt;p&gt;The build taught me three things worth passing on, one of which got the extension flagged by the Chrome Web Store.&lt;/p&gt;
&lt;h3 id=&quot;the-feature-i-actually-cared-about-improvement-streak&quot;&gt;The feature I actually cared about: improvement streak&lt;/h3&gt;
&lt;p&gt;Win streaks measure luck as much as skill. In a five-player team game, you can play well and lose.&lt;/p&gt;
&lt;p&gt;So the headline metric isn't wins — it's an &lt;strong&gt;improvement streak&lt;/strong&gt;: consecutive games where your GPM beat &lt;em&gt;your own&lt;/em&gt; 20-game baseline. It's a metric you control, and it moves when you improve rather than when your team cooperates.&lt;/p&gt;
&lt;p&gt;Same idea drives goals. Pick GPM, KDA, last hits, or win rate; the baseline snapshots your current 20-game average when you set the goal. You compete with past-you.&lt;/p&gt;
&lt;p&gt;The rest is the between-games layer: today's W/L, a GPM trend sparkline, recent matches with hero, K/D/A, duration and how long ago, most-played heroes, and private notes and tags on players you run into — stored on your device, never uploaded.&lt;/p&gt;
&lt;h3 id=&quot;lesson-1-chrome-tabs-create-does-not-need-the-tabs-permission&quot;&gt;Lesson 1: &lt;code&gt;chrome.tabs.create()&lt;/code&gt; does not need the &lt;code&gt;tabs&lt;/code&gt; permission&lt;/h3&gt;
&lt;p&gt;This one cost me a rejection email.&lt;/p&gt;
&lt;p&gt;I had one tabs call — opening a bundled inventory page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;chrome.tabs.create({ url: chrome.runtime.getURL('inventory.html') });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So &lt;code&gt;&quot;tabs&quot;&lt;/code&gt; went in the manifest. Reasonable, right?&lt;/p&gt;
&lt;p&gt;Wrong. Google flagged it under their minimum-permissions policy:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The following permission(s) need not be requested for the methods/properties implemented by the item: &lt;code&gt;tabs&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;chrome.tabs.create()&lt;/code&gt; has never required the &lt;code&gt;tabs&lt;/code&gt; permission.&lt;/strong&gt; No tab-creation API does. That permission gates exactly one thing: reading &lt;em&gt;sensitive tab metadata&lt;/em&gt; — &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;pendingUrl&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;favIconUrl&lt;/code&gt; — off &lt;code&gt;Tab&lt;/code&gt; objects.&lt;/p&gt;
&lt;p&gt;I passed a URL in and ignored the returned object. I was declaring a capability I never used.&lt;/p&gt;
&lt;p&gt;I verified the fix rather than trusting the docs — loaded the extension with &lt;code&gt;tabs&lt;/code&gt; removed and called the API in a real browser:&lt;/p&gt;
&lt;p&gt;runtime granted permissions: {&quot;permissions&quot;:[&quot;storage&quot;],&quot;origins&quot;:[&quot;https://api.opendota.com/*&quot;]}&lt;br&gt;
chrome.tabs.create -&amp;gt; {&quot;ok&quot;:true,&quot;tabId&quot;:210614909}&lt;br&gt;
pages before/after: 2 / 3&lt;br&gt;
errors: NONE&lt;/p&gt;
&lt;p&gt;Tab opened. Zero errors. The permission was pure liability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; grep your actual call sites before declaring anything. &quot;This API sounds tab-related, so I need &lt;code&gt;tabs&lt;/code&gt;&quot; is exactly the reasoning the policy exists to catch. Ask instead: &lt;em&gt;do I read the returned object's sensitive fields?&lt;/em&gt; If no, you don't need it.&lt;/p&gt;
&lt;h3 id=&quot;lesson-2-rate-limits-you-share-with-the-user-are-a-design-constraint-not-an-error-case&quot;&gt;Lesson 2: rate limits you share with the user are a design constraint, not an error case&lt;/h3&gt;
&lt;p&gt;The extension can estimate your Dota 2 inventory value from Steam Community Market prices. Steam rate-limits those endpoints hard — and critically, &lt;strong&gt;the limit applies to the whole IP, not to your extension.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Blow through it and you don't just break your feature. You break the user's normal Steam browsing. That reframes the problem: you're not optimizing your own throughput, you're spending a budget that isn't yours.&lt;/p&gt;
&lt;p&gt;So the design is deliberately timid:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nothing fetches automatically.&lt;/strong&gt; Every request traces back to a button the user pressed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A visible request budget&lt;/strong&gt;, capped well short of the real limit, shown in the UI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard backoff.&lt;/strong&gt; If Steam pushes back, it stops for hours rather than retrying.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Steam login cookies&lt;/strong&gt; are sent. Public data only.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Slower than technically possible, on purpose. A tool that degrades the rest of your browsing isn't a good tool.&lt;/p&gt;
&lt;h3 id=&quot;lesson-3-optional-permissions-are-worth-the-extra-state&quot;&gt;Lesson 3: optional permissions are worth the extra state&lt;/h3&gt;
&lt;p&gt;The inventory feature needs &lt;code&gt;steamcommunity.com&lt;/code&gt; access. Most users never open it.&lt;/p&gt;
&lt;p&gt;Requesting that host at install time means every user sees a scary permission prompt for a feature they may never touch. So it's an &lt;strong&gt;optional host permission&lt;/strong&gt;, requested at the moment of use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;chrome.permissions.contains({ origins: [ORIGIN] }, cb);  // gate the UI
chrome.permissions.request({ origins: [ORIGIN] }, cb);   // only on click
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cost: a real permission-state machine — gated UI, a grant screen, a declined path. Benefit: the install prompt asks for nothing surprising, and the request arrives with obvious context.&lt;/p&gt;
&lt;p&gt;Worth it. Install-time friction is where extensions die.&lt;/p&gt;
&lt;h3 id=&quot;testing-logic-that-lives-in-a-popup&quot;&gt;Testing logic that lives in a popup&lt;/h3&gt;
&lt;p&gt;Extension code resists testing — everything wants &lt;code&gt;chrome.*&lt;/code&gt; or the DOM. The fix was a hard boundary: all pure logic (streaks, baselines, formatting, aggregation) sits in modules that touch &lt;strong&gt;nothing&lt;/strong&gt; — no &lt;code&gt;chrome.*&lt;/code&gt;, no DOM, no &lt;code&gt;fetch&lt;/code&gt;, not even the clock. Current time is passed in as an argument.&lt;/p&gt;
&lt;p&gt;Those modules dual-export: a global for the extension, &lt;code&gt;module.exports&lt;/code&gt; for Node. The whole stat layer runs headless with zero browser mocks.&lt;/p&gt;
&lt;p&gt;That caught a genuinely nasty one. OpenDota returns &lt;code&gt;start_time&lt;/code&gt; in &lt;strong&gt;epoch seconds&lt;/strong&gt;. &lt;code&gt;new Date(start_time)&lt;/code&gt; expects &lt;strong&gt;milliseconds&lt;/strong&gt; — so every match silently renders as 1970. There's now a regression test asserting exactly that.&lt;/p&gt;
&lt;h3 id=&quot;try-it&quot;&gt;Try it&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome Web Store:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://chromewebstore.google.com/detail/dota-companion/gnnamhmenhhlgjmanoofngmfeddmfbej&quot;&gt;Dota Companion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project page:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://dhseadev.online/projects/dota-companion/&quot;&gt;dhseadev.online/projects/dota-companion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Data comes from the &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.opendota.com/&quot;&gt;OpenDota API&lt;/a&gt; — you'll need &quot;Expose Public Match Data&quot; enabled in Dota 2 settings for matches to show up. English and Simplified Chinese.&lt;/p&gt;
&lt;p&gt;Not affiliated with Valve.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26265/built-local-first-companion-chrome-extension-learned-minimum-permissions-actually-means</guid>
<pubDate>Sat, 05 Sep 2026 15:38:02 +0000</pubDate>
</item>
<item>
<title>When LCP Moves and Nobody Deployed: Browser Release Cadence and Your 28-Day Field Window</title>
<link>https://coderlegion.com/25864/when-lcp-moves-and-nobody-deployed-browser-release-cadence-and-your-28-day-field-window</link>
<description>&lt;p&gt;Field Largest Contentful Paint in PageSpeed Insights can move while your release calendar stays empty. Chrome User Experience Report (CrUX) data is always a 28-day rolling average of real Chrome sessions. From &lt;strong&gt;Chrome 153&lt;/strong&gt; Stable on &lt;strong&gt;8 September 2026&lt;/strong&gt;, Chrome also moves to a &lt;strong&gt;two-week&lt;/strong&gt; release cycle, so that same window can include more than one browser major with different paint and interaction behaviour. An amber field band after a quiet week is often &lt;strong&gt;population mix&lt;/strong&gt; (who updated Chrome, which channel they use, how fast auto-update spreads), not proof that engineering shipped a regression on Tuesday.&lt;/p&gt;&lt;p&gt;We already separated pipeline lag from rolling-window lag in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/crux-pipeline-delays-late-field-data-client-reports&quot;&gt;CrUX pipeline delays and late field data&lt;/a&gt; and explained why a verified fix can sit inside a green lab run and an amber field band in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/why-core-web-vitals-fix-not-in-crux-yet-28-day-window&quot;&gt;why your Core Web Vitals fix is not in CrUX yet&lt;/a&gt;. The gap here is the third clock agencies rarely label: &lt;strong&gt;browser release cadence inside the field window&lt;/strong&gt;. When nobody deployed but field LCP drifts, you need release annotations on the same calendar as app, CDN, tag manager, and RUM changes, sample thresholds before you slice by exact Chrome major, and scheduled lab runs as same-week proof that the origin did not change.&lt;/p&gt;&lt;h2 id=&quot;why-field-lcp-can-move-when-nobody-deployed&quot; class=&quot;scroll-mt-24&quot;&gt;Why field LCP can move when nobody deployed&lt;/h2&gt;&lt;p&gt;CrUX and PageSpeed Insights field sections describe what &lt;strong&gt;real Chrome users&lt;/strong&gt; experienced over roughly the past 28 days, not what your staging build measured yesterday. If the mix of Chrome versions, devices, networks, and journeys inside that window changes, the published p75 can move even when your HTML, CSS, and JavaScript bundles are byte-identical to last month.&lt;/p&gt;&lt;p&gt;Three non-deploy causes show up often in agency tickets:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser updates.&lt;/strong&gt; A new Stable or Extended Stable channel release changes paint timing, image decoding, lazy-loading heuristics, or interaction scheduling for the same page. Users who auto-update mid-window contribute post-update sessions beside pre-update sessions in one aggregate.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Channel skew.&lt;/strong&gt; Beta, Dev, and Canary users are a thin slice for most retail sites, but enterprise Extended Stable cohorts can lag Stable by weeks. A retail origin and a locked-down corporate audience can read different field bands on the same URL template.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Traffic mix.&lt;/strong&gt; Campaign traffic, geography shifts, or seasonality change which templates dominate Chrome sessions. Origin-level field LCP can move when the homepage share of traffic falls while a slower category listing gains share, with no code change on either template.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Lab runs on a fixed URL answer whether &lt;strong&gt;your deploy&lt;/strong&gt; changed the critical path. Field CrUX answers what &lt;strong&gt;Chrome users actually experienced&lt;/strong&gt; across versions and journeys. Treating a field move as a deploy regression without checking browser and traffic mix sends engineering on a hunt for a commit that does not exist.&lt;/p&gt;&lt;h2 id=&quot;chrome-release-cycle-and-core-web-vitals-two-week-stable-from-chrome-153&quot; class=&quot;scroll-mt-24&quot;&gt;Chrome release cycle and Core Web Vitals: two-week Stable from Chrome 153&lt;/h2&gt;&lt;p&gt;Google announced in March 2026 that Chrome will move from a four-week Stable cadence to a &lt;strong&gt;two-week&lt;/strong&gt; cycle, starting with &lt;strong&gt;Chrome 153&lt;/strong&gt; Stable on &lt;strong&gt;8 September 2026&lt;/strong&gt; (&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/blog/chrome-two-week-release&quot;&gt;Chrome two-week release blog&lt;/a&gt;). Beta and Stable promotions arrive every two weeks on Desktop, Android, and iOS. &lt;strong&gt;Extended Stable&lt;/strong&gt; keeps an eight-week cycle for enterprises that need longer validation windows (&lt;a rel=&quot;nofollow&quot; href=&quot;https://support.google.com/chrome/a/answer/16942104?hl=en&quot;&gt;Chrome Enterprise Extended Stable&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;The schedule compresses milestones quickly. Under the new table in Google's post, &lt;strong&gt;Chrome 153&lt;/strong&gt; Stable cuts on &lt;strong&gt;25 August 2026&lt;/strong&gt; with public Stable on &lt;strong&gt;8 September&lt;/strong&gt;, while &lt;strong&gt;Chrome 154&lt;/strong&gt; Stable follows on &lt;strong&gt;22 September&lt;/strong&gt;. Firefox is running a similar experiment around &lt;strong&gt;Firefox 155&lt;/strong&gt; from &lt;strong&gt;1 September 2026&lt;/strong&gt; (see community coverage linked from &lt;a rel=&quot;nofollow&quot; href=&quot;https://csswizardry.com/2026/08/web-perf-wednesday-006-faster-browser-releases-change-your-rum-population/&quot;&gt;CSS Wizardry Web-Perf Wednesday 006&lt;/a&gt;). Performance teams that only annotated application releases in 2025 will need browser rows on the same calendar in 2026.&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Release&lt;/th&gt;&lt;th&gt;Old four-week Stable (illustrative)&lt;/th&gt;&lt;th&gt;New two-week Stable (from Google table)&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chrome 153&lt;/td&gt;&lt;td&gt;Tue 22 Sep 2026&lt;/td&gt;&lt;td&gt;**Tue 8 Sep 2026**&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chrome 154&lt;/td&gt;&lt;td&gt;Tue 20 Oct 2026&lt;/td&gt;&lt;td&gt;**Tue 22 Sep 2026**&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Smaller, more frequent browser releases are good for security and platform velocity. For field reporting they mean &lt;strong&gt;more opportunities for a 28-day CrUX window to span two majors&lt;/strong&gt; with different Web Vitals behaviour, without any change on your origin.&lt;/p&gt;&lt;h2 id=&quot;how-a-28-day-crux-window-can-span-multiple-browser-majors&quot; class=&quot;scroll-mt-24&quot;&gt;How a 28-day CrUX window can span multiple browser majors&lt;/h2&gt;&lt;p&gt;CrUX aggregates opted-in Chrome sessions into a rolling 28-day window. At any query, PageSpeed Insights and the CrUX API return a &lt;code&gt;collectionPeriod&lt;/code&gt; with &lt;code&gt;firstDate&lt;/code&gt; and &lt;code&gt;endDate&lt;/code&gt; covering that blend (&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/crux/api&quot;&gt;CrUX API documentation&lt;/a&gt;). The window advances daily: oldest day drops, newest day enters. There is no switch that flips the entire population to &quot;only Chrome 153 sessions&quot; on Stable release day.&lt;/p&gt;&lt;p&gt;Under a four-week browser cadence, one 28-day field window often covered &lt;strong&gt;one&lt;/strong&gt; new Stable major plus tail versions. Under a two-week cadence, the same window can include &lt;strong&gt;two&lt;/strong&gt; adjacent majors (for example 152 and 153) while auto-update propagates. Each major can shift LCP, INP, or CLS for the same URL because the browser pipeline changed, not because your LCP element or server timing changed.&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Clock&lt;/th&gt;&lt;th&gt;What moves&lt;/th&gt;&lt;th&gt;Typical agency mistake&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;28-day CrUX window&lt;/td&gt;&lt;td&gt;Rolling average of Chrome sessions&lt;/td&gt;&lt;td&gt;Treating field p75 as &quot;yesterday's score&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chrome Stable cadence&lt;/td&gt;&lt;td&gt;Browser majors entering the window&lt;/td&gt;&lt;td&gt;Ignoring browser rows on the release calendar&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;App / CDN deploy&lt;/td&gt;&lt;td&gt;Origin HTML, assets, cache rules&lt;/td&gt;&lt;td&gt;Blaming deploys for browser-driven field drift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Lab schedule&lt;/td&gt;&lt;td&gt;Controlled PageSpeed Insights / Lighthouse runs&lt;/td&gt;&lt;td&gt;Expecting lab to explain field without dates&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;For metric definitions and why field percentiles behave differently from lab medians, start with our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;practical Core Web Vitals guide&lt;/a&gt;. For why lab and field are different instruments on the same URL, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance&quot;&gt;synthetic versus real user monitoring&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;browser-version-in-rum-population-mix-vs-a-site-regression&quot; class=&quot;scroll-mt-24&quot;&gt;Browser version in RUM: population mix vs a site regression&lt;/h2&gt;&lt;p&gt;First-party Real User Monitoring (RUM) and CrUX answer different questions. CrUX is a public, privacy-thresholded view of Chrome traffic Google already collected. RUM is yours: you choose segments, retention, and alert rules. When practitioners search &lt;strong&gt;browser version RUM&lt;/strong&gt;, they usually need to know whether a field shift is &lt;strong&gt;segment noise&lt;/strong&gt; before they open a regression ticket.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Population mix&lt;/strong&gt; means the aggregate changed because the audience composition changed: more sessions on Chrome 153, fewer on 152, a higher share of mobile on a slower network, or a campaign that sent traffic to a heavier template. &lt;strong&gt;Site regression&lt;/strong&gt; means the same browser version and similar journey on the same URL got worse after your change (or after a third-party or CDN change you control).&lt;/p&gt;&lt;p&gt;Before you slice field data by exact Chrome major, set &lt;strong&gt;sample thresholds&lt;/strong&gt;. Thin segments produce volatile p75 lines that look like regressions every week. Rules we use in client work:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Do not report URL-level p75 for a single Chrome major until you have enough sessions to trust the segment (exact cut-offs depend on traffic; treat very small counts as directional only).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Prefer &lt;strong&gt;unsegmented&lt;/strong&gt; LCP, INP, and CLS as the headline series in retainer reports; use browser-major slices in appendix slides for engineers.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Compare like with like: same form factor, same URL or origin scope, same collection period dates.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Pair every segmented chart with an unsegmented line so leadership sees whether the whole population moved or only one slice.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Harry Roberts framed the risk clearly in &lt;a rel=&quot;nofollow&quot; href=&quot;https://csswizardry.com/2026/08/web-perf-wednesday-006-faster-browser-releases-change-your-rum-population/&quot;&gt;Web-Perf Wednesday 006&lt;/a&gt;: faster browser releases change the &lt;strong&gt;RUM population&lt;/strong&gt; you are averaging, not just the code on your server. Agencies that report &quot;Chrome 152 LCP&quot; and &quot;Chrome 153 LCP&quot; without sample sizes invite false escalations every Stable Tuesday.&lt;/p&gt;&lt;h2 id=&quot;put-chrome-stable-on-the-same-calendar-as-deploys-and-cdn-changes&quot; class=&quot;scroll-mt-24&quot;&gt;Put Chrome Stable on the same calendar as deploys and CDN changes&lt;/h2&gt;&lt;p&gt;Performance regressions are easier to debug when every graph annotation uses the same calendar. Most teams already mark application deploys, CDN cache rule changes, tag manager publishes, and major marketing releases. Browser Stable and Beta dates belong on that same timeline from September 2026 onward.&lt;/p&gt;&lt;p&gt;Checklist we ask account and engineering leads to maintain:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chrome Stable and Early Stable&lt;/strong&gt; dates for Desktop and Android (at minimum) through the next two milestones.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extended Stable&lt;/strong&gt; notes for clients with locked-down browser policies.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Firefox&lt;/strong&gt; milestone dates when the site has meaningful non-Chrome share in RUM.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;RUM or CrUX instrumentation changes&lt;/strong&gt; (new snippet, different sampling, new soft-navigation handler).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Named owner&lt;/strong&gt; who updates the calendar within one business day of a release (not &quot;the platform team&quot; in the abstract).&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;When field LCP moves in the weekly report, the first question is not &quot;what did we ship?&quot; but &quot;what changed in the window: browser, traffic, CDN, tags, or code?&quot; A single annotated timeline prevents the &quot;nobody deployed&quot; argument from turning into a trust fight. The ops checklist (release owner, browser rows beside deploy rows) is the agency ritual; the sections above carry the CrUX math and monitoring split.&lt;/p&gt;&lt;h3&gt;Sample thresholds before you slice field data by Chrome major&lt;/h3&gt;&lt;p&gt;Segmentation is useful after thresholds, not before. If Chrome 153 represents 4% of sessions in a 28-day URL-level slice, its p75 is not a client-ready KPI. Use thresholds to decide when a segment earns its own row in the report.&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Segment type&lt;/th&gt;&lt;th&gt;When to show in client body&lt;/th&gt;&lt;th&gt;When to keep internal&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Unsegmented origin or URL field p75&lt;/td&gt;&lt;td&gt;Always, with `collectionPeriod` dates&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mobile vs desktop field&lt;/td&gt;&lt;td&gt;When both pass eligibility&lt;/td&gt;&lt;td&gt;Thin desktop slice on mobile-heavy sites&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chrome major (e.g. M152 vs M153)&lt;/td&gt;&lt;td&gt;When each major has stable sample counts&lt;/td&gt;&lt;td&gt;Single-digit session majors&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beta / Dev channel&lt;/td&gt;&lt;td&gt;Rarely&lt;/td&gt;&lt;td&gt;Almost always appendix only&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;In first-party RUM, configure minimum session counts per segment before alerts fire. In CrUX-only workflows, respect Google's eligibility and popularity rules (&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/crux/methodology&quot;&gt;CrUX methodology&lt;/a&gt;): missing URL-level data is often &quot;not enough Chrome sessions,&quot; not a tooling failure. Say that explicitly in the report footnote.&lt;/p&gt;&lt;h2 id=&quot;use-scheduled-lab-runs-as-same-week-proof-when-field-crux-drifts&quot; class=&quot;scroll-mt-24&quot;&gt;Use scheduled lab runs as same-week proof when field CrUX drifts&lt;/h2&gt;&lt;p&gt;Unsegmented field series are the executive headline. They answer &quot;how are our users doing in aggregate?&quot; without opening a statistics debate on Chrome 152.3 versus 153.0. Browser-major slices are diagnostic tools for engineers checking whether a shift correlates with a Stable release line on the calendar.&lt;/p&gt;&lt;p&gt;Scheduled lab runs provide &lt;strong&gt;same-week proof&lt;/strong&gt; that the origin did not change:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Run PageSpeed Insights or Lighthouse on priority URLs on a fixed schedule (&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/how-to-schedule-pagespeed-monitoring-test-frequency-priority-portfolio&quot;&gt;how to schedule PageSpeed monitoring across a portfolio&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Store run timestamps beside field &lt;code&gt;collectionPeriod&lt;/code&gt; dates in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/client-ready-core-web-vitals-report-outline&quot;&gt;client-ready Core Web Vitals report outline&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;If lab LCP and INP stay inside budget while field p75 drifts, investigate population mix and browser cadence before you roll back a deploy.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;If lab and field move together after a deploy, treat it as a site change regardless of browser week.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Spot checks fail this test because Tuesday's paste and Thursday's paste are not a history. &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt; is where we unpacked why portfolios need schedules, not heroic manual runs. Apogee Watcher holds that lab clock for multi-tenant teams: scheduled tests, budgets, alerts, and CrUX field numbers when Google returns them beside the same URL row. We do not replace first-party RUM segmentation. We keep lab verification repeatable while you interpret field drift.&lt;/p&gt;&lt;h2 id=&quot;browser-mix-vs-fix-lag-and-crux-pipeline-delay-three-lag-types&quot; class=&quot;scroll-mt-24&quot;&gt;Browser mix vs fix lag and CrUX pipeline delay: three lag types&lt;/h2&gt;&lt;p&gt;Agencies confuse three lag types. Each needs a different sentence in the client deck.&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Lag type&lt;/th&gt;&lt;th&gt;Cause&lt;/th&gt;&lt;th&gt;What the client sees&lt;/th&gt;&lt;th&gt;Primary doc&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rolling-window fix lag&lt;/td&gt;&lt;td&gt;Pre-fix sessions still inside 28 days after a deploy&lt;/td&gt;&lt;td&gt;Slow field improvement after a verified lab win&lt;/td&gt;&lt;td&gt;[Why your fix is not in CrUX yet](https://apogeewatcher.com/blog/why-core-web-vitals-fix-not-in-crux-yet-28-day-window)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pipeline / publication lag&lt;/td&gt;&lt;td&gt;CrUX API, History, or BigQuery publish late&lt;/td&gt;&lt;td&gt;Same field values two days straight; missing weekly point&lt;/td&gt;&lt;td&gt;[CrUX pipeline delays](https://apogeewatcher.com/blog/crux-pipeline-delays-late-field-data-client-reports)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Browser population mix&lt;/td&gt;&lt;td&gt;New Chrome majors enter the window without a site deploy&lt;/td&gt;&lt;td&gt;Field moves while lab flat; shift aligns with Stable calendar&lt;/td&gt;&lt;td&gt;This post&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Fix lag is about &lt;strong&gt;your&lt;/strong&gt; sessions aging out. Pipeline lag is about &lt;strong&gt;Google's&lt;/strong&gt; publish schedule. Browser mix is about &lt;strong&gt;whose Chrome&lt;/strong&gt; sits inside an already-published window. A field LCP move with no deploy and flat lab budgets is often the third row, especially from September 2026 when two-week Stable releases overlap the 28-day average more often.&lt;/p&gt;&lt;h2 id=&quot;how-agencies-should-monitor-and-report-while-browser-mix-shifts&quot; class=&quot;scroll-mt-24&quot;&gt;How agencies should monitor and report while browser mix shifts&lt;/h2&gt;&lt;p&gt;From August through October 2026, expect more &quot;false regression&quot; tickets. Build the monitoring plan around dated clocks, not vibes.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Weekly field read&lt;/strong&gt; with &lt;code&gt;firstDate&lt;/code&gt; and &lt;code&gt;endDate&lt;/code&gt; on every table row. No naked p75 without collection period.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Daily or thrice-weekly lab&lt;/strong&gt; on money URLs through the Chrome 153 and 154 Stable window.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Release calendar&lt;/strong&gt; with browser Stable rows visible to SEO and engineering, not only infra.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Executive one-liner&lt;/strong&gt; in the retainer PDF: &quot;Field CrUX is a 28-day rolling average of real Chrome users; browser Stable releases can move field bands without a site deploy; lab trends below are same-week origin verification.&quot;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escalation rule:&lt;/strong&gt; open a code regression when lab budgets break or when unsegmented field and lab move together after a deploy; investigate population mix when lab is flat and field drifts across a Stable line.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Portfolio teams scale this with per-client organisations, shared budget templates, and alerts that fire on lab thresholds even when field data lags. That is the layer Apogee Watcher adds on top of Search Console and whatever RUM vendor the client already pays for.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Can Core Web Vitals change without a website update?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Yes. CrUX field metrics reflect real Chrome sessions over a rolling 28-day window. Browser updates, traffic mix shifts, and eligibility changes can move field p75 without any deploy on your origin. Lab runs on fixed URLs help prove whether the site changed.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How does Chrome's two-week release cycle affect CrUX data?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;More frequent Stable releases mean a 28-day field window can include two browser majors with different performance behaviour. Field LCP or INP can shift as auto-update spreads, even when your code is unchanged. Annotate Chrome Stable dates on your release calendar from Chrome 153 onward.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Should I segment RUM by browser version after Chrome 153?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Segment when sample sizes support it, and keep an unsegmented headline series for clients. Thin Chrome-major slices produce noisy charts. Set minimum session thresholds before alerts or report rows use a single major.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Is a field LCP move a
&lt;/strong&gt;&lt;/p&gt;</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25864/when-lcp-moves-and-nobody-deployed-browser-release-cadence-and-your-28-day-field-window</guid>
<pubDate>Wed, 02 Sep 2026 22:12:54 +0000</pubDate>
</item>
<item>
<title>How to measure LCP and INP in Safari 26.2 (and what still only Chrome reports)</title>
<link>https://coderlegion.com/24758/how-to-measure-lcp-and-inp-in-safari-26-2-and-what-still-only-chrome-reports</link>
<description>&lt;p&gt;For years, many agency Core Web Vitals programmes had a quiet blind spot. Chrome users filled CrUX, Search Console, and PageSpeed Insights field panels. Safari users on iPhone and Mac still felt slow pages, yet your JavaScript often never saw &lt;code&gt;largest-contentful-paint&lt;/code&gt; or Event Timing entries in WebKit. That gap mattered whenever a client’s traffic mix was heavy on iOS, education, or consumer brands with strong Apple share.&lt;/p&gt;&lt;p&gt;Safari 26.2, released 12 December 2025, adds the Largest Contentful Paint API and the Event Timing API in WebKit. You can finally collect Largest Contentful Paint (LCP) and Interaction to Next Paint (INP) from real Safari sessions through the Performance API, your own analytics, or a real user monitoring (RUM) tool. What follows is a practical measurement guide: how to observe the new entries, how to use Google’s &lt;code&gt;web-vitals&lt;/code&gt; library, what still only Chrome reports in public Google tools, and where scheduled PageSpeed monitoring still fits beside Safari RUM.&lt;/p&gt;&lt;h2 id=&quot;what-safari-262-changed-for-lcp-and-inp-measurement&quot; class=&quot;scroll-mt-24&quot;&gt;What Safari 26.2 changed for LCP and INP measurement&lt;/h2&gt;&lt;p&gt;Apple’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://webkit.org/blog/17640/webkit-features-for-safari-26-2/&quot;&gt;WebKit Features for Safari 26.2&lt;/a&gt; post states that Safari 26.2 adds support for Event Timing and Largest Contentful Paint. Event Timing follows an interaction from input through event handlers and DOM updates until the next paint, which is the raw material for INP. Largest Contentful Paint reports when the largest visible element in the viewport finished painting during load. Web Inspector also shows LCP entries in the Timelines tab, which is useful for verifying a hero image or text block before you trust a production pipeline.&lt;/p&gt;&lt;p&gt;Google’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/blog/lcp-and-inp-are-now-baseline-newly-available&quot;&gt;web.dev note on Baseline&lt;/a&gt; marks LCP and INP measurement APIs as Baseline Newly available after Safari 26.2 completed the major-browser set (Chromium already had them; Firefox added the INP pieces earlier). Newly available does not mean every visitor has upgraded. Users on older iOS builds, managed devices, or delayed OS updates still will not emit these entries until they move to a supporting Safari. Plan for mixed support for months, not for a single overnight switch.&lt;/p&gt;&lt;p&gt;Metric definitions have not changed. LCP still describes load feel for the main content. INP still describes responsiveness across interactions on the page. CLS still measures layout stability and remains Chromium-led in many RUM stacks. If you need a refresher before you change reporting templates, start with &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, and CLS explained&lt;/a&gt; and our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/understanding-inp-newest-core-web-vital&quot;&gt;INP guide&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;how-to-measure-lcp-in-safari-with-performanceobserver&quot; class=&quot;scroll-mt-24&quot;&gt;How to measure LCP in Safari with PerformanceObserver&lt;/h2&gt;&lt;p&gt;Once Safari exposes &lt;code&gt;largest-contentful-paint&lt;/code&gt; entries, you can observe them the same way you do in Chromium. Register a &lt;code&gt;PerformanceObserver&lt;/code&gt; with &lt;code&gt;buffered: true&lt;/code&gt; so candidates that fired before your script loaded still appear. Log or beacon each candidate, and treat the last candidate before the page is hidden as the LCP you report for that navigation.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const lcpObserver = new PerformanceObserver((entryList) =&amp;gt; {
  for (const entry of entryList.getEntries()) {
    // Candidates update as larger elements paint; keep the latest.
    console.log('LCP candidate', entry.startTime, entry.element, entry.url);
  }
});
lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finalise on &lt;code&gt;visibilitychange&lt;/code&gt; or &lt;code&gt;pagehide&lt;/code&gt; when the document becomes hidden, then disconnect the observer. That pattern matches how production RUM libraries avoid reporting a mid-load candidate as the permanent LCP. Feature-detect with &lt;code&gt;PerformanceObserver.supportedEntryTypes.includes('largest-contentful-paint')&lt;/code&gt; so older Safari builds stay quiet instead of throwing.&lt;/p&gt;&lt;p&gt;Use Web Inspector’s Layout and Rendering timeline to confirm the element you think is LCP is the one Safari records. Agencies often discover that a cookie banner, carousels, or a late web font swap changes the LCP element on iOS even when Chrome’s lab run pointed at the hero image. Fix the template once you see the Safari element; do not argue from a single Chrome Lighthouse screenshot alone.&lt;/p&gt;&lt;h2 id=&quot;how-to-measure-inp-in-safari-with-the-event-timing-api&quot; class=&quot;scroll-mt-24&quot;&gt;How to measure INP in Safari with the Event Timing API&lt;/h2&gt;&lt;p&gt;INP is not a single Event Timing entry. You observe &lt;code&gt;event&lt;/code&gt; entries (with &lt;code&gt;interactionId&lt;/code&gt; where available), keep the interaction latencies that matter, and apply the INP selection rules across the page lifetime. Safari 26.2’s Event Timing support is what makes that pipeline possible in WebKit. A minimal observer looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const eventObserver = new PerformanceObserver((entryList) =&amp;gt; {
  for (const entry of entryList.getEntries()) {
    if (!entry.interactionId) continue;
    console.log('Interaction', {
      name: entry.name,
      duration: entry.duration,
      startTime: entry.startTime,
      interactionId: entry.interactionId,
    });
  }
});
eventObserver.observe({ type: 'event', buffered: true, durationThreshold: 16 });
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lower &lt;code&gt;durationThreshold&lt;/code&gt; (for example &lt;code&gt;1&lt;/code&gt;) if you are debugging and need more events. Production pipelines usually keep a higher threshold and let a library compute INP so you do not re-implement selection logic incorrectly. Finalise INP when the page is hidden, because the metric can improve or worsen as the user keeps interacting.&lt;/p&gt;&lt;p&gt;Treat early Safari INP numbers with care. DebugBear notes that Safari’s INP implementation has had cases of unreasonably high scores while the engine settles. Segment by browser family before you tell a client that “INP exploded on iPhone.” Confirm the Safari version share in your analytics, re-check on a physical device, and compare against Chrome INP for the same URL template.&lt;/p&gt;&lt;h2 id=&quot;how-to-collect-safari-lcp-and-inp-with-web-vitalsjs&quot; class=&quot;scroll-mt-24&quot;&gt;How to collect Safari LCP and INP with web-vitals.js&lt;/h2&gt;&lt;p&gt;For most sites, Google’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/GoogleChrome/web-vitals&quot;&gt;&lt;code&gt;web-vitals&lt;/code&gt;&lt;/a&gt; library is the safer path than hand-rolled observers. It handles buffering, attribution helpers, and finalisation when the page is hidden. After Safari gained the underlying APIs, the same &lt;code&gt;onLCP&lt;/code&gt; and &lt;code&gt;onINP&lt;/code&gt; callbacks can receive Safari sessions once those users are on 26.2 or later.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { onLCP, onINP, onCLS } from 'web-vitals';

function sendToAnalytics(metric) {
  navigator.sendBeacon('/rum', JSON.stringify(metric));
}

onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ask your RUM vendor whether Safari LCP and INP are already flowing, or whether you need a library upgrade. Shopify’s performance team warned store owners that dashboards can shift once Safari data arrives, and that prior “Safari” LCP or INP rows in some tools were not true Safari field samples. Establish browser-family baselines before you treat a combined p75 as gospel.&lt;/p&gt;&lt;p&gt;Keep CLS in the pipeline where your stack supports it, and label browser coverage in client decks. CLS support is still uneven compared with LCP and INP across engines. A Safari-heavy site can look healthy on LCP while layout shift problems remain visible mainly in Chromium field data.&lt;/p&gt;&lt;h2 id=&quot;what-still-only-chrome-reports-crux-search-console-pagespeed-insights-field&quot; class=&quot;scroll-mt-24&quot;&gt;What still only Chrome reports (CrUX, Search Console, PageSpeed Insights field)&lt;/h2&gt;&lt;p&gt;Safari RUM and Google’s public field panels are not the same system. CrUX, the Chrome User Experience Report, remains a Chrome-user sample. Search Console’s Core Web Vitals report and the field block in PageSpeed Insights draw on that CrUX world. Turning on Safari observers does not fill those Google UIs with iPhone percentiles.&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Source&lt;/th&gt;&lt;th&gt;What you get after Safari 26.2&lt;/th&gt;&lt;th&gt;Still Chrome-skewed?&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;First-party RUM / `web-vitals` / vendor RUM&lt;/td&gt;&lt;td&gt;LCP and INP from Safari 26.2+ users when instrumented&lt;/td&gt;&lt;td&gt;No, if you segment by browser&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CrUX (origin or URL)&lt;/td&gt;&lt;td&gt;Real-user Chrome percentiles&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Search Console CWV report&lt;/td&gt;&lt;td&gt;Field issues from CrUX&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PageSpeed Insights field section&lt;/td&gt;&lt;td&gt;CrUX slices beside lab&lt;/td&gt;&lt;td&gt;Yes for field; lab is synthetic&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Scheduled Lighthouse / PageSpeed Insights lab&lt;/td&gt;&lt;td&gt;Controlled lab run on a listed URL&lt;/td&gt;&lt;td&gt;Lab is not Safari field&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;That split is why agencies still need both layers. Safari RUM answers “how do our iOS users experience this template?” Chrome field tools answer “what does Google’s Chrome-based field sample say for ranking and Search Console?” Scheduled lab runs answer “did yesterday’s deploy regress the URL we listed?” Confusing any two of those produces the same failure mode as treating a missing CrUX row as proof the page has no CLS. We covered missing field rows in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-no-cls-inp-for-url&quot;&gt;When PageSpeed Insights shows no CLS or INP&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;why-safari-and-chrome-lcp-timings-can-differ-slightly&quot; class=&quot;scroll-mt-24&quot;&gt;Why Safari and Chrome LCP timings can differ slightly&lt;/h2&gt;&lt;p&gt;Even when both browsers expose LCP, the clocks are not identical down to the millisecond. web.dev explains that Chrome has historically included a later &lt;code&gt;presentationTime&lt;/code&gt; in LCP, while Firefox and Safari stop at an earlier &lt;code&gt;paintTime&lt;/code&gt;. The difference is usually small, but it is enough to create noisy comparisons if you merge browser families into one percentile without labelling the engine. Chrome has been exposing more comparable paint timing for cross-browser work; still segment reports by browser until your tooling documents like-for-like fields.&lt;/p&gt;&lt;p&gt;Expect distribution shifts when Safari volume turns on in RUM. Some teams see slower Safari LCP than Chrome on the same URL; others see the opposite. Image decoding, font loading, and main-thread contention differ by engine and device. Use the new visibility to find Safari-specific issues (lazy-loaded LCP images, large hero assets on cellular, third-party scripts that hurt INP on iOS). Do not panic-rewrite the entire stack because a combined dashboard moved after Safari data landed.&lt;/p&gt;&lt;h2 id=&quot;agency-checklist-segment-safari-rum-beside-chrome-lab-and-crux&quot; class=&quot;scroll-mt-24&quot;&gt;Agency checklist: segment Safari RUM beside Chrome lab and CrUX&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Confirm Safari version share&lt;/strong&gt; in analytics for priority clients (especially education, consumer, and US mobile-heavy brands).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upgrade or verify RUM&lt;/strong&gt; so &lt;code&gt;web-vitals&lt;/code&gt; or your vendor actually receives Safari LCP and INP.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Baseline by browser family&lt;/strong&gt; for two to four weeks before rewriting client SLAs.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep CrUX and Search Console&lt;/strong&gt; as the Chrome field story for SEO conversations.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep scheduled lab tests&lt;/strong&gt; on money URLs for deploy regression, independent of Safari RUM noise.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document the stack in the monthly deck:&lt;/strong&gt; Safari RUM for iOS experience, CrUX for Google field, lab for release confidence.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Re-test INP outliers on device&lt;/strong&gt; before escalating Safari INP spikes to engineering as production incidents.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;For journey-heavy products (enrolment, lessons, checkout), map which steps matter on iPhone first. Our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-monitoring-for-edtech&quot;&gt;EdTech performance monitoring guide&lt;/a&gt; is a useful pattern even outside education: measure the stages users feel, not only the marketing homepage. The same habit applies to SaaS onboarding and ecommerce checkout when Safari share is material.&lt;/p&gt;&lt;h2 id=&quot;where-apogee-watcher-fits-after-safari-starts-reporting-lcp-and-inp&quot; class=&quot;scroll-mt-24&quot;&gt;Where Apogee Watcher fits after Safari starts reporting LCP and INP&lt;/h2&gt;&lt;p&gt;Apogee Watcher runs scheduled PageSpeed Insights tests across multi-tenant portfolios: discovery, mobile and desktop strategies, budgets, alerts, and client-ready trends. Those runs give you lab metrics plus CrUX field slices when Google has enough Chrome sample for the URL or origin. Watcher does not inject a Safari RUM snippet, and it does not claim Safari LCP or INP inside the product UI.&lt;/p&gt;&lt;p&gt;That boundary is deliberate. Safari field collection belongs in your RUM or first-party &lt;code&gt;web-vitals&lt;/code&gt; pipeline. Watcher stays on the deploy and portfolio side: catch regressions on listed URLs after theme, tag, or CDN changes, while Safari RUM tells you whether iOS users improved after the fix. Layer the two. Do not rip out Chrome field reporting, and do not pretend a lab score is a Safari percentile.&lt;/p&gt;&lt;p&gt;If you need the wider lab versus field decision tree, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance&quot;&gt;synthetic versus real user monitoring&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt;. Soft navigations and SPA route measurement remain a separate Chromium-led topic. Scheduled PageSpeed Insights still measures full document loads of the URLs you list, as we described for &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/soft-navigations-chrome-151-prepare-measure&quot;&gt;Chrome 151 soft navigations&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;Start a free trial&lt;/a&gt; to schedule PageSpeed tests and budgets across client sites while you instrument Safari RUM for iOS-heavy accounts. Or &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;run a free PageSpeed check&lt;/a&gt; on a priority URL before you change reporting templates.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Does Safari 26.2 mean CrUX now includes iPhone users?&lt;/strong&gt;&lt;br&gt;No. CrUX remains a Chrome user experience sample. Safari 26.2 lets your own RUM or analytics read LCP and INP from Safari sessions. It does not rewrite Search Console or PageSpeed Insights field panels into multi-engine field data.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Is CLS now available in Safari the same way as LCP and INP?&lt;/strong&gt;&lt;br&gt;Do not assume parity. This release is about Largest Contentful Paint and Event Timing for INP. Check your RUM vendor’s browser support table for CLS before you promise Safari layout-shift percentiles in a retainer report.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Should we stop using PageSpeed Insights lab scores?&lt;/strong&gt;&lt;br&gt;No. Lab scores remain useful for controlled comparisons after deploys. Pair them with Chrome field data where CrUX exists, and with Safari RUM where iOS traffic matters. Each layer answers a different question.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Why did our RUM LCP get worse after Safari data appeared?&lt;/strong&gt;&lt;br&gt;Combined percentiles often move when a new browser family joins the sample. Segment by Safari versus Chrome, confirm users are on 26.2+, and inspect the LCP element on a real iPhone before you treat the shift as a pure regression from your last release.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Can Apogee Watcher show Safari LCP and INP today?&lt;/strong&gt;&lt;br&gt;No. Watcher stores scheduled PageSpeed Insights lab results and available CrUX field slices for the URLs you monitor. Use RUM or &lt;code&gt;web-vitals&lt;/code&gt; for Safari field collection, and Watcher for portfolio lab cadence and alerts.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;References&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://webkit.org/blog/17640/webkit-features-for-safari-26-2/&quot;&gt;WebKit Features for Safari 26.2&lt;/a&gt; (WebKit)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/blog/lcp-and-inp-are-now-baseline-newly-available&quot;&gt;LCP and INP are now Baseline Newly available&lt;/a&gt; (web.dev)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-26_2-release-notes&quot;&gt;Safari 26.2 Release Notes&lt;/a&gt; (Apple)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.debugbear.com/blog/firefox-safari-web-vitals&quot;&gt;Firefox And Safari Now Support Two Core Web Vitals Metrics&lt;/a&gt; (DebugBear)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://performance.shopify.com/blogs/blog/safari-lcp-inp&quot;&gt;LCP and INP are now in Safari - What to expect&lt;/a&gt; (Shopify Performance)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.searchenginejournal.com/apple-safari-update-enables-tracking-two-core-web-vitals-metrics/563465/&quot;&gt;Apple Safari Update Enables Tracking Two Core Web Vitals Metrics&lt;/a&gt; (Search Engine Journal)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/GoogleChrome/web-vitals&quot;&gt;web-vitals library&lt;/a&gt; (Chrome)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/understanding-inp-newest-core-web-vital&quot;&gt;Understanding INP: The Newest Core Web Vital and Why It Matters&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance&quot;&gt;When to Use Synthetic vs Real User Monitoring for Performance&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights vs Automated Monitoring&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-no-cls-inp-for-url&quot;&gt;When PageSpeed Insights Shows No CLS or INP for Your URL&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/soft-navigations-chrome-151-prepare-measure&quot;&gt;Soft Navigations in Chrome 151: How to Prepare and What to Measure&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-monitoring-for-edtech&quot;&gt;Performance Monitoring for EdTech&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24758/how-to-measure-lcp-and-inp-in-safari-26-2-and-what-still-only-chrome-reports</guid>
<pubDate>Mon, 17 Aug 2026 12:44:00 +0000</pubDate>
</item>
<item>
<title>Lighthouse’s New Baseline Features Audit: What Developers Should Do With It</title>
<link>https://coderlegion.com/24002/lighthouses-new-baseline-features-audit-what-developers-should-do-with-it</link>
<description>&lt;p&gt;You ship a layout that looks clean in Chrome. A week later Safari users report a broken filter panel, or Firefox drops a CSS feature your design system assumed was safe. The Performance score on PageSpeed Insights still looks fine, because speed and interoperability are different questions. Until recently, Lighthouse did not give you a single Best Practices view of which web platform features your page (and its vendors) actually use, and where those features sit on the Baseline timeline.&lt;/p&gt;&lt;p&gt;Chrome’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/baseline-features&quot;&gt;Baseline Features&lt;/a&gt; audit now sits in Lighthouse’s Best Practices category as a diagnostic. It detects web feature IDs from the &lt;code&gt;web-features&lt;/code&gt; package, reports each feature’s Baseline status (Limited availability, Newly available, or Widely available), links to the matching entry on &lt;a rel=&quot;nofollow&quot; href=&quot;https://webstatus.dev&quot;&gt;webstatus.dev&lt;/a&gt;, and points at one place in the page’s source where that feature showed up. It also covers features used in third-party scripts and active extensions. What follows is a practical read of that report for developers and agencies: what the statuses mean, how to triage Limited features, when Newly available is acceptable, and how scheduled PageSpeed monitoring fits beside a one-off DevTools run.&lt;/p&gt;&lt;h2 id=&quot;what-the-lighthouse-baseline-features-audit-reports&quot; class=&quot;scroll-mt-24&quot;&gt;What the Lighthouse Baseline Features audit reports&lt;/h2&gt;&lt;p&gt;The audit is diagnostic. Chrome’s docs describe it as information for developers, not as a single pass/fail gate that behaves like a broken HTTPS check. Treat the output as an inventory with risk labels, not as a new Core Web Vitals threshold. If you only chase the green Performance dial, you can still ship Limited features that fail for a meaningful share of clients on Safari or Firefox.&lt;/p&gt;&lt;p&gt;For each detected feature you typically get three artefacts. The web feature ID (from the &lt;code&gt;web-features&lt;/code&gt; package) links through to &lt;a rel=&quot;nofollow&quot; href=&quot;https://webstatus.dev&quot;&gt;webstatus.dev&lt;/a&gt; so you can read support notes without leaving the report. The Baseline status tells you how far that feature has progressed through the WebDX Baseline model described on &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/baseline&quot;&gt;web.dev’s Baseline overview&lt;/a&gt;. A source location shows one occurrence in the site’s code or in loaded scripts, which is enough to open a ticket even when the same feature appears many times on the page.&lt;/p&gt;&lt;p&gt;Third-party coverage matters as much as first-party CSS. Tag managers, chat widgets, and personalisation scripts often pull newer APIs than your own theme ever would. The same pattern we cover in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/third-party-scripts-performance-worst-offenders&quot;&gt;third-party scripts and performance&lt;/a&gt; applies here: the vendor controls when their script updates, and you still answer the support ticket when a checkout filter breaks. Extensions loaded in the browser you used for the audit can also appear, so run a clean profile when you need a list you can show a client.&lt;/p&gt;&lt;h2 id=&quot;what-widely-available-newly-available-and-limited-availability-mean-for-web-platform-baseline&quot; class=&quot;scroll-mt-24&quot;&gt;What Widely available, Newly available, and Limited availability mean for web platform Baseline&lt;/h2&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/baseline&quot;&gt;Baseline&lt;/a&gt; answers a different question from “does Chrome support this?” Limited availability means the feature is not yet interoperable across the core browser set (desktop and mobile engines in the Baseline definition). Newly available means it has become interoperable across those core browsers. Widely available means roughly thirty months have passed since that Newly available date, which web.dev treats as a practical “safe for most sites” line, while still reminding teams that audience data can justify earlier or later adoption.&lt;/p&gt;&lt;p&gt;Use those labels as triage, not as hard law for every project. Widely available is the default green light for marketing sites and agency retainers where support tickets are expensive. Newly available is fine when you control progressive enhancement, have analytics that show the relevant engines are already current, or are shipping an internal tool with a known browser policy. Limited availability needs an explicit decision: polyfill or progressive enhancement, feature-detect and degrade, remove the usage, or accept documented risk with the client. &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/baseline-and-polyfills&quot;&gt;web.dev’s guidance on Baseline and polyfills&lt;/a&gt; is clear that polyfills do not move a feature out of Limited in Baseline messaging; native interoperability is what the status tracks.&lt;/p&gt;&lt;p&gt;A practical agency rule of thumb keeps reviews short. Treat Limited on a money URL as a release blocker until someone names the fallback. Treat Newly available as a design-system discussion, not a silent ship in the theme pull request. Treat Widely available as “no special story required,” unless your analytics show a long tail of very old browsers that still matter for that client.&lt;/p&gt;&lt;h2 id=&quot;how-to-triage-lighthouse-baseline-features-findings-on-a-live-page&quot; class=&quot;scroll-mt-24&quot;&gt;How to triage Lighthouse Baseline Features findings on a live page&lt;/h2&gt;&lt;p&gt;Open the Best Practices section after a Lighthouse or PageSpeed Insights run and collect every Limited row first. Ignore Widely available noise until Limited and Newly available are sorted. For each Limited feature, answer three questions in the ticket: first-party or third-party, which URL template, and what the user loses if the feature is missing. Then decide the fix class: remove, replace with a Widely available equivalent, progressive enhancement, or vendor escalation.&lt;/p&gt;&lt;h3&gt;First-party CSS and JavaScript&lt;/h3&gt;&lt;p&gt;When the source points at your stylesheet or application bundle, ownership is clear. Prefer a Widely available pattern when the visual result is equivalent, even if the newer syntax looks cleaner in Chrome DevTools. If the feature is Newly available and the design needs it, wrap behaviour behind feature detection and keep a usable fallback for engines that lag. Document the choice in the pull request so the next release does not “simplify” the fallback away during a tidy-up.&lt;/p&gt;&lt;h3&gt;Third-party scripts and tag managers&lt;/h3&gt;&lt;p&gt;When the occurrence sits in a vendor file or a Google Tag Manager-injected script, do not burn a sprint rewriting their minified output. Raise the Limited list with the vendor or the marketing owner of that tag, ask whether a widely supported build exists, and fence the tag behind consent or load rules if it is optional on the URL. If the vendor cannot commit to a timeline, treat the tag like any other performance offender: keep it off checkout and other money paths until the risk is accepted in writing by the account lead.&lt;/p&gt;&lt;h3&gt;Extensions and noisy environments&lt;/h3&gt;&lt;p&gt;Active extensions can inject features into the page under audit and pollute the inventory. For client reports, use a clean Chromium profile or an automated lab environment without personal extensions. Otherwise you will spend a call explaining why a password-manager API appeared on a retail homepage that never shipped that code.&lt;/p&gt;&lt;h2 id=&quot;when-is-baseline-newly-available-acceptable-on-client-sites&quot; class=&quot;scroll-mt-24&quot;&gt;When is Baseline Newly available acceptable on client sites?&lt;/h2&gt;&lt;p&gt;Newly available is not a failure. It means interoperability across the core set has only recently landed, so older minor versions and slow updaters may still miss it. For a consumer ecommerce site with a long mobile Safari tail, wait for Widely available or ship with a tested fallback. For a SaaS app where you already require current Chrome and Firefox, Newly available can be an intentional choice written into the browser support policy.&lt;/p&gt;&lt;p&gt;Decide with audience data, not with a Chrome-only staging machine. If you lack analytics, default to Widely available for public marketing pages and reserve Newly available for progressive enhancement that still works when the feature is missing. Record the decision in the ticket or design-system note so account managers do not treat every Newly available row as a red flag in the monthly review.&lt;/p&gt;&lt;h2 id=&quot;lighthouse-best-practices-versus-performance-scores-and-core-web-vitals&quot; class=&quot;scroll-mt-24&quot;&gt;Lighthouse Best Practices versus Performance scores and Core Web Vitals&lt;/h2&gt;&lt;p&gt;The Baseline Features audit lives under Best Practices. It does not replace Largest Contentful Paint, Interaction to Next Paint, or Cumulative Layout Shift, and it does not redefine how the lab Performance score is weighted. A page can score well on Performance while listing Limited features, or fail Core Web Vitals while using only Widely available APIs. Keep those dashboards separate in client language: speed budgets on one slide, interoperability findings on another.&lt;/p&gt;&lt;p&gt;If your team still pastes a single PageSpeed Insights run into Slack and calls the week done, the Baseline list will go stale the same way scores do. We covered that failure mode in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt;. Coding agents can also run Lighthouse for Best Practices in DevTools, which helps for a local fix but not for portfolio history. Pair this audit with the workflow in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lighthouse-audits-ai-agents-chrome-devtools&quot;&gt;Automate Lighthouse audits with AI agents&lt;/a&gt; when an engineer wants a one-shot pass, then put the URL back on a schedule so the next tag change does not silently reintroduce Limited features.&lt;/p&gt;&lt;h2 id=&quot;how-to-monitor-baseline-features-after-a-deploy-with-pagespeed-schedules&quot; class=&quot;scroll-mt-24&quot;&gt;How to monitor Baseline Features after a deploy with PageSpeed schedules&lt;/h2&gt;&lt;p&gt;One DevTools run proves what shipped today, but it does not prove the marketing site still looks the same after the next plugin update. For agencies, fold Baseline triage into the same schedule you already use for Core Web Vitals: priority URLs, mobile and desktop where it matters, and a named owner when Limited rows appear after a release. The &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/core-web-vitals-monitoring-checklist-for-agencies&quot;&gt;Core Web Vitals monitoring checklist for agencies&lt;/a&gt; is a useful starting list; add a short Best Practices / Baseline step on money templates after theme, tag, or design-system changes.&lt;/p&gt;&lt;p&gt;Apogee Watcher schedules PageSpeed Insights-backed lab runs across client sites, stores history, and alerts when budgets regress. Best Practices diagnostics, including Baseline Features when the Lighthouse version behind your PageSpeed Insights run includes them, appear in those lab reports as the PageSpeed Insights and Lighthouse versions catch up. Be honest about rollout lag: public PageSpeed Insights and local Lighthouse can ship audits on different clocks. Confirm the Baseline Features section appears on a fresh run before you promise clients a weekly Baseline comparison. Where it does appear, use Watcher for multi-site schedules and regression alerts; use DevTools for deep triage of a single Limited feature. Layer monitoring onto the stack you already have. Do not remove vendor real user monitoring or continuous integration solely to read Baseline statuses.&lt;/p&gt;&lt;h2 id=&quot;what-to-tell-clients-about-web-platform-baseline-and-lighthouse-best-practices&quot; class=&quot;scroll-mt-24&quot;&gt;What to tell clients about web platform Baseline and Lighthouse Best Practices&lt;/h2&gt;&lt;p&gt;Keep the retainer wording short so SEO and engineering stay aligned.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Baseline is WebDX’s shared language for how far a web platform feature has progressed across core browsers: Limited, Newly available, Widely available.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Lighthouse’s Baseline Features audit lists features detected on the page (including many third-party scripts), with links to webstatus.dev and a source hint.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Limited on a money URL needs an owner and a fallback plan before go-live. Newly available needs an audience check. Widely available is the usual default for public sites.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Performance scores and Core Web Vitals still answer speed and interaction quality. Baseline answers interoperability risk.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Done means Limited rows on priority URLs are cleared or accepted in writing, and scheduled lab runs still catch regressions after deploys.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Avoid inventing a “Baseline score” Google has not defined as a ranking factor. Report the inventory and the decisions you took on Limited rows. That is enough for most procurement conversations and quarterly client reviews.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;What is the Lighthouse Baseline Features audit?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It is a Best Practices diagnostic in Lighthouse that lists web platform features detected on the page, each with a Baseline status (Limited availability, Newly available, or Widely available), a link to webstatus.dev, and a source location. Chrome documents it under &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/baseline-features&quot;&gt;Baseline Features&lt;/a&gt;. It also lists features from third-party scripts and active extensions.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Does Baseline Newly available mean I should not ship the feature?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. Newly available means the feature is interoperable across the core browser set but has not yet reached the Widely available (about thirty months) line. Ship it when progressive enhancement or your audience data supports it. Prefer Widely available defaults for public marketing sites with unknown long tails.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Will Limited availability features lower my PageSpeed Insights Performance score?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not automatically. Baseline Features is a Best Practices diagnostic about interoperability, not a Performance metric like Largest Contentful Paint or Total Blocking Time. Fix Limited features for user risk and support cost, not because you expect the Performance dial alone to move.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Do third-party scripts show up in the Baseline Features audit?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Yes. Chrome’s documentation states the audit reports web features used in third-party scripts and extensions. That is often where Limited findings appear even when your own theme is conservative. Expect chat widgets, A/B tools, and tag-manager containers to contribute rows you did not author.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Does Apogee Watcher replace a manual Baseline Features review?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. Watcher runs scheduled lab tests and keeps portfolio history, budgets, and alerts so regressions after deploys are visible across many sites. Use DevTools or a single PageSpeed Insights report to triage a specific Limited feature, then keep the URL on a schedule so the next tag or theme change cannot quietly reintroduce it. Confirm your lab stack’s Lighthouse version includes the audit before you sell weekly Baseline reporting.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;Pick one money URL (homepage, product template, or checkout). Run Lighthouse in a clean Chrome profile, open Best Practices, and export every Limited and Newly available row into a short table: feature ID, status, first-party or third-party, owner, decision. Fix or fence the Limited items that affect that URL, then put the same URL on a Watcher or PageSpeed schedule so the next deploy still gets a lab history. Baseline Features closes an interoperability gap Lighthouse now names for you. Scheduled monitoring still closes the portfolio gap agencies own.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;References&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/baseline-features&quot;&gt;Baseline Features (Lighthouse Best Practices)&lt;/a&gt; — Chrome for Developers&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://webstatus.dev&quot;&gt;webstatus.dev&lt;/a&gt; — Web Platform Dashboard / feature status&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/baseline&quot;&gt;Baseline&lt;/a&gt; — web.dev overview&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/baseline-and-polyfills&quot;&gt;How to think about Baseline and polyfills&lt;/a&gt; — web.dev&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/third-party-scripts-performance-worst-offenders&quot;&gt;Third-Party Scripts and Performance: How to Identify and Fix the Worst Offenders&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights vs Automated Monitoring: When Manual Checks Aren't Enough&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lighthouse-audits-ai-agents-chrome-devtools&quot;&gt;Automate Lighthouse Audits with AI Agents: What Chrome DevTools Means for Agencies&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/core-web-vitals-monitoring-checklist-for-agencies&quot;&gt;Core Web Vitals Monitoring Checklist for Agencies&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24002/lighthouses-new-baseline-features-audit-what-developers-should-do-with-it</guid>
<pubDate>Mon, 03 Aug 2026 08:22:00 +0000</pubDate>
</item>
<item>
<title>Soft Navigations in Chrome 151: How to Prepare and What to Measure</title>
<link>https://coderlegion.com/24003/soft-navigations-in-chrome-151-how-to-prepare-and-what-to-measure</link>
<description>&lt;p&gt;Your React or Vue product site already updates the URL when someone clicks from pricing to checkout. The address bar looks like a new page. Search Console and PageSpeed Insights still treat most of that journey as one long document load, so Largest Contentful Paint (LCP) for the first paint stays on the initial hard navigation while later route changes never get their own Core Web Vitals story. Clients feel those transitions. Field tooling often does not.&lt;/p&gt;&lt;p&gt;Chrome has been working toward a browser-standard definition of those client-side route changes, called soft navigations. In &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/blog/chrome-151-beta#performancesoftnavigation_and_interactioncontentfulpaint_timeline_entries&quot;&gt;Chrome 151&lt;/a&gt; the soft-navigation and interaction-contentful-paint performance entry types ship for sites without a special flag. Barry Pollard's &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/web-platform/soft-navigations&quot;&gt;Measuring soft navigations&lt;/a&gt; guide (updated July 2026) states the feature is available for all sites from Chrome 151. What follows is a practical prep and measurement checklist for agencies: what soft navigations are, how Interaction Contentful Paint (ICP) relates to LCP on route changes, how to prepare the app so heuristics fire, what you can observe today, and where Apogee Watcher's scheduled lab runs still stop short.&lt;/p&gt;&lt;h2 id=&quot;what-soft-navigations-mean-for-spa-core-web-vitals&quot; class=&quot;scroll-mt-24&quot;&gt;What soft navigations mean for SPA Core Web Vitals&lt;/h2&gt;&lt;p&gt;Chrome's working definition of a soft navigation is short. The navigation starts from a user action. It results in a visible URL change. The interaction results in a visible paint. Sites that miss any of those three conditions may see false negatives (route changes users treat as navigations that never emit soft-navigation entries). Sites that meet them too loosely may see false positives. Feedback still belongs in the soft navigation specification repository, not in invented thresholds.&lt;/p&gt;&lt;p&gt;For Core Web Vitals reporting, the gap has always been architectural. Multi-page apps get a fresh navigation timing origin on each full document load. Single-page apps replace content with JavaScript, push history, and keep the same document. Classic LCP, Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS) still run, but they were designed around that document lifecycle. Soft navigations give Chromium a shared way to slice metrics per route-like transition, independent of which framework performed the update. For metric definitions before you argue about SPA timing, start with &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, and CLS explained&lt;/a&gt; and our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/understanding-inp-newest-core-web-vital&quot;&gt;INP guide&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Soft navigations do not replace hard navigations. Cold loads, deep links, and full reloads still use the usual navigation and LCP entries. Soft navigations sit beside that model for in-app route changes once Chrome detects them.&lt;/p&gt;&lt;h2 id=&quot;what-chrome-151-ships-for-soft-navigation-measurement&quot; class=&quot;scroll-mt-24&quot;&gt;What Chrome 151 ships for soft navigation measurement&lt;/h2&gt;&lt;p&gt;Chrome 151 adds &lt;code&gt;soft-navigation&lt;/code&gt; and &lt;code&gt;interaction-contentful-paint&lt;/code&gt; entry types to the Web Performance API timeline. The beta notes describe them as establishing new time origins for route transitions so Core Web Vitals can be measured for soft navigations. You can feature-detect with &lt;code&gt;PerformanceObserver.supportedEntryTypes.includes('soft-navigation')&lt;/code&gt; or check for &lt;code&gt;SoftNavigationEntry&lt;/code&gt; on &lt;code&gt;window&lt;/code&gt; while support is rolling out.&lt;/p&gt;&lt;p&gt;When soft navigations are active, Chrome changes how some timings report. A &lt;code&gt;soft-navigation&lt;/code&gt; entry emits after each detected soft navigation. It carries a &lt;code&gt;navigationId&lt;/code&gt;, the new URL in &lt;code&gt;name&lt;/code&gt;, and an &lt;code&gt;interactionId&lt;/code&gt; for the initiating interaction. One or more &lt;code&gt;interaction-contentful-paint&lt;/code&gt; entries emit after interactions that cause a contentful paint; each can include a &lt;code&gt;largestContentfulPaint&lt;/code&gt; property usable as LCP for that soft navigation when you map entries carefully. Soft-navigation entries also expose &lt;code&gt;paintTime&lt;/code&gt; and &lt;code&gt;presentationTime&lt;/code&gt; as FCP for that navigation, and &lt;code&gt;getLargestInteractionContentfulPaint()&lt;/code&gt; to retrieve the largest ICP entry for that navigation without buffering every paint yourself.&lt;/p&gt;&lt;p&gt;Hard-navigation LCP from &lt;code&gt;largest-contentful-paint&lt;/code&gt; still finalises on interaction as before. Soft-navigation LCP comes from ICP entries whose &lt;code&gt;interactionId&lt;/code&gt; matches the soft navigation, not from every later interaction on the same document. Timings remain relative to the original hard navigation start time, so you subtract the soft navigation &lt;code&gt;startTime&lt;/code&gt; when you report LCP relative to the route change. Chrome's docs recommend reporting TTFB as 0 for soft navigations for now, similar to back/forward cache restores, which is what the &lt;code&gt;web-vitals&lt;/code&gt; library does.&lt;/p&gt;&lt;p&gt;DevTools already shows soft navigation and LCP markers in the Performance panel trace view, marked with &lt;code&gt;*&lt;/code&gt; to distinguish them from hard navigations. That path is useful for verifying detection on a staging SPA before your RUM pipeline is ready. Walk the money routes once in the trace view so you know whether Chrome sees the same transitions your users feel.&lt;/p&gt;&lt;h2 id=&quot;how-to-prepare-your-spa-so-soft-navigations-can-be-detected&quot; class=&quot;scroll-mt-24&quot;&gt;How to prepare your SPA so soft navigations can be detected&lt;/h2&gt;&lt;p&gt;You cannot force Chrome to invent a soft navigation for a route change that never updates the URL or never paints. Preparation is about matching the heuristic, not about shipping a private score. If the address bar stays put or nothing paints after the click, no observer will invent a Core Web Vitals slice for that journey.&lt;/p&gt;&lt;h3&gt;Keep URL updates visible and history-friendly&lt;/h3&gt;&lt;p&gt;Soft navigations require a visible URL change tied to the user action. Use the History API or Navigation API in ways users already understand: push or replace state when the primary content area represents a new destination, keep the back button coherent, and avoid silent content swaps that leave the address bar on the previous path. If marketing and product disagree on whether a filter panel is a &quot;page,&quot; decide deliberately. Heuristics will not resolve product ambiguity for you.&lt;/p&gt;&lt;h3&gt;Paint after the interaction that starts the transition&lt;/h3&gt;&lt;p&gt;The third criterion is a visible paint after the interaction. If your router changes the URL before any paint, or paints before the URL update, Chrome still tries to reconcile ICP and soft-navigation ordering, but delayed paints and deferred URL updates create harder mapping. Prefer a clear sequence: user activates a control, content updates enough to paint, URL reflects the destination. Skeleton screens that paint count; invisible DOM mutations that never reach the screen do not.&lt;/p&gt;&lt;h3&gt;Test detection before you promise clients soft-nav field data&lt;/h3&gt;&lt;p&gt;Enable soft navigation heuristics in a local Chrome build if you need to verify early (&lt;code&gt;chrome://flags/#soft-navigation-heuristics&lt;/code&gt; or SoftNavigationHeuristics features), then re-check on Chrome 151+ where the feature is intended to be on by default. Walk primary SPA flows in DevTools Performance, confirm soft-navigation markers appear on the money routes, and note false positives on overlays that change the hash without a real destination change. Feature-detect before you attach observers in production so older Chromium builds and non-Chromium browsers stay quiet.&lt;/p&gt;&lt;h2 id=&quot;how-to-measure-soft-navigations-and-interaction-contentful-paint&quot; class=&quot;scroll-mt-24&quot;&gt;How to measure soft navigations and Interaction Contentful Paint&lt;/h2&gt;&lt;p&gt;Observe &lt;code&gt;soft-navigation&lt;/code&gt; with a &lt;code&gt;PerformanceObserver&lt;/code&gt;, including &lt;code&gt;buffered: true&lt;/code&gt; if you need earlier entries on the page. On each soft navigation, finalise metrics for the previous URL, then start fresh for the new URL using &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;navigationId&lt;/code&gt;. Map ICP entries to soft navigations with &lt;code&gt;interactionId&lt;/code&gt;, and use &lt;code&gt;getLargestInteractionContentfulPaint()&lt;/code&gt; so paints that happened before the soft-navigation entry was emitted still attach correctly.&lt;/p&gt;&lt;p&gt;Reset long-lived metrics the way Chrome's guide describes. When a new soft navigation starts, treat LCP, INP, and CLS as new series for that URL slice. Do not keep the previous route's largest paint or shift score as if the user never left. Subtract soft-navigation &lt;code&gt;startTime&lt;/code&gt; from soft-nav LCP timings so reports are relative to the route interaction, not the original document load.&lt;/p&gt;&lt;p&gt;Expect incomplete coverage. Soft-navigation APIs are Chromium-first. Other browsers and older Chrome versions may report classic Core Web Vitals without soft-navigation slices. Many RUM vendors are still aligning to the shipped API shape after origin-trial changes. Plan dual reporting for a while: hard-navigation metrics for cross-browser history, soft-navigation slices where Chromium support exists. That dual view is the same spirit as keeping lab and field clocks separate in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance&quot;&gt;synthetic versus real user monitoring&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Content that stays on screen across routes also matters. Soft-nav LCP from ICP only considers new paints tied to the initiating interaction. A persistent banner that was already the hard-nav LCP may not be the soft-nav LCP when only the body text changes. Deep links into the same URL as a hard load can report a different LCP element than an in-app soft navigation to that URL. Document that difference for clients so they do not treat soft-nav LCP as a drop-in twin of cold-load LCP.&lt;/p&gt;&lt;h2 id=&quot;soft-navigations-versus-scheduled-pagespeed-insights-monitoring&quot; class=&quot;scroll-mt-24&quot;&gt;Soft navigations versus scheduled PageSpeed Insights monitoring&lt;/h2&gt;&lt;p&gt;Scheduled PageSpeed Insights and Lighthouse runs still measure full document loads of the URLs you list. They do not walk your SPA click path and emit soft-navigation entries for every in-app route. That limit is honest product scope, not a bug in Chrome 151. If checkout is only reachable after three client-side transitions from the marketing homepage, a lab run of the checkout deep link still helps. It remains a hard navigation to that URL, not a soft navigation from pricing.&lt;/p&gt;&lt;p&gt;Agencies need both layers. Lab schedules catch regressions on public URLs after deploys: third-party tags, template changes, CDN mistakes. Soft-navigation instrumentation (RUM or first-party PerformanceObserver pipelines) catches whether route transitions themselves stay within agreed LCP and INP bands for Chromium users. Confusing the two produces the same failure mode as treating a single PageSpeed Insights paste as Search Console status. We unpacked when spot checks stop scaling in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt;. For SaaS product surfaces that live almost entirely behind soft navigations, pair this with the URL priorities in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-monitoring-saas-metrics-product-teams&quot;&gt;performance monitoring for SaaS&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Apogee Watcher stays on the scheduled lab and portfolio side: multi-tenant site lists, mobile and desktop strategies, budgets, and alerts when a listed URL regresses. Soft-navigation and ICP observation belong in your RUM or custom instrumentation until field tooling and CrUX-style aggregation catch up to the new entries. Layer Watcher for deploy confidence across many hostnames. Layer soft-nav measurement for SPA route truth on the products that need it. Do not claim Watcher already scores soft navigations as a first-class metric.&lt;/p&gt;&lt;p&gt;Related navigation performance topics will show up later on our calendar, including back/forward cache restores and Speculation Rules prefetch or prerender. Soft navigations solve a different problem. They measure in-document route changes once those changes look like navigations to users and to Chrome.&lt;/p&gt;&lt;h2 id=&quot;what-to-tell-clients-after-chrome-151-soft-navigations-ship&quot; class=&quot;scroll-mt-24&quot;&gt;What to tell clients after Chrome 151 soft navigations ship&lt;/h2&gt;&lt;p&gt;Keep the retainer script short. Account managers need one shared wording so engineering and SEO are not arguing past each other in the same thread. Put the bullets below in the monthly review deck, not only in a Slack reply after a client escalates.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Soft navigations are Chrome's way to measure SPA-style route changes that update the URL and paint after a user action.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Chrome 151 exposes &lt;code&gt;soft-navigation&lt;/code&gt; and &lt;code&gt;interaction-contentful-paint&lt;/code&gt; so teams can report Core Web Vitals per soft navigation in Chromium, with careful URL and interactionId mapping.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Lab PageSpeed Insights schedules still verify listed URLs as full loads. Soft-nav quality needs RUM or custom observers on the SPA itself.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Field reports will lag while RUM vendors and aggregation pipelines adopt the shipped API. Do not promise overnight Search Console parity for soft-nav LCP.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Done means hard-nav lab budgets stay green on public URLs, and soft-nav instrumentation (where you invested) shows stable route LCP and INP for the journeys you named.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Avoid inventing a soft-nav &quot;Good&quot; threshold Chrome has not published as a Core Web Vitals programme change. Use the same discipline you already use for LCP and INP definitions. Label soft-nav slices as Chromium-route metrics until standards and tooling settle, and keep hard-navigation budgets as the client-facing language you already report.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;What are soft navigations in Chrome 151?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Soft navigations are client-side route changes that start from a user action, change the visible URL, and produce a visible paint. Chrome 151 ships &lt;code&gt;soft-navigation&lt;/code&gt; and &lt;code&gt;interaction-contentful-paint&lt;/code&gt; performance entries so those transitions can carry their own timing origin for Core Web Vitals-style measurement in Chromium. Older Chrome versions and other browsers may still report only classic document-level metrics.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Is Interaction Contentful Paint the same as LCP?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not exactly. Interaction Contentful Paint entries describe contentful paints after interactions. For soft navigations, LCP for the route is taken from the largest matching ICP entry (via &lt;code&gt;largestContentfulPaint&lt;/code&gt; / &lt;code&gt;getLargestInteractionContentfulPaint()&lt;/code&gt;), mapped with &lt;code&gt;interactionId&lt;/code&gt;, with times adjusted by the soft navigation &lt;code&gt;startTime&lt;/code&gt;. Hard-navigation LCP still uses &lt;code&gt;largest-contentful-paint&lt;/code&gt; for the initial load.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Do soft navigations change how PageSpeed Insights scores my SPA homepage?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;A standard PageSpeed Insights or Lighthouse navigation still loads the URL you request as a document. Soft-navigation APIs affect what you can observe in the page after Chromium detects in-app transitions. They do not turn a single lab run into a full click-path audit of every SPA route.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Should we wait for CrUX before instrumenting soft navigations?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. Instrument and verify detection in Chromium now if SPA routes are commercially important. Field aggregation and cross-browser coverage will take longer. Keep scheduled lab monitoring on the public URLs you already sell, and treat soft-nav metrics as an additional Chromium slice until your RUM vendor documents support.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Does Apogee Watcher measure soft navigations today?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Watcher schedules PageSpeed Insights-backed tests on listed URLs and stores history, budgets, and alerts for those loads. Soft-navigation and ICP observation require page-side or RUM instrumentation. Use Watcher for portfolio deploy monitoring; add soft-nav measurement where SPA route quality is the product risk.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;Pick one SPA money path (pricing to checkout, search to product, dashboard to settings). On Chrome 151 or a flagged build, record a Performance panel trace while you click through, confirm soft-navigation markers fire, then attach a &lt;code&gt;PerformanceObserver&lt;/code&gt; for &lt;code&gt;soft-navigation&lt;/code&gt; and &lt;code&gt;interaction-contentful-paint&lt;/code&gt; on staging. Write down which URLs get soft-nav LCP and which never meet the three heuristics. Put the public deep-link URLs for those destinations on a Watcher or PageSpeed schedule so hard-navigation regressions still alert after the next theme or tag change. Soft navigations close a measurement gap Chrome owns. Scheduled monitoring still closes the portfolio gap agencies own.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24003/soft-navigations-in-chrome-151-how-to-prepare-and-what-to-measure</guid>
<pubDate>Sun, 02 Aug 2026 20:22:00 +0000</pubDate>
</item>
<item>
<title>Chrome Cut Android Scroll Jank 48%: What to Check on Your Site</title>
<link>https://coderlegion.com/23583/chrome-cut-android-scroll-jank-48-what-to-check-on-your-site</link>
<description>&lt;p&gt;A client scrolls a product page on Android and the page hitches, but they blame the phone, the network, or &quot;Chrome is slow.&quot; In July 2026 the Chromium team published how they &lt;a rel=&quot;nofollow&quot; href=&quot;https://blog.google/chromium/smoother-scrolling-how-we-halved-scroll-jank-in-chrome-on-android/&quot;&gt;reduced the frequency of janky scrolls in Chrome on Android by about 48% between 2023 and 2026&lt;/a&gt;. That work is real, but it still does not remove the cost of your JavaScript on the main thread, your &lt;code&gt;scroll&lt;/code&gt; listeners, or UI that shifts while the finger is moving.&lt;/p&gt;&lt;p&gt;Scroll jank is a missed frame during scroll: the screen shows a stale scroll offset for a refresh cycle (about 16.7 ms on a 60 Hz display). Chrome's post focuses on consistent input-to-frame delivery inside a multi-process browser, but your site owns a different slice of the same problem: work that runs while Chrome is trying to produce the next frame. The sections below are a practical checklist for web teams, not a rehash of Input Vizard or Direct2Thread.&lt;/p&gt;&lt;h2 id=&quot;what-chrome-fixed-on-android-scroll-jank-and-what-it-did-not&quot; class=&quot;scroll-mt-24&quot;&gt;What Chrome fixed on Android scroll jank (and what it did not)&lt;/h2&gt;&lt;p&gt;Petr Čermák's Chromium write-up describes instrumentation across the input-to-presentation pipeline, then a series of architectural projects: routing input away from a busy browser main thread, waiting briefly for late input after VSync, predicting scroll when input is delayed, cutting cross-process hops, moving browser-controls sync into Viz, and raising priority on Android input threads. The theme is consistency, so raw peak speed is not enough if one stage occasionally spikes and the frame deadline is missed.&lt;/p&gt;&lt;p&gt;None of that rewrites your page, so Chrome still has to run your scripts, apply your styles, and paint your DOM. If a &lt;code&gt;scroll&lt;/code&gt; handler forces layout, if a third-party tag runs a long task mid-gesture, or if a sticky bar and an infinite-scroll feed fight for space, users still feel stutter on the same phone that benefits from Chrome's pipeline work. Treat the 48% figure as a browser-side win, but treat residual jank after a Chrome update as a site audit signal.&lt;/p&gt;&lt;h2 id=&quot;what-is-scroll-jank-on-a-website&quot; class=&quot;scroll-mt-24&quot;&gt;What is scroll jank on a website?&lt;/h2&gt;&lt;p&gt;Scroll jank on a site shows up as hitching, rubber-banding that feels wrong, or content that jumps while the user is still dragging. It is related to, but not identical to, Core Web Vitals. Interaction to Next Paint (INP) measures responsiveness after interactions; Cumulative Layout Shift (CLS) measures unexpected layout movement. Heavy main-thread work during scroll can worsen both, and long tasks that block scrolling also show up as elevated Total Blocking Time (TBT) in lab runs. For metric definitions, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, and CLS explained&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/understanding-inp-newest-core-web-vital&quot;&gt;Understanding INP&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;When a stakeholder says &quot;scrolling feels bad on mobile,&quot; separate three causes before you open a hosting ticket:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Browser frame delivery (Chrome's domain; improving on Android).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Site main-thread and style work during scroll (your domain).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Layout that shifts while scrolling (your domain; often CLS).&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Only the second and third belong on your sprint board after a Chrome release note.&lt;/p&gt;&lt;h2 id=&quot;how-to-reduce-scroll-jank-free-the-main-thread-during-scroll&quot; class=&quot;scroll-mt-24&quot;&gt;How to reduce scroll jank: free the main thread during scroll&lt;/h2&gt;&lt;p&gt;Chrome's post is blunt that a busy main thread was a major source of non-deterministic delay on the critical path of a scroll. On the web side, the same idea applies, so keep the main thread free while the user is scrolling, or the browser's smoother pipeline still waits on your work.&lt;/p&gt;&lt;h3&gt;Long tasks and scroll handlers&lt;/h3&gt;&lt;p&gt;Search the codebase for &lt;code&gt;addEventListener('scroll'&lt;/code&gt;, &lt;code&gt;onscroll&lt;/code&gt;, &lt;code&gt;touchmove&lt;/code&gt;, and libraries that attach scroll spies by default (analytics &quot;scroll depth,&quot; sticky-header kits, parallax, lazy-load managers). For each listener, ask whether the work must run on every frame. Reading &lt;code&gt;offsetWidth&lt;/code&gt;, writing styles, and querying layout in the same turn forces synchronous layout and burns the frame budget. Prefer reading positions in one pass, writing in another, or moving visual follow effects to CSS (&lt;code&gt;position: sticky&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;) so the compositor can keep up.&lt;/p&gt;&lt;p&gt;If you only observe scroll position for analytics or lazy loading, register the listener with &lt;code&gt;{ passive: true }&lt;/code&gt; so the browser does not wait for your handler before continuing the scroll. If you must call &lt;code&gt;preventDefault&lt;/code&gt;, you cannot be passive, so keep that handler tiny and defer expensive work with &lt;code&gt;requestAnimationFrame&lt;/code&gt; or a short idle callback.&lt;/p&gt;&lt;p&gt;Long tasks from other sources still hitch scroll even when your scroll listener is clean. Third-party tags, hydration bursts, and theme scripts that parse large JSON on the main thread compete for the same thread Chrome needs for input. Our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/third-party-scripts-performance-worst-offenders&quot;&gt;third-party scripts guide&lt;/a&gt; covers how to find the worst offenders; for lab blocking time, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/fcp-tbt-supporting-metrics-beyond-core-web-vitals&quot;&gt;FCP and TBT as supporting metrics&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Compositor-friendly motion&lt;/h3&gt;&lt;p&gt;Animations and transitions that change &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt;, or &lt;code&gt;height&lt;/code&gt; on scroll tend to force layout and paint. Prefer &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;opacity&lt;/code&gt; for scroll-linked effects when you need motion at all. Many &quot;scroll reveal&quot; patterns are nicer as one-shot Intersection Observer callbacks than as continuous scroll math. If a design requires parallax, gate it behind a reduced-motion preference and test on mid-range Android devices, rather than only on a fast laptop with DevTools device mode.&lt;/p&gt;&lt;h2 id=&quot;mobile-scroll-performance-sticky-ui-infinite-scroll-and-late-injection&quot; class=&quot;scroll-mt-24&quot;&gt;Mobile scroll performance: sticky UI, infinite scroll, and late injection&lt;/h2&gt;&lt;p&gt;Mobile scroll performance fails in patterns that look fine in a quiet desktop lab. Sticky headers that resize on scroll, cookie banners that inject after first paint, chat widgets that open over content, and infinite-scroll lists that insert rows without reserved space all create layout work and CLS while the finger is moving. &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/cls-deep-dive-common-causes-fixes-layout-shift&quot;&gt;CLS deep-dive&lt;/a&gt; covers sizing and late injection, so the scroll-specific rule is simple: do not change layout geometry in response to scroll if you can help it.&lt;/p&gt;&lt;p&gt;Infinite scroll deserves its own check. Each batch of cards should reserve height (skeletons or aspect-ratio boxes) before images and ads arrive. Intersection Observer is usually enough to trigger fetches; a continuous scroll listener that measures every card on every frame is not. After a theme or tag change, re-test the primary feed URL on a real phone or a throttled mobile lab profile, because desktop CrUX can hide the hitch.&lt;/p&gt;&lt;p&gt;Form factor splits matter for monitoring too. Schedule and report mobile separately from desktop, as in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/mobile-vs-desktop-core-web-vitals-monitoring-both&quot;&gt;mobile versus desktop Core Web Vitals&lt;/a&gt;. Chrome's Android work improves one side of the field; your desktop Safari or Chrome desktop users still see whatever your handlers do.&lt;/p&gt;&lt;h2 id=&quot;what-to-check-on-your-site-after-chromes-scroll-jank-fixes&quot; class=&quot;scroll-mt-24&quot;&gt;What to check on your site after Chrome's scroll jank fixes&lt;/h2&gt;&lt;p&gt;Use this as a pull-request and release gate, not as a one-off audit PDF.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;List every &lt;code&gt;scroll&lt;/code&gt; / &lt;code&gt;touchmove&lt;/code&gt; / wheel listener on priority templates (homepage, PDP, article, category feed).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Mark each as passive observe, must &lt;code&gt;preventDefault&lt;/code&gt;, or removable.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Remove or rewrite handlers that force layout (&lt;code&gt;getBoundingClientRect&lt;/code&gt; loops, style writes) on every event.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Move scroll-linked visuals to CSS sticky / transform where possible.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Reserve space for lazy images, embeds, and infinite-scroll rows before they load.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Audit third-party tags for long tasks during the first scroll gesture after load.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Respect &lt;code&gt;prefers-reduced-motion&lt;/code&gt; for decorative scroll effects.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Re-run mobile lab (PageSpeed Insights or Lighthouse) on the URLs you changed; store the before/after.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Watch INP and CLS field bands on those URLs for the following weeks; do not expect overnight CrUX flips (&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/why-core-web-vitals-fix-not-in-crux-yet-28-day-window&quot;&gt;why field lags lab&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;One green Lighthouse paste after a Chrome update is not proof the portfolio is smooth, because spot checks miss the template you did not open. That gap is why &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights versus automated monitoring&lt;/a&gt; exists for multi-site teams.&lt;/p&gt;&lt;h2 id=&quot;how-to-monitor-mobile-scroll-performance-across-a-client-portfolio&quot; class=&quot;scroll-mt-24&quot;&gt;How to monitor mobile scroll performance across a client portfolio&lt;/h2&gt;&lt;p&gt;Agencies cannot feel every client's feed on every phone after every plugin update. Put the money URLs (feeds, PDPs, long articles) on a mobile schedule, set budgets on LCP, INP, and CLS, and alert when a release regresses lab vitals even if scroll &quot;feels&quot; fine in the office. Match frequency to risk using &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/how-to-schedule-pagespeed-monitoring-test-frequency-priority-portfolio&quot;&gt;how to schedule PageSpeed monitoring&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Apogee Watcher runs scheduled PageSpeed Insights-backed tests across many sites, keeps mobile and desktop as separate strategies, and stores history so you can show before/after when a sticky header or tag manager change lands. We do not claim a dedicated &quot;scroll jank&quot; metric in-product, but we give you the Core Web Vitals and supporting lab timings that move when main-thread and layout cost during scroll get worse, across the portfolio without pasting PageSpeed Insights links into a spreadsheet. Layer Watcher beside RUM or session replay when you need gesture-level proof on a single flagship site.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Did Chrome fix scroll jank so sites no longer need to care?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. Chrome reduced how often its own pipeline misses frame deadlines on Android, but your scroll handlers, long tasks, and layout shifts during scroll still run on the page. Browser gains and site work stack; they do not replace each other.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Is scroll jank the same as poor INP or CLS?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not exactly: scroll jank is missed frames during scroll, while INP scores interaction latency and CLS scores unexpected layout shift. The same main-thread and layout habits often drive all three, so fixing scroll handlers and reserved space usually helps the vitals you already report.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How do I find scroll listeners that hurt mobile scroll performance?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Search the bundle and third-party tags for scroll and touch listeners, then profile a mid-range Android device (or a throttled lab profile) while scrolling the money URL and watch for long tasks and forced layout in Performance traces. Start with themes, sticky headers, analytics scroll depth, and infinite-scroll libraries.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Should we re-test after every Chrome release?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Re-test after your own releases first; when Chrome announces scroll or input pipeline changes, spot-check one or two mid-range Android devices on a priority URL, then rely on scheduled mobile monitoring for the rest of the portfolio rather than a manual PageSpeed Insights day.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;On Monday, pick one client feed or article URL that drew a &quot;scrolling feels bad&quot; comment. Open the Performance panel, scroll for ten seconds on a mobile profile, and list every long task and layout shift during that gesture. Fix or remove one handler, reserve space for one late-loading block, then store a mobile lab run. If you manage many sites and need that history on a schedule, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/&quot;&gt;start a free trial of Apogee Watcher&lt;/a&gt; or run a &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;free domain PageSpeed check&lt;/a&gt; on the URL that complains most on phones.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23583/chrome-cut-android-scroll-jank-48-what-to-check-on-your-site</guid>
<pubDate>Wed, 29 Jul 2026 08:12:00 +0000</pubDate>
</item>
<item>
<title>Trying Declarative Partial Updates: A Future API for Replacing HTML Later</title>
<link>https://coderlegion.com/21951/trying-declarative-partial-updates-a-future-api-for-replacing-html-later</link>
<description>&lt;p&gt;Hoi hoi!&lt;/p&gt;
&lt;p&gt;I'm &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/nyaomaru&quot;&gt;@nyaomaru&lt;/a&gt;, a frontend engineer who was cheering for the World Cup during tropical nights in the Netherlands while nearly melting from heat exhaustion. ⚽ (But yesterday was comfortable 😺)&lt;/p&gt;
&lt;p&gt;How do you usually build frontend applications?&lt;/p&gt;
&lt;p&gt;Do you build SPAs with &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Do you use SSR / SSG / ISR frameworks like &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;There are many ways to build frontend applications, but today it is very common to update the DOM on the client side using JavaScript.&lt;/p&gt;
&lt;p&gt;Even when using UI libraries and frameworks like &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt;, or SSR frameworks like &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;, there are still many cases where part of the screen is eventually updated by client-side JavaScript.&lt;/p&gt;
&lt;p&gt;But is that really always the best answer?&lt;/p&gt;
&lt;p&gt;Are there cases where we are forcing JavaScript on the client to handle work that could naturally be handled on the server?&lt;/p&gt;
&lt;p&gt;In response to that kind of question, the Chrome team introduced an experimental API called DPU, or Declarative Partial Updates. 🚀&lt;/p&gt;
&lt;p&gt;{% embed &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/blog/declarative-partial-updates?hl=en&quot;&gt;https://developer.chrome.com/blog/declarative-partial-updates?hl=en&lt;/a&gt; %}&lt;/p&gt;
&lt;p&gt;In this article, I want to explore what Declarative Partial Updates are, what problems they try to solve, and why they might matter.&lt;/p&gt;
&lt;p&gt;I will focus especially on the out-of-order streaming mechanism that can replace parts of HTML later without writing client-side JavaScript for the replacement itself.&lt;/p&gt;
&lt;p&gt;Let's dive in!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/zsfps9jwqzeu8tjzh7o5.png&quot; alt=&quot;nyaomaru soccer&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-what-are-declarative-partial-updates-&quot;&gt;🧩 What are Declarative Partial Updates?&lt;/h3&gt;
&lt;p&gt;Declarative Partial Updates are, roughly speaking&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A mechanism where you declare part of your HTML as “this area will be replaced later”, and then update only that part with HTML that arrives later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, imagine you want to return the overall page HTML immediately, but some data is slower to fetch.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The header is instant&lt;/li&gt;
&lt;li&gt;The layout is fast&lt;/li&gt;
&lt;li&gt;The user profile is also pretty fast&lt;/li&gt;
&lt;li&gt;But only the recommendations API is slow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In that case, we often show a loading state on the client, fetch data, and update the DOM with JavaScript. In &lt;code&gt;React&lt;/code&gt;, you might reach for something like &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With DPU, the server can first return HTML like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;section&amp;gt;
  &amp;lt;h2&amp;gt;Recommendations&amp;lt;/h2&amp;gt;

  &amp;lt;?start name=&quot;recommendations&quot;&amp;gt;
    &amp;lt;p&amp;gt;Loading recommendations...&amp;lt;/p&amp;gt;
  &amp;lt;?end&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The area surrounded by &lt;code&gt;&amp;lt;?start name=&quot;recommendations&quot;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; is a &lt;strong&gt;region that can be replaced later&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Then, when the recommendations HTML is ready on the server, it can stream HTML like this later.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template for=&quot;recommendations&quot;&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;Advanced CSS Layouts&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Modern HTML APIs&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Web Performance Basics&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At that point, the browser finds the region named &lt;code&gt;recommendations&lt;/code&gt; and replaces the loading UI with the contents of this &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Wait, does that feel a bit weird?&lt;/p&gt;
&lt;p&gt;Exactly. The wild part is that &lt;strong&gt;up to this point, we did not write any JavaScript for the replacement, and no framework is involved&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In other words, you no longer need to write client-side JavaScript like this just to replace that area:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const element = document.querySelector(&quot;#recommendations&quot;);
element.innerHTML = html;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You stream HTML, and the browser understands where that HTML should go.&lt;/p&gt;
&lt;p&gt;That is the interesting part of Declarative Partial Updates.&lt;/p&gt;
&lt;p&gt;DPU also has &lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt;, not only &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; is basically a marker that says, “insert later HTML here.”&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;?marker name=&quot;placeholder&quot;&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;template for=&quot;placeholder&quot;&amp;gt;
  &amp;lt;p&amp;gt;Here is streamed content!&amp;lt;/p&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the browser finds the marker named &lt;code&gt;placeholder&lt;/code&gt; and inserts the contents of the later &lt;code&gt;&amp;lt;template for=&quot;placeholder&quot;&amp;gt;&lt;/code&gt; at that position.&lt;/p&gt;
&lt;p&gt;On the other hand, the &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; pair used mainly in this article is for showing placeholder content, such as a loading UI, and replacing that entire range later.&lt;/p&gt;
&lt;p&gt;So, roughly&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; means “insert here”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt; means “replace this range”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That mental model should be enough to start.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; can also be used by leaving the same marker inside streamed content, which lets you append list items one by one. That is pretty interesting too.&lt;/p&gt;
&lt;p&gt;In the first half of this article, I focus mainly on replacing loading UI, so I mostly use &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;?end&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the later sample, I also try an example that uses &lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt; to append asset links sequentially.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-why-do-we-need-declarative-partial-updates-&quot;&gt;🤔 Why do we need Declarative Partial Updates?&lt;/h3&gt;
&lt;p&gt;At this point, you might think&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Wait, frameworks like React or Astro can already do this, right?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes. They can.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt; / &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;, you can show loading states, receive API results, and update parts of the screen. Many of us do this every day.&lt;/p&gt;
&lt;p&gt;But wait a second. A lot of that is implemented by &lt;strong&gt;client-side JavaScript updating the DOM&lt;/strong&gt;, right?&lt;/p&gt;
&lt;p&gt;A common flow looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The server returns HTML&lt;/li&gt;
&lt;li&gt;The browser displays the HTML&lt;/li&gt;
&lt;li&gt;Client-side JavaScript is loaded&lt;/li&gt;
&lt;li&gt;JavaScript calls an API&lt;/li&gt;
&lt;li&gt;The API result is put into state&lt;/li&gt;
&lt;li&gt;The framework updates the DOM&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course, this is an extremely common frontend architecture today.&lt;/p&gt;
&lt;p&gt;But if part of the screen is “something the server can already produce as HTML”, do we really need to make client-side JavaScript do that work every time?&lt;/p&gt;
&lt;p&gt;For example, the recommendations HTML can be generated on the server like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;Advanced CSS Layouts&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;Modern HTML APIs&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;Web Performance Basics&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If all we want to do is send that to the browser, it can feel a bit indirect to do this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;fetch(&quot;/api/recommendations&quot;)
  .then((res) =&amp;gt; res.json())
  .then((items) =&amp;gt; {
    setRecommendations(items);
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You fetch JSON, convert it to HTML on the client, update state, and then update the DOM.&lt;/p&gt;
&lt;p&gt;That is convenient, but it is also a bit roundabout. &lt;/p&gt;
&lt;p&gt;What makes DPU interesting is that it points in another direction&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If the server can produce HTML, why not stream that HTML directly and let the browser insert it into the right place?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So DPU is &lt;strong&gt;not a replacement for &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt;&lt;/strong&gt;. It is more like a lower-level browser primitive.&lt;/p&gt;
&lt;p&gt;It may allow the browser to understand, as part of HTML itself, some of the partial update work that frameworks currently handle.&lt;/p&gt;
&lt;p&gt;If that happens, the boundary between client-side responsibility and server-side responsibility becomes even more important.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What can be done with HTML?&lt;/li&gt;
&lt;li&gt;What should be done with JavaScript?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By redesigning these boundaries and declaring things in a way that fits the browser, we may be able to unlock browser capabilities that we are not fully using yet.&lt;/p&gt;
&lt;p&gt;But we should not misunderstand &lt;strong&gt;the client still has responsibilities&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This discussion is not about replacing state management, and interactive features still need JavaScript.&lt;/p&gt;
&lt;p&gt;For example, forms, modals, charts, and similar UI should still be managed on the client side, while static text or server-generated HTML based on slower API responses may be a better fit for HTML streaming.&lt;/p&gt;
&lt;p&gt;The responsibility split becomes more complex, but the UX may improve a lot. This is definitely something worth watching.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-this-may-expand-what-spas-can-do&quot;&gt;🏠 This may expand what SPAs can do&lt;/h3&gt;
&lt;p&gt;DPU is &lt;strong&gt;not about rejecting SPAs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Personally, I see it as something that may expand the possibilities of SPAs.&lt;/p&gt;
&lt;p&gt;Until now, SPAs have often followed this mental model.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Fetch data as JSON
    ↓
Put it into client-side state
    ↓
Re-render components
    ↓
Update the DOM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if DPU and the new HTML insertion / streaming APIs become available, another option appears.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;The server returns HTML
    ↓
HTML is streamed
    ↓
The browser inserts it into the existing DOM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That means an SPA could potentially choose different update strategies for different parts of the UI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fetch JSON and render on the client&lt;/li&gt;
&lt;li&gt;Generate HTML on the server and insert it directly&lt;/li&gt;
&lt;li&gt;Return only the shell initially, then stream slower parts later&lt;/li&gt;
&lt;li&gt;Perform page-transition-like updates with HTML partials&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is really interesting.&lt;/p&gt;
&lt;p&gt;SPAs often carry the image of “doing everything with client-side JavaScript”, but they may become more hybrid in the future. The meaning of the word SPA itself may change.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;State that belongs on the client stays on the client&lt;/li&gt;
&lt;li&gt;HTML that can be produced on the server is produced on the server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the browser does not merely display that HTML. It also understands &lt;strong&gt;where and how to insert it&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If this direction continues, frontend architecture may become even more flexible and deeper than it is today.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-apis-for-streaming-html-from-javascript-are-also-coming&quot;&gt;🧪 APIs for streaming HTML from JavaScript are also coming&lt;/h3&gt;
&lt;p&gt;The interesting part of DPU is not only out-of-order streaming with &lt;code&gt;&amp;lt;template for=&quot;...&quot;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Chrome team is also proposing a new set of APIs for inserting and streaming HTML from JavaScript.&lt;/p&gt;
&lt;p&gt;Even today, there are several ways to dynamically insert HTML.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;element.innerHTML = html;
element.outerHTML = html;
element.insertAdjacentHTML(&quot;beforeend&quot;, html);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But they all have slightly different behavior.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does it overwrite existing content?&lt;/li&gt;
&lt;li&gt;Does it append after the existing content?&lt;/li&gt;
&lt;li&gt;Are &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags executed?&lt;/li&gt;
&lt;li&gt;What happens with sanitization?&lt;/li&gt;
&lt;li&gt;How does it interact with Trusted Types?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a lot of subtle differences.&lt;/p&gt;
&lt;p&gt;Honestly, I do not think many developers can confidently explain all of those differences from memory. I definitely cannot.&lt;/p&gt;
&lt;p&gt;The new APIs try to make HTML insertion easier to understand with more consistent names.&lt;/p&gt;
&lt;p&gt;For example, static HTML insertion looks like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const newHTML = &quot;&amp;lt;p&amp;gt;This is a new paragraph&amp;lt;/p&amp;gt;&quot;;
const contentElement = document.querySelector(&quot;#content-to-update&quot;);

contentElement.setHTML(newHTML);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not an API that appends to the end, like &lt;code&gt;insertAdjacentHTML(&quot;beforeend&quot;, html)&lt;/code&gt;. It replaces the existing contents of &lt;code&gt;contentElement&lt;/code&gt; with &lt;code&gt;newHTML&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A useful way to understand the difference is&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setHTML()&lt;/code&gt; is the safer API that runs through a sanitizer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setHTMLUnsafe()&lt;/code&gt; disables the sanitizer by default and lets you handle HTML more directly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then comes the really interesting part of streaming versions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const contentElement = document.querySelector(&quot;#content-to-update&quot;);

const response = await fetch(&quot;/api/content.html&quot;);

response.body
  .pipeThrough(new TextDecoderStream())
  .pipeTo(contentElement.streamHTMLUnsafe());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is pretty wild.&lt;/p&gt;
&lt;p&gt;It means we may be able to take HTML returned by &lt;code&gt;fetch()&lt;/code&gt; and stream it directly into an element &lt;strong&gt;without waiting for the entire response to finish downloading&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;SPAs have not benefited much from HTML streaming after the initial document load.&lt;/p&gt;
&lt;p&gt;The initial document can be streamed from the server, but later screen updates often become JSON fetch + client render.&lt;/p&gt;
&lt;p&gt;With APIs like this, SPA updates may also be able to benefit from HTML streaming.&lt;/p&gt;
&lt;p&gt;That is why I think this may expand the possibilities of SPAs.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-unsafe-does-not-mean-never-use-it-&quot;&gt;⚠️ “unsafe” does not mean “never use it”&lt;/h3&gt;
&lt;p&gt;When you see a name like &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt;, you might think&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Unsafe!? That sounds terrifying.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I thought that too at first.&lt;/p&gt;
&lt;p&gt;But this &lt;code&gt;unsafe&lt;/code&gt; does not mean “you must never use it.” It is closer to a warning that &lt;strong&gt;the sanitizer is disabled by default, so you need to think carefully about whether the input is trusted&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example, it would be dangerous to stream user-generated HTML directly into the DOM.&lt;/p&gt;
&lt;p&gt;But if the HTML is generated by your own trusted server, there may be valid use cases.&lt;/p&gt;
&lt;p&gt;Of course, before using this in production, you need to think carefully about sanitizers, Trusted Types, script execution, browser support, and other security concerns.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-what-happens-when-dpu-and-the-streaming-apis-are-combined-&quot;&gt;➕ What happens when DPU and the streaming APIs are combined?&lt;/h3&gt;
&lt;p&gt;This is the most interesting part.&lt;/p&gt;
&lt;p&gt;DPU’s &lt;code&gt;&amp;lt;template for=&quot;...&quot;&amp;gt;&lt;/code&gt; and the new HTML streaming APIs are &lt;strong&gt;separate APIs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But combining them makes the story even deeper.&lt;/p&gt;
&lt;p&gt;For example, imagine placing placeholders in an SPA screen.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;main&amp;gt;
  &amp;lt;?start name=&quot;page-title&quot;&amp;gt;
    &amp;lt;h1&amp;gt;Loading...&amp;lt;/h1&amp;gt;
  &amp;lt;?end&amp;gt;
  
  &amp;lt;?start name=&quot;page-content&quot;&amp;gt;
    &amp;lt;p&amp;gt;Loading content...&amp;lt;/p&amp;gt;
  &amp;lt;?end&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, during a page update, the server streams HTML.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template for=&quot;page-title&quot;&amp;gt;
  &amp;lt;h1&amp;gt;Dashboard&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;template for=&quot;page-content&quot;&amp;gt;
  &amp;lt;section&amp;gt;
    &amp;lt;p&amp;gt;This is the dashboard content.&amp;lt;/p&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of manually targeting the DOM with JavaScript.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;document.querySelector(&quot;#page-title&quot;).innerHTML = titleHTML;
document.querySelector(&quot;#page-content&quot;).innerHTML = contentHTML;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the browser may be able to understand where &lt;code&gt;page-title&lt;/code&gt; and &lt;code&gt;page-content&lt;/code&gt; should be applied.&lt;/p&gt;
&lt;p&gt;In other words, even in SPA-style page transitions, something like this may become possible.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Fetch a new page's HTML partial
    ↓
Stream the HTML
    ↓
Update only the necessary places via template for
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Part of the work that frameworks currently handle with Virtual DOM, compilers, or fine-grained reactivity may be shifted to browser-native HTML streaming / partial updates.&lt;/p&gt;
&lt;p&gt;That makes DPU feel like more than just a small HTML API. It feels like something that could expand the design space of frontend architecture.&lt;/p&gt;
&lt;p&gt;Of course, this is still experimental. This is not a “let's all use this in production right now” kind of API.&lt;/p&gt;
&lt;p&gt;But the old assumption&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;An SPA fetches JSON and renders on the client&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;may start to change.&lt;/p&gt;
&lt;p&gt;HTML may evolve from “a static document loaded once at the beginning” into “a UI unit that can be streamed, replaced, and updated.”&lt;/p&gt;
&lt;p&gt;That is pretty exciting, right?&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-trying-it-with-node-js-dpu-samples&quot;&gt;🚀 Trying it with Node.js DPU samples&lt;/h3&gt;
&lt;p&gt;So far, we have talked about the concept. I also built a small Node.js sample app to try this out.&lt;/p&gt;
&lt;p&gt;{% embed &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/nyaomaru/declarative-partial-updates-sample&quot;&gt;https://github.com/nyaomaru/declarative-partial-updates-sample&lt;/a&gt; %}&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is an experimental feature, so you need Chrome Canary (Chrome v148 or later) or a Chrome build that includes this feature, with the experimental flag enabled.&lt;/p&gt;
&lt;p&gt;Open the following URL in Chrome’s address bar:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;chrome://flags/#enable-experimental-web-platform-features&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Enable it, click “Relaunch”, and then run the sample. This article assumes a supported build with this flag enabled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/t7ffawoyyt5vm4krbhob.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The demo app has roughly three pages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;/              ... Document streaming
/hybrid-shell  ... Hybrid shell + streamed HTML route updates
/set-apis      ... Static / Streaming HTML APIs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first page, &lt;code&gt;/&lt;/code&gt;, demonstrates DPU out-of-order streaming.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/7xrej8wmdlbqnla84pgn.gif&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;The server first returns an HTML shell, and slower server-rendered fragments are streamed later as &lt;code&gt;&amp;lt;template for=&quot;...&quot;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, the initial HTML contains a placeholder.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;article class=&quot;panel&quot;&amp;gt;
  &amp;lt;h2&amp;gt;Recommendations&amp;lt;/h2&amp;gt;

  &amp;lt;?start name=&quot;recommendations&quot;&amp;gt;
    &amp;lt;p class=&quot;loading&quot;&amp;gt;Waiting for recommendations...&amp;lt;/p&amp;gt;
  &amp;lt;?end&amp;gt;
&amp;lt;/article&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, the browser shows the loading UI.&lt;/p&gt;
&lt;p&gt;Then, once the recommendations HTML is ready on the server, it streams a chunk.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template for=&quot;recommendations&quot;&amp;gt;
  &amp;lt;ul class=&quot;list&quot;&amp;gt;
    &amp;lt;li&amp;gt;Advanced CSS Layouts&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Modern HTML APIs&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Web Performance Basics&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The browser finds the DPU range named &lt;code&gt;recommendations&lt;/code&gt; and replaces the loading UI with the list.&lt;/p&gt;
&lt;p&gt;On this page, I stream multiple named regions at different timings, not only &lt;code&gt;recommendations&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hero image&lt;/li&gt;
&lt;li&gt;metric&lt;/li&gt;
&lt;li&gt;asset strip&lt;/li&gt;
&lt;li&gt;team activity&lt;/li&gt;
&lt;li&gt;streamed code block&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The asset strip also uses &lt;code&gt;&amp;lt;?marker&amp;gt;&lt;/code&gt;. The initial HTML has a marker.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;section class=&quot;panel asset-panel&quot;&amp;gt;
  &amp;lt;h2&amp;gt;Streamed public assets&amp;lt;/h2&amp;gt;
  &amp;lt;div class=&quot;asset-grid&quot;&amp;gt;
    &amp;lt;?marker name=&quot;asset-list&quot;&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the server streams chunks one by one whenever each asset link becomes ready.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;template for=&quot;asset-list&quot;&amp;gt;
  &amp;lt;!-- streamed asset link --&amp;gt;
  &amp;lt;?marker name=&quot;asset-list&quot;&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By leaving the same marker again inside the streamed content, the next asset link can continue to be appended in the same place.&lt;/p&gt;
&lt;p&gt;So HTML does not have to wait until everything is complete from top to bottom. &lt;strong&gt;Fragments can be streamed in later as soon as they are ready.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That is the really interesting part of DPU.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; has several subtle rules, including constraints related to parent elements.&lt;/p&gt;
&lt;p&gt;This demo is a sample for exploring the direction of the API, but if you want to use it in production someday, you should carefully check the applicable range of &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;, DOM movement during streaming, Trusted Types, sanitizers, and related details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-trying-a-hybrid-shell-style-architecture&quot;&gt;🌓 Trying a hybrid shell style architecture&lt;/h3&gt;
&lt;p&gt;Next, &lt;code&gt;/hybrid-shell&lt;/code&gt; demonstrates streaming HTML route updates inside a hybrid shell style architecture.&lt;/p&gt;
&lt;p&gt;This is not a “pure SPA where everything is rendered on the client”. It is closer to an architecture where &lt;strong&gt;the whole document is not reloaded, the URL changes through the History API, and only the route content inside the shell is updated&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The goal is&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Keep client-side state alive, while replacing only the route content with server-generated HTML.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, this page has a counter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div&amp;gt;
  Counter: &amp;lt;strong id=&quot;counter&quot;&amp;gt;0&amp;lt;/strong&amp;gt;
  &amp;lt;button id=&quot;increment&quot; class=&quot;primary&quot; type=&quot;button&quot;&amp;gt;Increment&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This counter is managed by client-side JavaScript.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;document.querySelector(&quot;#increment&quot;).addEventListener(&quot;click&quot;, () =&amp;gt; {
  counter.textContent = String(Number(counter.textContent) + 1);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So this is clearly a client-side responsibility.&lt;/p&gt;
&lt;p&gt;On the other hand, route content is fetched from the server as HTML.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const loadRoute = async (route, { push = false } = {}) =&amp;gt; {
  setActiveRoute(route);

  if (push) {
    const nextUrl =
      route === &quot;dashboard&quot;
        ? &quot;/hybrid-shell/dashboard&quot;
        : `/hybrid-shell/${route}`;
    window.history.pushState({ route }, &quot;&quot;, nextUrl);
  }

  const response = await fetch(`/partials/hybrid-shell/${route}`);
  view.replaceChildren();

  if (&quot;streamHTMLUnsafe&quot; in Element.prototype &amp;amp;&amp;amp; response.body) {
    await response.body
      .pipeThrough(new TextDecoderStream())
      .pipeTo(view.streamHTMLUnsafe());
    return;
  }

  const template = document.createElement(&quot;template&quot;);
  template.innerHTML = await response.text();
  view.replaceChildren(template.content.cloneNode(true));
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What this does is not “fetch JSON and render components on the client.” Instead, &lt;strong&gt;it streams HTML generated by the server directly into the view&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The counter state remains on the client.&lt;/p&gt;
&lt;p&gt;That means we can split responsibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interactive state such as the counter belongs to the client&lt;/li&gt;
&lt;li&gt;Server-generated route body can be streamed as HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This feels close to the thinking behind island architecture in frameworks like &lt;code&gt;Astro&lt;/code&gt; / &lt;code&gt;Fresh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of making the client do everything, we separate &lt;strong&gt;HTML that can be returned statically or from the server&lt;/strong&gt; from &lt;strong&gt;interactive client state&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Personally, I find this very interesting.&lt;/p&gt;
&lt;p&gt;At the very least, a shell with SPA-like navigation does not have to mean “everything is rendered by client-side JavaScript.” It may also expand into a hybrid shape that combines client state with streamed HTML.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;/hybrid-shell&lt;/code&gt; sample is &lt;strong&gt;not&lt;/strong&gt; a demo that replaces a range inside the shell using DPU’s &lt;code&gt;&amp;lt;?start&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Chrome team article also introduces the possibility of SPA-style page loads by combining &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt; and &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, in my local tests, I could not confirm that streaming &lt;code&gt;&amp;lt;template for=&quot;...&quot;&amp;gt;&lt;/code&gt; into &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt; in this shell architecture updates an existing DPU range.&lt;/p&gt;
&lt;p&gt;The SPA-style page load described in the official article seems to point toward an outline page with processing instructions, where the new page’s &lt;code&gt;&amp;lt;template for&amp;gt;&lt;/code&gt; elements are streamed toward the end of the HTML and slotted into those instructions.&lt;/p&gt;
&lt;p&gt;So in this &lt;code&gt;/hybrid-shell&lt;/code&gt; sample, I do not handle DPU range replacement. Instead, I use the HTML streaming insertion API to stream server-generated route partials directly into &lt;code&gt;#hybrid-shell-view&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-trying-static-streaming-html-apis&quot;&gt;🎁 Trying Static / Streaming HTML APIs&lt;/h3&gt;
&lt;p&gt;Finally, &lt;code&gt;/set-apis&lt;/code&gt; tries the new HTML insertion / streaming APIs separately from DPU’s out-of-order streaming.&lt;/p&gt;
&lt;p&gt;This page first checks whether the browser has the APIs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;support.innerHTML = `
  &amp;lt;ul class=&quot;list&quot;&amp;gt;
    &amp;lt;li&amp;gt;setHTMLUnsafe: ${&quot;setHTMLUnsafe&quot; in Element.prototype}&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;streamHTMLUnsafe: ${&quot;streamHTMLUnsafe&quot; in Element.prototype}&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For static insertion, if &lt;code&gt;setHTMLUnsafe()&lt;/code&gt; is available, the demo uses it. Otherwise, it falls back to &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;replaceChildren()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;if (&quot;setHTMLUnsafe&quot; in Element.prototype) {
  staticTarget.setHTMLUnsafe(markup);
  return;
}

const template = document.createElement(&quot;template&quot;);
template.innerHTML = markup;
staticTarget.replaceChildren(template.content.cloneNode(true));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For streaming insertion, it pipes the fetched HTML response directly into &lt;code&gt;streamHTMLUnsafe()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const response = await fetch(&quot;/partials/set-apis/stream&quot;);

streamTarget.replaceChildren();

if (&quot;streamHTMLUnsafe&quot; in Element.prototype &amp;amp;&amp;amp; response.body) {
  await response.body
    .pipeThrough(new TextDecoderStream())
    .pipeTo(streamTarget.streamHTMLUnsafe());
  return;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this works, we can stream chunks into an existing element as they arrive, &lt;strong&gt;instead of waiting until the entire HTML response has downloaded and inserting it all at once&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Traditionally, SPAs could benefit from HTML streaming for the initial document, but subsequent screen updates often became JSON fetch + client render.&lt;/p&gt;
&lt;p&gt;With APIs like this, SPAs may be able to benefit from HTML streaming even for later updates.&lt;/p&gt;
&lt;p&gt;That is the exciting part of DPU and the new HTML streaming APIs.&lt;/p&gt;
&lt;p&gt;The static insertion partial is returned from &lt;code&gt;/partials/set-apis/static&lt;/code&gt;, and the streaming insertion partial is returned from &lt;code&gt;/partials/set-apis/stream&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-summary&quot;&gt;🎯 Summary&lt;/h3&gt;
&lt;p&gt;In this article, I looked at Declarative Partial Updates introduced by the Chrome team.&lt;/p&gt;
&lt;p&gt;Declarative Partial Updates are, roughly&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;A mechanism where you declare part of your HTML as “this area will be replaced later”, and then update only that part with HTML that arrives later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, DPU does not replace &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; / &lt;code&gt;Svelte&lt;/code&gt; / &lt;code&gt;Next&lt;/code&gt; / &lt;code&gt;Remix&lt;/code&gt; / &lt;code&gt;Nuxt&lt;/code&gt; / &lt;code&gt;Astro&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Interactive UI, client-side state management, forms, modals, charts, drag and drop, and similar features still need JavaScript.&lt;/p&gt;
&lt;p&gt;But on the other hand, there may be more cases where we do not need to handle everything with client-side JavaScript.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTML that can be generated on the server should be generated on the server&lt;/li&gt;
&lt;li&gt;State that should be managed on the client should be managed on the client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the browser may come to understand &lt;strong&gt;not only how to display HTML, but also where streamed HTML should be inserted&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If this responsibility split progresses, frontend architecture may become more hybrid.&lt;/p&gt;
&lt;p&gt;Especially for SPAs, there may be another path beyond&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Fetch JSON and render on the client&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead, we may also be able to&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Fetch / stream HTML partials and update via browser-native behavior&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I do not see this as the end of SPAs. I see it as something that may expand what SPAs can do.&lt;/p&gt;
&lt;p&gt;This is still experimental, so it is not an API to use in production right away.&lt;/p&gt;
&lt;p&gt;But the direction where HTML changes from “a document loaded once at the beginning” into “a UI unit that can be streamed, replaced, and updated” feels very important for the future of frontend development.&lt;/p&gt;
&lt;p&gt;DPU is definitely something to keep an eye on. 😺&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;references-1&quot;&gt;References&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/blog/declarative-partial-updates?hl=en&quot;&gt;https://developer.chrome.com/blog/declarative-partial-updates?hl=en&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/WICG/declarative-partial-updates&quot;&gt;https://github.com/WICG/declarative-partial-updates&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/GoogleChromeLabs/template-for-polyfill&quot;&gt;https://github.com/GoogleChromeLabs/template-for-polyfill&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/GoogleChromeLabs/html-setters-polyfill&quot;&gt;https://github.com/GoogleChromeLabs/html-setters-polyfill&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/nyaomaru/declarative-partial-updates-sample&quot;&gt;https://github.com/nyaomaru/declarative-partial-updates-sample&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21951/trying-declarative-partial-updates-a-future-api-for-replacing-html-later</guid>
<pubDate>Sun, 05 Jul 2026 10:54:28 +0000</pubDate>
</item>
<item>
<title>Internet Identity Crisis: GA4 Is Blind, Is Your Web Ready for 1.3 Billion New &quot;AI Citizens&quot;?</title>
<link>https://coderlegion.com/21624/internet-identity-crisis-ga4-is-blind-is-your-web-ready-for-1-3-billion-new-ai-citizens</link>
<description>&lt;p&gt;In early June 2026, Matthew Prince – CEO and co-founder of Cloudflare – confirmed a historic milestone on X (Twitter): &lt;strong&gt;For the first time in internet history, automated bot traffic has officially surpassed human traffic.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;According to real-time data from Cloudflare Radar, bots now account for &lt;strong&gt;57.4% - 57.5%&lt;/strong&gt; of all global HTTP requests, pushing human activity down to just over 42%. This monumental crossover arrived &lt;strong&gt;18 months earlier&lt;/strong&gt; than Cloudflare’s original forecasts, driven entirely by the explosive growth of LLM Scrapers and Agentic AI.&lt;/p&gt;
&lt;p&gt;1.3 Billion &quot;AI Citizens&quot; with No Human Presence&lt;/p&gt;
&lt;p&gt;At major tech events like Microsoft Build, Microsoft has consistently highlighted a stark projection: &lt;strong&gt;The world is on track to reach 1.3 billion AI Agents working alongside humans by 2028.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This vision is being aggressively pushed by both Microsoft CEO Satya Nadella and Microsoft AI CEO Mustafa Suleyman, with declarations that fundamentally reshape the web:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Shift to the &quot;Open Agentic Web&quot;:&lt;/strong&gt; The internet will no longer be a place where humans click through individual apps. Instead, it will be an ecosystem where AI Agents interact directly with each other and web databases to execute tasks on behalf of users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identity for AI Agents:&lt;/strong&gt; Satya Nadella stated that since AI Agents can operate autonomously and consume actual budgets, they must be granted their own digital identities (IDs), access rights, and strict monitoring mechanisms—just like a real employee.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Modern Turing Test:&lt;/strong&gt; Mustafa Suleyman proposed a modern economic Turing test for agents: Can an AI agent legally plan and turn $100,000 into $1,000,000 in the real economy? He believes this milestone is closer than we think.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As web developers, we are transitioning rapidly from a &lt;strong&gt;Human-to-Machine&lt;/strong&gt; web to a &lt;strong&gt;Machine-to-Machine&lt;/strong&gt; infrastructure.&lt;/p&gt;
&lt;p&gt;When Traditional Analytics (GA4) Goes Completely Blind&lt;/p&gt;
&lt;p&gt;The old internet business model—relying on human views and clicks to generate ad revenue—is crumbling. When an AI Agent visits your site to extract data, it fires thousands of background HTTP requests in seconds, grabs the exact data it needs, and leaves without ever looking at a single ad banner.&lt;/p&gt;
&lt;p&gt;More critically, classic analytical tools like &lt;strong&gt;Google Analytics 4 (GA4)&lt;/strong&gt; are completely blind to these entities. GA4 cannot distinguish between a real human user with true transactional intent and the massive waves of &quot;ghost traffic&quot; constantly scraping your site to train foundation models.&lt;/p&gt;
&lt;p&gt;Coming from my own experience operating a web project optimized for bots, I realized a major gap: &lt;strong&gt;Webmasters currently have no visual tool to see how their website actually looks through the &quot;eyes&quot; of an AI Agent.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hands-on: Measuring Your Site's LLM Compatibility (Agent Readiness Score - ARS v1)&lt;/p&gt;
&lt;p&gt;To solve this exact pain point, I built and officially published a free extension on the Chrome Web Store (which also works on Chromium-based browsers like Edge): &lt;strong&gt;AgentShare Agent Readiness&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The tool allows you to instantly scan any domain to evaluate its AI transparency and bot friendliness based on the &lt;strong&gt;ARS v1&lt;/strong&gt; specification. It breaks down critical criteria such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The existence of next-gen AI discovery configurations like &lt;code&gt;llms.txt&lt;/code&gt; or &lt;code&gt;llm.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Crawler policies in &lt;code&gt;robots.txt&lt;/code&gt; regarding major AI bots (OpenAI, Google, Anthropic, etc.).&lt;/li&gt;
&lt;li&gt;Server overload risks and traffic identification gaps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just for fun, I used my own extension to scan our very own &lt;strong&gt;coderlegion.com&lt;/strong&gt;, and the result was &lt;strong&gt;22/100 points (Low readiness)&lt;/strong&gt; as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=12218395923685394264&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Of course, this is just a playful test since CoderLegion is fundamentally a space built for human-to-human developer connections. But for your SaaS projects, technical documentation sites, or e-commerce platforms—where being indexed properly determines whether an AI Agent will recommend your product to an end-user—a &lt;strong&gt;22 score&lt;/strong&gt; should be an immediate wake-up call.&lt;/p&gt;
&lt;p&gt;Let's Discuss&lt;/p&gt;
&lt;p&gt;The internet rules are changing daily. Cloudflare is dropping free bot-blocking tools, Microsoft is building the Agentic Web, but what are &lt;em&gt;you&lt;/em&gt; doing to prepare your tech stack? Are you opening your doors to LLM scrapers or shutting them down?&lt;/p&gt;
&lt;p&gt;I'd love for you to try out the extension, check your own website's &quot;Agent-readiness,&quot; and drop your harshest technical feedback or feature requests right in the comments below!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Try the Extension on Chrome Web Store:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://chromewebstore.google.com/detail/agentshare-agent-readines/nimndnhajfkicbnipbfdkmgencjejjed?authuser=0&amp;amp;hl=en&quot;&gt;AgentShare Agent Readiness&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21624/internet-identity-crisis-ga4-is-blind-is-your-web-ready-for-1-3-billion-new-ai-citizens</guid>
<pubDate>Tue, 30 Jun 2026 15:11:35 +0000</pubDate>
</item>
<item>
<title>Every Website You Visit Is Profiling You - Here's the Technical Reality (And How to Fight Back)</title>
<link>https://coderlegion.com/16148/every-website-you-visit-is-profiling-you-heres-the-technical-reality-and-how-to-fight-back</link>
<description>&lt;p&gt;Open Chrome DevTools on any popular website. Click the Network tab. Reload the page.&lt;br&gt;
Count the third-party requests.&lt;br&gt;
On a typical news site, you'll see 40–80 requests going out - not to the site you're visiting, but to trackers, ad networks, analytics platforms, and data brokers you never agreed to interact with. Google, Facebook, Amazon, and dozens of smaller surveillance companies are watching every click, scroll, and pause.&lt;br&gt;
Most users have no idea. Most developers do - and still underestimate the scale of it.&lt;/p&gt;
&lt;p&gt;What's Actually Happening Under the Hood&lt;br&gt;
When you load a page with embedded trackers, here's the flow:&lt;/p&gt;
&lt;p&gt;Your browser fetches the HTML from the server&lt;br&gt;
The page includes third-party  tags, tracking pixels (1×1 &lt;img src=&quot;src&quot; alt=&quot;image&quot;&gt; tags), and invisible iframes&lt;br&gt;
These fire requests to tracker domains - passing your IP, User-Agent, referrer, cookies, and often fingerprinting data (screen resolution, installed fonts, WebGL renderer, etc.)&lt;br&gt;
The tracker correlates this with your identity across thousands of other sites using the same embedded scripts&lt;br&gt;
&lt;em&gt;A profile is built - silently, continuously, without your consent&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The worst part? Many of these trackers bypass cookie consent banners entirely. Fingerprinting doesn't need cookies. It needs nothing from you except a browser that renders JavaScript.&lt;br&gt;
Here's a quick example of what a fingerprinting script might read:&lt;br&gt;
javascript// Trackers collect this without ever asking permission&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const fingerprint = {
  screen: `${screen.width}x${screen.height}`,
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  languages: navigator.languages,
  platform: navigator.platform,
  hardwareConcurrency: navigator.hardwareConcurrency,
  canvas: getCanvasFingerprint(), // unique per device
  webGL: getWebGLFingerprint(),   // unique per GPU
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This combination is unique enough to identify ~99.5% of browsers - no cookies required.&lt;/p&gt;
&lt;p&gt;The Scope of the Problem: Data Breaches&lt;br&gt;
Tracking isn't the only threat. Your data - email, passwords, phone numbers - lives in hundreds of databases you've signed up for over the years. When those databases are breached, your credentials end up on dark web forums.&lt;br&gt;
In 2024 alone:&lt;/p&gt;
&lt;p&gt;National Public Data leaked ~2.9 billion records including SSNs&lt;br&gt;
Ticketmaster exposed 560 million customer records&lt;br&gt;
Dell leaked data of 49 million customers&lt;/p&gt;
&lt;p&gt;If your email has been around for more than a few years, it's almost certainly in at least one breach database. Most people only find out when their accounts start getting compromised.&lt;/p&gt;
&lt;p&gt;Enter Digital Shield: A Technical Overview&lt;br&gt;
Digital Shield is a Chrome extension built to tackle both of these problems - real-time tracker blocking and proactive breach monitoring - in a single, lightweight tool.&lt;br&gt;
Here's what it actually does under the hood:&lt;br&gt;
️ Tracker &amp;amp; Ad Blocking&lt;br&gt;
Digital Shield intercepts outgoing network requests using Chrome's declarativeNetRequest API (the modern, privacy-preserving replacement for webRequest). It matches requests against a regularly updated blocklist of known tracker, ad, and malware domains - and drops them before they ever leave your browser.&lt;br&gt;
The result: pages load faster (fewer requests), less bandwidth is consumed, and trackers never receive your data in the first place.&lt;br&gt;
️ &lt;strong&gt;SpyGraph - Visual Tracker Intelligence&lt;/strong&gt;&lt;br&gt;
This is the feature developers will find most interesting. SpyGraph gives you a real-time visualization of which trackers are present on any page you visit - categorized by type (ad network, analytics, social widget, fingerprinting, etc.) and by company.&lt;br&gt;
It's essentially a live view of what Chrome DevTools Network tab shows, presented in a way that's immediately readable. Great for auditing sites you're building, not just sites you're browsing.&lt;br&gt;
 &lt;strong&gt;AI-Powered Privacy Policy Summarizer&lt;/strong&gt;&lt;br&gt;
Privacy policies average 4,000–10,000 words and are deliberately written to obscure what data is actually collected. Digital Shield uses AI to summarize them into plain English - what data is collected, how it's used, and what your rights are - in seconds.&lt;br&gt;
Useful for developers evaluating third-party SDKs or APIs for their own projects: you can quickly understand the data implications before integrating.&lt;br&gt;
 &lt;strong&gt;Dark Web Breach Monitoring&lt;/strong&gt;&lt;br&gt;
Enter your email address and Digital Shield continuously monitors breach databases. If your credentials appear in a newly exposed dataset, you get an immediate alert so you can rotate passwords before attackers use them.&lt;br&gt;
Unlike one-off checks on sites like HaveIBeenPwned, this is ongoing monitoring with instant notifications.&lt;br&gt;
 &lt;strong&gt;Parental Controls (Unique Feature)&lt;/strong&gt;&lt;br&gt;
This is where Digital Shield differentiates from most tracker blockers. It includes:&lt;/p&gt;
&lt;p&gt;Content filtering for adult, gambling, and violent content&lt;br&gt;
Bedtime Scheduler - automatically locks browsing during set hours&lt;br&gt;
Instant Pause - one-click to freeze all browsing&lt;br&gt;
Kids Safe Browsing Mode - restricts to a whitelist of safe sites&lt;/p&gt;
&lt;p&gt;For developers who are also parents, this is a practical tool for protecting kids on shared devices without needing a separate parental control app.&lt;br&gt;
 &lt;strong&gt;Secure Password Generator&lt;/strong&gt;&lt;br&gt;
Built-in cryptographically secure password generation - useful for quickly generating strong credentials without reaching for a separate tool.&lt;/p&gt;
&lt;p&gt;Performance Impact&lt;br&gt;
A common concern with extensions: do they slow down browsing?&lt;br&gt;
Because Digital Shield uses declarativeNetRequest rather than the older webRequest API, blocking happens at the browser engine level - not in the extension's JavaScript runtime. This means:&lt;/p&gt;
&lt;p&gt;No added latency from extension processing&lt;br&gt;
Rules are compiled and matched natively by Chrome&lt;br&gt;
In practice, pages often load faster because 30–60% fewer network requests are made&lt;/p&gt;
&lt;p&gt;Why This Matters for Developers Specifically&lt;br&gt;
As developers, we're in an interesting position:&lt;/p&gt;
&lt;p&gt;We build the web - many of us embed Google Analytics, Facebook Pixel, or third-party SDKs in our projects. Understanding what those tools actually do to users is part of building responsibly.&lt;br&gt;
We're high-value targets - developer accounts (GitHub, npm, AWS, cloud providers) are extremely valuable to attackers. A single compromised credential can expose entire codebases or production infrastructure.&lt;br&gt;
We test on real browsers - SpyGraph and the privacy policy summarizer are genuinely useful QA and due diligence tools, not just consumer features.&lt;br&gt;
We have families - the parental control features are for the same reason anyone needs them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Install &amp;amp; Try It&lt;/strong&gt;&lt;br&gt;
Digital Shield is free to install with premium features available.&lt;br&gt;
Chrome Web Store: &lt;a rel=&quot;nofollow&quot; href=&quot;https://chromewebstore.google.com/detail/pkonihncnkmbejhhjadaognganhinnhc?utm_source=item-share-cb&quot;&gt;Install Digital Shield&lt;/a&gt;&lt;br&gt;
After installing, try this:&lt;/p&gt;
&lt;p&gt;Open SpyGraph on a major news site - the number of trackers will surprise you&lt;br&gt;
Run a breach check on your main email address&lt;br&gt;
Open DevTools Network tab before and after - compare the request count&lt;/p&gt;
&lt;p&gt;The difference is immediately visible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Bigger Picture&lt;/strong&gt;&lt;br&gt;
The web's surveillance economy is a structural problem. Ad-funded business models create financial incentives to collect as much data as possible. Users - even technically sophisticated ones - are largely powerless against fingerprinting at the browser level.&lt;br&gt;
Extensions like Digital Shield sit at the only practical intervention point: the browser, where requests can be intercepted before they leave your machine.&lt;br&gt;
This isn't a perfect solution. VPNs, private DNS, and browser hardening all have roles to play. But for most people - including developers who want a single tool that handles the most common threats - it's a meaningful and immediate improvement.&lt;br&gt;
Privacy should be the default, not a premium feature. Tools that move the web in that direction are worth knowing about.&lt;/p&gt;
&lt;p&gt;Have questions about how the tracker blocking works technically, or want to discuss the fingerprinting threat model? Drop a comment below.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/16148/every-website-you-visit-is-profiling-you-heres-the-technical-reality-and-how-to-fight-back</guid>
<pubDate>Wed, 29 Apr 2026 06:35:25 +0000</pubDate>
</item>
<item>
<title>Chrome 144 Introduces the &lt;geolocation&gt; Element: Declarative Location Access for Modern Web Apps</title>
<link>https://coderlegion.com/14655/chrome-144-introduces-the-geolocation-element-declarative-location-access-modern-apps</link>
<description>
&lt;p&gt;&lt;img src=&quot;https://blog.ratnesh-maurya.com/images/blog/chrome-144-introduces-the-geolocation-element-declarative-location-access-for-modern-web-apps.png&quot; alt=&quot;Chrome 144 Introduces the &amp;lt;geolocation&amp;gt; Element: Declarative Location Access for Modern Web Apps&quot;&gt;&lt;/p&gt;&lt;h1&gt;Chrome 144 Introduces the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; Element: Declarative Location Access for Modern Web Apps&lt;/h1&gt;
&lt;p&gt;Chrome 144 introduces a new declarative &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; HTML element that changes how web applications request location access. Instead of calling &lt;code&gt;navigator.geolocation.getCurrentPosition()&lt;/code&gt; imperatively from JavaScript, developers can now place a browser-controlled element directly in the DOM.&lt;/p&gt;
&lt;p&gt;This post is for frontend engineers, platform engineers, and privacy-conscious developers who want to understand how this new model works and whether they should migrate.&lt;/p&gt;
&lt;p&gt;By the end of this article, you'll understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is&lt;/li&gt;
&lt;li&gt;How it works internally&lt;/li&gt;
&lt;li&gt;How it compares to the traditional Geolocation API&lt;/li&gt;
&lt;li&gt;How to implement it with proper fallback support&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Why Chrome Introduced &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Historically, location access was triggered via JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-js&quot;&gt;navigator.&lt;span class=&quot;hljs-property&quot;&gt;geolocation&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getCurrentPosition&lt;/span&gt;(success, error);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This caused several problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Permission prompts appearing on page load&lt;/li&gt;
&lt;li&gt;Users denying requests due to poor timing&lt;/li&gt;
&lt;li&gt;Quiet permission blocking by browsers&lt;/li&gt;
&lt;li&gt;Complicated permission state handling in code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element solves this by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requiring explicit user interaction&lt;/li&gt;
&lt;li&gt;Providing a visible, browser-controlled UI&lt;/li&gt;
&lt;li&gt;Reducing boilerplate permission code&lt;/li&gt;
&lt;li&gt;Improving recovery from previously denied states&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chrome origin trials showed measurable improvements in successful permission grants and recovery rates.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What Is the &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; Element?&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is part of the WICG &quot;Permission Elements&quot; proposal. It acts as a declarative wrapper around the existing Geolocation API.&lt;/p&gt;
&lt;p&gt;It renders as a browser-controlled button such as:&lt;/p&gt;
&lt;p&gt;When clicked:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The browser shows the location permission dialog.&lt;/li&gt;
&lt;li&gt;If granted, it dispatches a &lt;code&gt;location&lt;/code&gt; event.&lt;/li&gt;
&lt;li&gt;The element exposes either:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;position&lt;/code&gt; (success)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;error&lt;/code&gt; (failure)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;attributes-explained&quot;&gt;Attributes Explained&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;autolocate&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Automatically attempts to retrieve location when inserted into the DOM &amp;mdash; &lt;strong&gt;only if permission was already granted&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;autolocate&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It does not trigger surprise permission prompts.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;&lt;code&gt;watch&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Continuously tracks position updates, similar to &lt;code&gt;watchPosition()&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;watch&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without &lt;code&gt;watch&lt;/code&gt;, it behaves like &lt;code&gt;getCurrentPosition()&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;&lt;code&gt;accuracymode&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Controls precision level.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;accuracymode&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;precise&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Possible values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;approximate&quot;&lt;/code&gt; (default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;precise&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When set to &lt;code&gt;&quot;precise&quot;&lt;/code&gt;, the browser may:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change icon (crosshair instead of pin)&lt;/li&gt;
&lt;li&gt;Update label text&lt;/li&gt;
&lt;li&gt;Request higher accuracy internally&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;basic-implementation&quot;&gt;Basic Implementation&lt;/h2&gt;
&lt;p&gt;Minimal example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;onlocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;handleLocation(event)&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;javascript&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;handleLocation&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;event&lt;/span&gt;) {
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (event.&lt;span class=&quot;hljs-property&quot;&gt;target&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;position&lt;/span&gt;) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; { latitude, longitude } = event.&lt;span class=&quot;hljs-property&quot;&gt;target&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;position&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;coords&lt;/span&gt;;
    &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Location:&quot;&lt;/span&gt;, latitude, longitude);
  } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (event.&lt;span class=&quot;hljs-property&quot;&gt;target&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;error&lt;/span&gt;) {
    &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;error&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error:&quot;&lt;/span&gt;, event.&lt;span class=&quot;hljs-property&quot;&gt;target&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;error&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;message&lt;/span&gt;);
  }
}
&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No permission logic required.&lt;/p&gt;
&lt;p&gt;The browser handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Permission prompts&lt;/li&gt;
&lt;li&gt;Recovery dialogs&lt;/li&gt;
&lt;li&gt;Error states&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;adding-progressive-enhancement-fallback&quot;&gt;Adding Progressive Enhancement (Fallback)&lt;/h2&gt;
&lt;p&gt;You must support non-Chrome browsers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;geo&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;fallback-btn&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    Use my location
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;geolocation&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;javascript&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-string&quot;&gt;'HTMLGeolocationElement'&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;) {
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; geo = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;'geo'&lt;/span&gt;);
  geo.&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;'location'&lt;/span&gt;, &lt;span class=&quot;hljs-function&quot;&gt;() =&amp;gt;&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (geo.&lt;span class=&quot;hljs-property&quot;&gt;position&lt;/span&gt;) {
      &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;log&lt;/span&gt;(geo.&lt;span class=&quot;hljs-property&quot;&gt;position&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;coords&lt;/span&gt;);
    }
  });
} &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
  &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;'fallback-btn'&lt;/span&gt;)
    .&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;'click'&lt;/span&gt;, &lt;span class=&quot;hljs-function&quot;&gt;() =&amp;gt;&lt;/span&gt; {
      navigator.&lt;span class=&quot;hljs-property&quot;&gt;geolocation&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getCurrentPosition&lt;/span&gt;(&lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;pos&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
        &lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;log&lt;/span&gt;(pos.&lt;span class=&quot;hljs-property&quot;&gt;coords&lt;/span&gt;);
      });
    });
}
&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures compatibility across browsers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;browser-ui-behavior&quot;&gt;Browser UI Behavior&lt;/h2&gt;
&lt;p&gt;When clicked, Chrome displays the standard location permission dialog:&lt;/p&gt;
&lt;p&gt;If previously denied, Chrome shows a recovery prompt:&lt;/p&gt;
&lt;p&gt;This makes permission recovery significantly easier compared to manual browser settings navigation.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;styling-restrictions-security-guardrails&quot;&gt;Styling Restrictions (Security Guardrails)&lt;/h2&gt;
&lt;p&gt;To prevent abuse or clickjacking, Chrome enforces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimum size&lt;/li&gt;
&lt;li&gt;Opacity must remain &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;No negative margins&lt;/li&gt;
&lt;li&gt;No deceptive transforms&lt;/li&gt;
&lt;li&gt;Enforced contrast ratio&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can style it, but you cannot make it invisible or misleading.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot;&gt;geolocation {
  &lt;span class=&quot;hljs-attribute&quot;&gt;border-radius&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;8px&lt;/span&gt;;
  &lt;span class=&quot;hljs-attribute&quot;&gt;padding&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;12px&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But you cannot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hide it&lt;/li&gt;
&lt;li&gt;Make it 1px wide&lt;/li&gt;
&lt;li&gt;Overlay fake UI elements&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;&lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; vs &lt;code&gt;navigator.geolocation&lt;/code&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional API&lt;/th&gt;
&lt;th&gt;&lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Permission Trigger&lt;/td&gt;
&lt;td&gt;Script-based&lt;/td&gt;
&lt;td&gt;User-click only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate Code&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery Flow&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling Control&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;Guard-railed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy Model&lt;/td&gt;
&lt;td&gt;Developer-controlled&lt;/td&gt;
&lt;td&gt;Browser-mediated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;when-should-you-use-it&quot;&gt;When Should You Use It?&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need a simple &quot;Use my location&quot; feature&lt;/li&gt;
&lt;li&gt;You want better permission recovery&lt;/li&gt;
&lt;li&gt;You want reduced code complexity&lt;/li&gt;
&lt;li&gt;You care about user trust and privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stick to the traditional API if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You need fine-grained timing control&lt;/li&gt;
&lt;li&gt;You require silent background tracking&lt;/li&gt;
&lt;li&gt;You are building real-time geo-heavy apps (ride-sharing, logistics dashboards)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;production-checklist&quot;&gt;Production Checklist&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Feature-detect &lt;code&gt;HTMLGeolocationElement&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Provide a JS fallback&lt;/li&gt;
&lt;li&gt;Avoid using &lt;code&gt;autolocate&lt;/code&gt; unnecessarily&lt;/li&gt;
&lt;li&gt;Test denied &amp;rarr; recovery flows&lt;/li&gt;
&lt;li&gt;Validate UX on mobile devices&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;geolocation&amp;gt;&lt;/code&gt; element is a significant shift toward declarative permission handling on the web. It reduces developer complexity while improving privacy, trust, and user experience.&lt;/p&gt;
&lt;p&gt;For simple location-based features, it should become the default pattern in Chrome-supported environments.&lt;/p&gt;
&lt;p&gt;However, since it's currently Chrome-specific and incubating, production systems must still include fallback support.&lt;/p&gt;
&lt;p&gt;If you're building modern web applications and care about privacy-first UX, this is worth adopting early &amp;mdash; but do it responsibly with progressive enhancement.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/14655/chrome-144-introduces-the-geolocation-element-declarative-location-access-modern-apps</guid>
<pubDate>Mon, 13 Apr 2026 10:42:28 +0000</pubDate>
</item>
<item>
<title>Top JSON Formatting &amp; Validation Tools (Fast + Developer-Friendly)</title>
<link>https://coderlegion.com/3958/top-json-formatting-validation-tools-fast-developer-friendly</link>
<description>&lt;p&gt;Here are some &lt;strong&gt;fast, reliable tools&lt;/strong&gt; for &lt;strong&gt;JSON formatting and validation&lt;/strong&gt; — perfect for developers working with APIs, logs, or large JSON payloads.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;1-jsonformatter-org&quot;&gt;1. &lt;a rel=&quot;nofollow&quot; href=&quot;https://jsonformatter.org&quot;&gt;&lt;strong&gt;jsonformatter.org&lt;/strong&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;✅ Format, validate, minify, and view JSON&lt;/li&gt;
&lt;li&gt;Has tree view and raw text view&lt;/li&gt;
&lt;li&gt;Supports upload + clipboard copy&lt;/li&gt;
&lt;li&gt;Also supports XML, YAML, JWT, CSV&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Fastest and most comprehensive online tool.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-2-jsoneditoronline-org&quot;&gt;⚡ 2. &lt;a rel=&quot;nofollow&quot; href=&quot;https://jsoneditoronline.org&quot;&gt;&lt;strong&gt;jsoneditoronline.org&lt;/strong&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Visual + code editor side-by-side&lt;/li&gt;
&lt;li&gt;Detects and highlights syntax issues live&lt;/li&gt;
&lt;li&gt;Offers &quot;Transform&quot;, &quot;Sort&quot;, and &quot;Filter&quot; tools&lt;/li&gt;
&lt;li&gt;Supports collaboration with shareable links&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Great for working with deeply nested JSON visually.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;3-vs-code-built-in-or-plugin-&quot;&gt;3. &lt;strong&gt;VS Code (Built-in or Plugin)&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;✨ Use built-in formatting: Right click → Format Document&lt;/li&gt;
&lt;li&gt;Extensions:&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prettier&lt;/strong&gt; (formatting)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON Tools&lt;/strong&gt; (validation, sorting, filtering)&lt;/li&gt;
&lt;li&gt;Works offline and with huge files&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;Ideal if you're already coding in VS Code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;4-quicktype-io&quot;&gt;4. &lt;a rel=&quot;nofollow&quot; href=&quot;https://quicktype.io&quot;&gt;&lt;strong&gt;quicktype.io&lt;/strong&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;⚙️ Convert JSON → TypeScript, Python, Java, etc.&lt;/li&gt;
&lt;li&gt;Also formats + validates input&lt;/li&gt;
&lt;li&gt;Instant TypeScript interfaces for Angular/NestJS devs&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Best for generating types/interfaces from real API responses.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;5-cli-tools-for-local-work-&quot;&gt;5. &lt;strong&gt;CLI Tools (For local work)&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;If you want a &lt;strong&gt;fast terminal-based&lt;/strong&gt; option:&lt;/p&gt;
&lt;h5 id=&quot;-jq-lightweight-and-powerful-&quot;&gt;✅ &lt;code&gt;jq&lt;/code&gt; (lightweight and powerful)&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;jq '.' data.json  # Format
jq type data.json # Validate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install jq   # macOS
sudo apt install jq   # Ubuntu/Debian
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;Fastest tool for shell scripting and JSON pipelines.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;summary-table&quot;&gt;Summary Table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Tool                                                 &lt;/th&gt;&lt;th&gt;Format &lt;/th&gt;&lt;th&gt;Validate &lt;/th&gt;&lt;th&gt;Extras&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://jsonformatter.org&quot;&gt;jsonformatter.org&lt;/a&gt;       &lt;/td&gt;&lt;td&gt;✅      &lt;/td&gt;&lt;td&gt;✅        &lt;/td&gt;&lt;td&gt;Tree view, minify, export&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://jsoneditoronline.org&quot;&gt;jsoneditoronline.org&lt;/a&gt; &lt;/td&gt;&lt;td&gt;✅      &lt;/td&gt;&lt;td&gt;✅        &lt;/td&gt;&lt;td&gt;Visual editing, sharing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;VS Code                                              &lt;/td&gt;&lt;td&gt;✅      &lt;/td&gt;&lt;td&gt;✅        &lt;/td&gt;&lt;td&gt;Extensions, huge JSON&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://quicktype.io&quot;&gt;quicktype.io&lt;/a&gt;                 &lt;/td&gt;&lt;td&gt;✅      &lt;/td&gt;&lt;td&gt;✅        &lt;/td&gt;&lt;td&gt;Generate TS/Java classes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;jq&lt;/code&gt; (CLI)                                           &lt;/td&gt;&lt;td&gt;✅      &lt;/td&gt;&lt;td&gt;✅        &lt;/td&gt;&lt;td&gt;Scriptable, blazing fast&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
</description>
<category>Full-stack Dev</category>
<guid isPermaLink="true">https://coderlegion.com/3958/top-json-formatting-validation-tools-fast-developer-friendly</guid>
<pubDate>Mon, 14 Jul 2025 07:43:29 +0000</pubDate>
</item>
<item>
<title>Mastering Browser Developer Tools: A Beginner’s Guide</title>
<link>https://coderlegion.com/1416/mastering-browser-developer-tools-a-beginners-guide</link>
<description>&lt;p&gt;Table of contents&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Introduction&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding the Web browser as a developer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Key Components of Chrome Developer Tools&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Step-by-Step Guide to Using Developer Tools&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Common Challenges and Solutions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advanced Techniques and Additional Considerations&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conclusion&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Have you ever wondered how developers make websites run smoothly or how they troubleshoot issues on web pages? If you're starting out in web development, understanding how to interact with the tools available in your browser is essential. Browsers are not just for viewing websites --- they are also powerful tools for creating, testing, and debugging web pages. In this guide, we'll explore the basics of browser development tools, why browsers are referred to as clients in web development, and how to leverage these tools to enhance your skills.&lt;/p&gt;
&lt;p&gt;A browser is a software application used to access and view websites on the internet. Popular browsers include Chrome, Firefox, Safari, and Edge. Browsers act as clients in web development, meaning they are the &quot;consumer&quot; of web content, receiving data from servers (which host websites) and rendering that content for users.&lt;/p&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.w3.org/&quot;&gt;World Wide Web Consortium&lt;/a&gt; (W3C) is an international community that develops web standards to ensure the internet is accessible and consistent. W3C standards guide developers in creating websites that work across different devices and browsers.&lt;/p&gt;
&lt;p&gt;Browsers come equipped with developer tools to assist developers in inspecting, debugging, and improving websites. These tools are a must-have for anyone starting out in web development.&lt;/p&gt;
&lt;h3 id=&quot;key-components&quot;&gt;Key Components&lt;/h3&gt;
&lt;p&gt;The developer tools (often accessed by pressing F12) in browsers, particularly in Google Chrome, offer a range of tabs that each focus on a specific area of web development. Let's break down the key components of Chrome Developer Tools:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Elements:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lets you view the raw HTML and CSS of a webpage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can inspect and edit the HTML structure of a page and immediately see changes.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/elements&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Console:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Offers access to JavaScript functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developers can view error messages or test JavaScript code directly in the browser.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/console&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Sources:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Navigate the files and folders that make up the webpage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also view and edit JavaScript files, inspect scripts, and debug them.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/sources&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Network:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Monitor network activity such as page load times, API requests, and responses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Helps developers optimize website performance and detect potential issues.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/network/overview&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Performance:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Acts like a dashboard for monitoring real-time performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Helps developers track and optimize resource usage (like CPU or memory) during page loads.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/performance/overview&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Memory:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Shows memory usage during web page interaction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Helps developers identify memory leaks and improve efficiency.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/memory&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Application:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Provides advanced tools for debugging a web page, including inspecting local storage, session storage, and cookies.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/application&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Privacy and Security:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Debug third-party cookies and HTTP security.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allows checking the security of a webpage, like SSL/TLS certificates and encryption status.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/security&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Lighthouse:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Provides tools to test and analyze website performance, security, and accessibility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Offers actionable insights and suggestions for improvements.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Recorder:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Allows developers to record user interactions on a webpage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Useful for research purposes and performance testing.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools/recorder/overview&quot;&gt;Read more&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-by-step-guide&quot;&gt;Step-by-Step Guide&lt;/h3&gt;
&lt;p&gt;To start using the developer tools in Chrome, follow these simple steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open Google Chrome.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Press F12 on your keyboard or right-click on a webpage and choose &quot;Inspect&quot; to open the Developer Tools.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explore different tabs, starting with Elements to get familiar with the HTML structure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the Console to experiment with JavaScript code and see the immediate results.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check Network for any loading issues or delays in resources.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test the performance of your page using the Performance tab, and make adjustments accordingly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Memory tab, monitor how the page behaves in terms of memory usage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check for security issues under the Privacy and Security tab.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=17009352706187946805&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;common-challenges-and-solutions&quot;&gt;Common Challenges and Solutions&lt;/h3&gt;
&lt;p&gt;As a beginner, you might face some challenges when using developer tools. Here are a few common ones and solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Challenge: Not understanding the raw HTML and CSS in the Elements tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solution: Take time to learn basic HTML and CSS. Experiment by making changes in the Elements tab to see the immediate effects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Challenge: Getting overwhelmed by the vast amount of data in the Console or Network tabs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solution: Filter out unnecessary information to focus on errors or specific issues you're troubleshooting.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Challenge: Difficulty interpreting performance data in the Performance tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solution: Use online resources and tutorials to better understand how to read performance reports, and practice optimizing real pages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;advanced-techniques&quot;&gt;Advanced Techniques&lt;/h3&gt;
&lt;p&gt;As you gain more experience, you'll want to explore deeper features in the browser developer tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dive into the Sources tab to debug and set breakpoints in your JavaScript code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Lighthouse to run audits for performance, accessibility, and SEO to ensure your website meets best practices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Experiment with advanced debugging tools in the Application tab for complex web features like Progressive Web Apps (PWAs) and service workers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For further learning, you can check out additional resources, like the official Chrome Developer Tools &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/devtools&quot;&gt;documentation&lt;/a&gt; or&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.w3.org/standards/&quot;&gt;  W3C web standards&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Conclusion:&lt;/p&gt;
&lt;p&gt;Understanding browser developer tools is an essential skill for web developers, especially beginners. With tools like Elements, Console, and Network, you can efficiently debug and improve your web pages. By using the tips and techniques provided in this guide, you'll be able to start experimenting with real-world development scenarios. Start using these tools today and take your web development skills to the next level!&lt;/p&gt;
&lt;p&gt;Have you tried using developer tools? What's your favorite tab? Share your thoughts in the comments below!&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/1416/mastering-browser-developer-tools-a-beginners-guide</guid>
<pubDate>Sun, 09 Mar 2025 22:07:16 +0000</pubDate>
</item>
</channel>
</rss>