Skip to content
Chrome 153 → 154

Chrome 154: what changed for fingerprinting and automation

Chrome 154 changed what a web page can observe in 16 places and nothing in the network handshake. The biggest change is invisible in a feature list: V8 15.4 reorders the global object, so every property-order fingerprint moves. Two of Chrome 153's changes were reverted.

Pim
Pim · Clearcote Research
Stable release
September 22, 2026
Measured on (Linux x64)
153.0.8010.52 → 154.0.8037.57
Source read at
153.0.8010.55 → 154.0.8037.58
V8
15.3.76.13 → 15.4.80.11

Key takeaways

  • V8 15.4 installs Float16Array, SuppressedError, the disposable stacks, Math.f16round and friends in their specified positions instead of at the end. Float16Array moves from position 893 to 41 in window's property list, so any hash of that order changes, in windows and workers alike.
  • New behaviour a page can test in one line: Promise.try(() => p) === p is true from 154, and Iterator.prototype.includes exists.
  • Two 153 changes were reverted: XML parsing is back on libxml2 by default (the error text is the Chrome 152 text again), and scroll-marker-group: after tabs is accepted again. Both make 153 the odd one out among its neighbours.
  • Time zone data moved to tzdata 2026c: Morocco stays on +00 from October 2026, and British Columbia and Alberta stay on daylight time from November. A browser claiming 154 on those exits must report the new offsets.
  • A server still cannot tell 153 from 154 by TLS, HTTP/2 or header order, only by the version strings and the new GREASE brand, Not A(Brand version 99 with Chromium listed first.

Every check, both versions, and your browser

23 one-line checks across 16 changes. The strip shows where they are; the table shows what each returns on Chrome 153 and Chrome 154. Run them in this browser to see which version its engine matches.

Chrome 153 → Chrome 154 · 23 checks

Run the checks to see which Chrome version this browser's engine matches.

Where the changes are. Select a surface to filter the rows.

CheckChrome 153Chrome 154This browser
Client Hints
New GREASE brand and brand order in User-Agent Client Hintsnavigator.userAgentData.brands.map((b) => `${b.brand};v=${b.version}`).join(', ')"Google Chrome;v=153, Not_A Brand;v=8, Chromium;v=153""Chromium;v=154, Google Chrome;v=154, Not A(Brand;v=99"–
JavaScript and DOM
V8 15.4 reorders the global object: Float16Array, SuppressedError and friends move to their spec positionsObject.getOwnPropertyNames(window)[Object.getOwnPropertyNames(window).indexOf('Float64Array') + 1]"DataView""Float16Array"–
V8 15.4 reorders the global object: Float16Array, SuppressedError and friends move to their spec positionsObject.getOwnPropertyNames(window)[Object.getOwnPropertyNames(window).indexOf('URIError') + 1]"globalThis""SuppressedError"–
V8 15.4 reorders the global object: Float16Array, SuppressedError and friends move to their spec positionsObject.getOwnPropertyNames(Math).slice(-2).join(',')"f16round,sumPrecise""SQRT1_2,SQRT2"–
V8 15.4 reorders the global object: Float16Array, SuppressedError and friends move to their spec positionsObject.getOwnPropertyNames(DataView.prototype).indexOf('getFloat16') < Object.getOwnPropertyNames(DataView.prototype).indexOf('getFloat32')falsetrue–
V8 15.4 reorders the global object: Float16Array, SuppressedError and friends move to their spec positionsObject.getOwnPropertyNames(Intl.Locale.prototype).indexOf('variants') < Object.getOwnPropertyNames(Intl.Locale.prototype).indexOf('baseName')falsetrue–
Promise.try returns the promise it was given((p) => Promise.try(() => p) === p)(Promise.resolve(1))falsetrue–
Iterator.prototype.includestypeof Iterator.prototype.includes"undefined""function"–
window.requestResize (responsive iframes)typeof window.requestResize"undefined""function"–
FontFace.prototype.width'width' in FontFace.prototypefalsetrue–
CSS Typed OM in dedicated workersnew Promise((r) => { const w = new Worker(URL.createObjectURL(new Blob(['postMessage(typeof CSSStyleValue)']))); w.onmessage = (e) => r(e.data); })"undefined""function"–
SVGTextPathElement gains the TEXTPATH_SIDETYPE constants'TEXTPATH_SIDETYPE_LEFT' in SVGTextPathElementfalsetrue–
Property order moved: Document.prototype.activeViewTransitionObject.getOwnPropertyNames(Document.prototype).indexOf('activeViewTransition') < Object.getOwnPropertyNames(Document.prototype).indexOf('fonts')falsetrue–
document.requestStorageAccessFor and FencedFrameConfig.setSharedStorageContext removed'requestStorageAccessFor' in documenttruefalse–
document.requestStorageAccessFor and FencedFrameConfig.setSharedStorageContext removed'setSharedStorageContext' in FencedFrameConfig.prototypetruefalse–
Parsing and rendering
XML parsing back on libxml2: the Chrome 153 error text is gone againnew DOMParser().parseFromString('<a><b></a>', 'application/xml').querySelector('parsererror div').textContent.trim()"error on line 1 at column 10: Unexpected closing tag: a != b""error on line 1 at column 11: Opening and ending tag mismatch: b line 1 and a"–
XSLT output carries a deprecation banner/This site uses XSLT/.test(new XMLSerializer().serializeToString(((p) => (p.importStylesheet(new DOMParser().parseFromString('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><html><body><p><xsl:value-of select="r/v"/></p></body></html></xsl:template></xsl:stylesheet>', 'application/xml')), p.transformToDocument(new DOMParser().parseFromString('<r><v>1</v></r>', 'application/xml'))))(new XSLTProcessor())))falsetrue–
CSS
New CSS property: frame-sizingCSS.supports('frame-sizing', 'content-height')falsetrue–
scroll-marker-group: the tabs and links modes are accepted againCSS.supports('scroll-marker-group', 'after tabs')falsetrue–
Media and GPU
New WGSL language feature: swizzle_assignmentnavigator.gpu.wgslLanguageFeatures.has('swizzle_assignment')falsetrue–
Intl and time zones
Time zone data updated to tzdata 2026cnew Intl.DateTimeFormat('en-US', { timeZone: 'Africa/Casablanca', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 9, 1)).find((p) => p.type === 'timeZoneName').value"GMT+01:00""GMT+00:00"–
Time zone data updated to tzdata 2026cnew Intl.DateTimeFormat('en-US', { timeZone: 'America/Vancouver', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 10, 15)).find((p) => p.type === 'timeZoneName').value"GMT-08:00""GMT-07:00"–
Time zone data updated to tzdata 2026cnew Intl.DateTimeFormat('en-US', { timeZone: 'America/Edmonton', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 10, 15)).find((p) => p.type === 'timeZoneName').value"GMT-07:00""GMT-06:00"–

A tinted cell differs from the version before it. Values are as the DevTools console prints them. Checks that need a debugger attached are not run live.

TLS, HTTP/2 and request headers in Chrome 154

TLS ClientHello
Identical on both versions: JA4 t13d1517h2_8daaf6152771_cb7bf5808d99, the same 19 extensions, the same key-share groups (X25519MLKEM768 first) and signature algorithms. Measured three times against two independent TLS echo services.
HTTP/2
Identical: Akamai fingerprint 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p, priority u=0, i, pseudo-header order m,a,s,p.
Request headers
Identical names, order and values on all sixteen request types and after an Accept-CH round, except the values that carry the version: User-Agent, Sec-CH-UA, Sec-CH-UA-Full-Version and Sec-CH-UA-Full-Version-List.

Chrome 154 User-Agent strings and Client Hints

PlatformUser-Agent
WindowsMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
macOSMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
LinuxMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
AndroidMozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Mobile Safari/537.36
Headless (Linux)Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/154.0.0.0 Safari/537.36

The Linux and headless strings were measured, and the Windows string was confirmed on a Windows Chrome 154. The others follow Chromium's reduced User-Agent format (user_agent_utils.cc): only the major version is real, the rest is frozen, and the platform part is fixed per operating system.

Sec-CH-UA (the low-entropy brand list sent with every request):

"Chromium";v="154", "Google Chrome";v="154", "Not A(Brand";v="99"

User-Agent and Client Hints

high impactMeasured on both builds

New GREASE brand and brand order in User-Agent Client Hints

The fake GREASE brand and the order of the brand list are computed from the major version. On 154 the brand is Not A(Brand version 99, and Chromium is listed first. Sent on every request in Sec-CH-UA, and returned by navigator.userAgentData.brands in windows and workers.

navigator.userAgentData.brands.map((b) => `${b.brand};v=${b.version}`).join(', ')
Chrome 153
"Google Chrome;v=153, Not_A Brand;v=8, Chromium;v=153"
Chrome 154
"Chromium;v=154, Google Chrome;v=154, Not A(Brand;v=99"

Why it matters: A version number changed by hand, with the previous brand list left in place, produces a combination no real Chrome sends. The algorithm is unchanged; only its input is.

JavaScript and Web APIs

high impactMeasured on both builds

V8 15.4 reorders the global object: Float16Array, SuppressedError and friends move to their spec positions

Until 153, V8 appended newer built-ins (Float16Array, SuppressedError, DisposableStack, AsyncDisposableStack, Math.f16round, Math.sumPrecise, the DataView float16 accessors, Intl.Locale.prototype.variants) at the end of their objects' property lists. V8 15.4 installs them where the specification lists them: Float16Array goes from position 893 to 41 in window, DisposableStack from 891 to 53. The same happens in workers.

Object.getOwnPropertyNames(window)[Object.getOwnPropertyNames(window).indexOf('Float64Array') + 1]
Chrome 153
"DataView"
Chrome 154
"Float16Array"
  • Object.getOwnPropertyNames(window)[Object.getOwnPropertyNames(window).indexOf('URIError') + 1]"globalThis"→ "SuppressedError"
  • Object.getOwnPropertyNames(Math).slice(-2).join(',')"f16round,sumPrecise"→ "SQRT1_2,SQRT2"
  • Object.getOwnPropertyNames(DataView.prototype).indexOf('getFloat16') < Object.getOwnPropertyNames(DataView.prototype).indexOf('getFloat32')false→ true
  • Object.getOwnPropertyNames(Intl.Locale.prototype).indexOf('variants') < Object.getOwnPropertyNames(Intl.Locale.prototype).indexOf('baseName')false→ true

Why it matters: Nothing was added or removed, so a presence check sees no difference, but every fingerprint that hashes the order of window's or Math's properties changes. The order is a property of the engine build and cannot be set by a page.

high impactMeasured on both builds

Promise.try returns the promise it was given

When the callback returns a promise, Promise.try now returns that same promise instead of a new one wrapping it, following a change to the specification.

((p) => Promise.try(() => p) === p)(Promise.resolve(1))
Chrome 153
false
Chrome 154
true

Why it matters: A one-line engine behaviour, the same in every realm, that a page cannot influence.

medium impactMeasured on both builds

window.requestResize (responsive iframes)

A new global that lets an embedded document ask its embedder for a size, paired with the CSS frame-sizing property below. window grows from 1225 to 1226 own properties.

typeof window.requestResize
Chrome 153
"undefined"
Chrome 154
"function"

Why it matters: A new global changes the window's property list and count.

medium impactMeasured on both builds

CSS Typed OM in dedicated workers

Fourteen CSS Typed OM classes (CSSStyleValue, CSSUnitValue, CSSMathSum, …) are now exposed in dedicated workers, which go from 335 to 349 globals. This check spins up a worker, so it is asynchronous.

new Promise((r) => { const w = new Worker(URL.createObjectURL(new Blob(['postMessage(typeof CSSStyleValue)']))); w.onmessage = (e) => r(e.data); })
Chrome 153
"undefined"
Chrome 154
"function"

Why it matters: Worker globals are a fingerprint surface of their own, and their count and order both change here.

low impactMeasured on both builds

Property order moved: Document.prototype.activeViewTransition

Its View Transition kill-switch flag was removed in 154, so Blink now installs it with the unconditional members: position 246 on 153, 70 on 154.

Object.getOwnPropertyNames(Document.prototype).indexOf('activeViewTransition') < Object.getOwnPropertyNames(Document.prototype).indexOf('fonts')
Chrome 153
false
Chrome 154
true

Why it matters: Same mechanism as the 153 customElementRegistry move: order encodes the build.

Removed or deprecated

high impactMeasured on both builds

document.requestStorageAccessFor and FencedFrameConfig.setSharedStorageContext removed

Google's notes listed requestStorageAccessFor as removed in 153, but the method was still exposed there (it only rejected). Chrome 154 removes it, along with the last Shared Storage remnant on FencedFrameConfig.

'requestStorageAccessFor' in document
Chrome 153
true
Chrome 154
false
  • 'setSharedStorageContext' in FencedFrameConfig.prototypetrue→ false

Why it matters: Removals are clean version markers: a 154 claim with requestStorageAccessFor present comes from an older engine.

Parsing and rendering behaviour

high impactMeasured on both builds

XML parsing back on libxml2: the Chrome 153 error text is gone again

Chrome 153 switched DOMParser to a Rust XML parser; Chrome 154's default is libxml2 again, so the error text for malformed XML is the Chrome 152 text. This makes the message a 153-only marker. The parser is still behind a feature flag that a server-side experiment can flip.

new DOMParser().parseFromString('<a><b></a>', 'application/xml').querySelector('parsererror div').textContent.trim()
Chrome 153
"error on line 1 at column 10: Unexpected closing tag: a != b"
Chrome 154
"error on line 1 at column 11: Opening and ending tag mismatch: b line 1 and a"

Why it matters: The text comes straight from the parser, so one malformed string identifies the parser in use.

high impactMeasured on both builds

XSLT output carries a deprecation banner

Documents produced by XSLTProcessor.transformToDocument() (and XSLT-styled XML) now contain a red "This site uses XSLT" notice, ahead of XSLT's removal. The serialised output grows from 84 to 947 characters for a one-paragraph stylesheet.

/This site uses XSLT/.test(new XMLSerializer().serializeToString(((p) => (p.importStylesheet(new DOMParser().parseFromString('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><html><body><p><xsl:value-of select="r/v"/></p></body></html></xsl:template></xsl:stylesheet>', 'application/xml')), p.transformToDocument(new DOMParser().parseFromString('<r><v>1</v></r>', 'application/xml'))))(new XSLTProcessor())))
Chrome 153
false
Chrome 154
true

Why it matters: Deterministic, and it also changes any content hash over XSLT output.

CSS

medium impactMeasured on both builds

scroll-marker-group: the tabs and links modes are accepted again

Chrome 152 accepted after tabs and after links by mistake, 153 (from 153.0.8010.43) gated them, and 154 turns them on for real. The value therefore reads true, false, true across the three versions.

CSS.supports('scroll-marker-group', 'after tabs')
Chrome 153
false
Chrome 154
true

Why it matters: A value that singles out 153 among its neighbours. On other Chromium-based builds the flag may be set differently, so treat it as a supporting signal.

WebGL and WebGPU

Intl, time zones and locale

high impactMeasured on both builds

Time zone data updated to tzdata 2026c

Four of 422 zones change: Africa/Casablanca and Africa/El_Aaiun stay on +00 from October 1, 2026 (Chrome 153 still reports +01), and America/Vancouver and America/Edmonton stop falling back on November 1, 2026 (Chrome 153 reports -08 and -07 for mid-November, Chrome 154 reports -07 and -06). Every other zone, and every other Intl data set, is identical.

new Intl.DateTimeFormat('en-US', { timeZone: 'Africa/Casablanca', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 9, 1)).find((p) => p.type === 'timeZoneName').value
Chrome 153
"GMT+01:00"
Chrome 154
"GMT+00:00"
  • new Intl.DateTimeFormat('en-US', { timeZone: 'America/Vancouver', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 10, 15)).find((p) => p.type === 'timeZoneName').value"GMT-08:00"→ "GMT-07:00"
  • new Intl.DateTimeFormat('en-US', { timeZone: 'America/Edmonton', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 10, 15)).find((p) => p.type === 'timeZoneName').value"GMT-07:00"→ "GMT-06:00"

Why it matters: Geo-coherence checks compare the offset a browser reports with the one its IP's region should have. A browser claiming 154 on a Moroccan, British Columbian or Albertan exit must report the new offsets from those dates, and a real 153 cannot.

What the docs claim that the source does not show

Release notes and Chrome Platform Status describe intent; the source at the release tag is what shipped. These entries differ, so a version check built on the docs alone would be wrong.

Reproduce these results

  1. 1. Get both versions

    Use the stable Google Chrome packages of the two exact versions. Google keeps every version in its Linux package pool:

    bash
    for v in 153.0.8010.52 154.0.8037.57; do
      curl -sSO https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${v}-1_amd64.deb
      dpkg -x google-chrome-stable_${v}-1_amd64.deb chrome-${v}
    done
  2. 2. Or use Chrome for Testing, with one extra flag

    Chrome for Testing builds run Chromium's testing field-trial configuration by default, which changes over a hundred observable values and the TLS fingerprint. Start them with --disable-field-trial-config and they match the branded build apart from the brand name.

    bash
    curl -sSO https://storage.googleapis.com/chrome-for-testing-public/154.0.8037.57/linux64/chrome-linux64.zip
    unzip -q chrome-linux64.zip
    ./chrome-linux64/chrome --disable-field-trial-config --user-data-dir="$(mktemp -d)"
  3. 3. Start each one clean

    A new profile directory per run and no automation flags. Headless (--headless=new) gives the same values as headful for everything on this page.

    bash
    ./chrome-154.0.8037.57/opt/google/chrome/chrome --user-data-dir="$(mktemp -d)" --no-first-run https://example.com
  4. 4. Run the checks

    Press "Run the checks in this browser" at the top of this page, or paste the script below into the DevTools console on any https:// page. The worker check is asynchronous; the script awaits it.

  5. 5. Check the network side

    Open tls.peet.ws or tls.browserleaks.com in each version and compare the JA4 and HTTP/2 fingerprints with the values above. They are the same on 152, 153 and 154.

  6. 6. Find a change in the source yourself

    Blink's test expectations record the page-visible surface of each release; V8's bootstrapper records the install order of built-ins:

    bash
    git diff 153.0.8010.55 154.0.8037.58 -- third_party/blink/web_tests/virtual/stable/webexposed/
    git diff 153.0.8010.55 154.0.8037.58 -- third_party/blink/renderer/platform/runtime_enabled_features.json5
    git log --oneline 15.3.76.13..15.4.80.11 -- src/init/bootstrapper.cc   # in a V8 checkout

The whole check list as one script

Paste it into the DevTools console on Chrome 153 and on Chrome 154: it prints every check on this page with the value your browser returns.

chrome-154-probe.js
// Chrome 153 vs 154: paste into the DevTools console on any https:// page and press Enter.
// Each line prints "<change>  <check> = <value>". Expected values: clearcotelabs.com/chrome-releases/154
(async () => {
  const checks = [
    ["grease-brand", () => navigator.userAgentData.brands.map((b) => `${b.brand};v=${b.version}`).join(', ')],
    ["v8-property-order", () => Object.getOwnPropertyNames(window)[Object.getOwnPropertyNames(window).indexOf('Float64Array') + 1]],
    ["v8-property-order", () => Object.getOwnPropertyNames(window)[Object.getOwnPropertyNames(window).indexOf('URIError') + 1]],
    ["v8-property-order", () => Object.getOwnPropertyNames(Math).slice(-2).join(',')],
    ["v8-property-order", () => Object.getOwnPropertyNames(DataView.prototype).indexOf('getFloat16') < Object.getOwnPropertyNames(DataView.prototype).indexOf('getFloat32')],
    ["v8-property-order", () => Object.getOwnPropertyNames(Intl.Locale.prototype).indexOf('variants') < Object.getOwnPropertyNames(Intl.Locale.prototype).indexOf('baseName')],
    ["promise-try-identity", () => ((p) => Promise.try(() => p) === p)(Promise.resolve(1))],
    ["iterator-includes", () => typeof Iterator.prototype.includes],
    ["request-resize", () => typeof window.requestResize],
    ["fontface-width", () => 'width' in FontFace.prototype],
    ["typed-om-workers", () => new Promise((r) => { const w = new Worker(URL.createObjectURL(new Blob(['postMessage(typeof CSSStyleValue)']))); w.onmessage = (e) => r(e.data); })],
    ["svg-textpath-sidetype", () => 'TEXTPATH_SIDETYPE_LEFT' in SVGTextPathElement],
    ["active-view-transition-order", () => Object.getOwnPropertyNames(Document.prototype).indexOf('activeViewTransition') < Object.getOwnPropertyNames(Document.prototype).indexOf('fonts')],
    ["storage-access-for-removed", () => 'requestStorageAccessFor' in document],
    ["storage-access-for-removed", () => 'setSharedStorageContext' in FencedFrameConfig.prototype],
    ["xml-parser-libxml2", () => new DOMParser().parseFromString('<a><b></a>', 'application/xml').querySelector('parsererror div').textContent.trim()],
    ["xslt-banner", () => /This site uses XSLT/.test(new XMLSerializer().serializeToString(((p) => (p.importStylesheet(new DOMParser().parseFromString('<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><html><body><p><xsl:value-of select="r/v"/></p></body></html></xsl:template></xsl:stylesheet>', 'application/xml')), p.transformToDocument(new DOMParser().parseFromString('<r><v>1</v></r>', 'application/xml'))))(new XSLTProcessor())))],
    ["frame-sizing", () => CSS.supports('frame-sizing', 'content-height')],
    ["scroll-marker-group-modes-on", () => CSS.supports('scroll-marker-group', 'after tabs')],
    ["wgsl-swizzle-assignment", () => navigator.gpu.wgslLanguageFeatures.has('swizzle_assignment')],
    ["tzdata-2026c", () => new Intl.DateTimeFormat('en-US', { timeZone: 'Africa/Casablanca', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 9, 1)).find((p) => p.type === 'timeZoneName').value],
    ["tzdata-2026c", () => new Intl.DateTimeFormat('en-US', { timeZone: 'America/Vancouver', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 10, 15)).find((p) => p.type === 'timeZoneName').value],
    ["tzdata-2026c", () => new Intl.DateTimeFormat('en-US', { timeZone: 'America/Edmonton', timeZoneName: 'longOffset' }).formatToParts(Date.UTC(2026, 10, 15)).find((p) => p.type === 'timeZoneName').value],
  ];
  const out = [];
  for (const [id, f] of checks) {
    let v;
    try { v = await f(); } catch (e) { v = "throws " + e.name; }
    const expr = f.toString().replace(/^\(\)\s*=>\s*/, "");
    out.push(id.padEnd(28) + expr + " = " + (typeof v === "string" ? JSON.stringify(v) : String(v)));
  }
  console.log(out.join("\n"));
})();

FAQ

When was Chrome 154 released?

Chrome 154 reached the stable channel on September 22, 2026, two weeks after Chrome 153, on Google's two-week release cycle.

What is the Chrome 154 user agent string?

On Windows: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36. Only the major version changes; the full version travels in Client Hints. The table above lists every platform.

What is the Sec-CH-UA header in Chrome 154?

"Chromium";v="154", "Google Chrome";v="154", "Not A(Brand";v="99". Both the fake GREASE brand and the order change with every major.

Did Chrome 154 change the TLS (JA3/JA4) or HTTP/2 fingerprint?

No. Both are identical to Chrome 153 and Chrome 152: JA4 t13d1517h2_8daaf6152771_cb7bf5808d99 and the same HTTP/2 settings and priority.

How can a website tell Chrome 153 from Chrome 154?

The quickest single lines are Promise.try(() => p) === p (true only from 154) and typeof Iterator.prototype.includes. The property order of window changes as well, which shifts any fingerprint built on it.

Why do two checks read the same on Chrome 152 and Chrome 154?

Chrome 153 switched its XML parser and turned off two scroll-marker-group values; Chrome 154 reverted both. So for those two checks 153 is the odd one out, and a browser matching 152 on them while matching 154 on everything else is a normal Chrome 154.

Which time zones changed in Chrome 154?

Africa/Casablanca and Africa/El_Aaiun (no more +01 from October 2026) and America/Vancouver and America/Edmonton (no fall-back in November 2026), from tzdata 2026c. The other 418 zones are unchanged.

Clearcote puts this into practice

An open-source Chromium with fingerprint control compiled into the engine. A drop-in for Playwright & Puppeteer.

Free for one browser with GitHub. No card.