Skip to content
Clearcote Labs · Chrome releases

What each Chrome release changed

Chrome ships a new version every two weeks, and each one changes something a website or a server can see: new APIs, removed ones, Client Hints, the network handshake. Each page here lists those changes for one version, measured on real builds, with a one-line check and a Chromium source link for every item.

Every check across the series, and which version your browser matches

One row per check, one column per Chrome version. A tinted cell differs from the version before it, so a row tinted in one column only identifies that version. Run the checks to see where this browser's engine lands.

Chrome 152 → Chrome 153 → Chrome 154 · 49 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 152Chrome 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(', ')"Chromium;v=152, Not?A_Brand;v=24, Google Chrome;v=152""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
New Iterator helpers: Iterator.zip, Iterator.zipKeyed and Iterator.prototype.jointypeof Iterator.zip"undefined""function"–
New Iterator helpers: Iterator.zip, Iterator.zipKeyed and Iterator.prototype.jointypeof Iterator.zipKeyed"undefined""function"–
New Iterator helpers: Iterator.zip, Iterator.zipKeyed and Iterator.prototype.jointypeof Iterator.prototype.join"undefined""function"–
New <camera> and <microphone> elementstypeof HTMLCameraElement"undefined""function"–
New <camera> and <microphone> elementstypeof HTMLMicrophoneElement"undefined""function"–
Shared Storage removed, with its permissions-policy features'sharedStorage' in windowtruefalse–
Shared Storage removed, with its permissions-policy featurestypeof SharedStorageWorklet"function""undefined"–
Shared Storage removed, with its permissions-policy features'sharedStorageWritable' in HTMLIFrameElement.prototypetruefalse–
Shared Storage removed, with its permissions-policy features'canLoadOpaqueURL' in HTMLFencedFrameElementtruefalse–
Shared Storage removed, with its permissions-policy featuresdocument.featurePolicy.features().includes('run-ad-auction')truefalse–
HTMLElement.autocorrect'autocorrect' in HTMLElement.prototypefalsetrue–
BaseAudioContext.renderQuantumSize'renderQuantumSize' in BaseAudioContext.prototypefalsetrue–
Property order moved on Element, Document and CustomElementRegistryObject.getOwnPropertyNames(Element.prototype).indexOf('customElementRegistry') < Object.getOwnPropertyNames(Element.prototype).indexOf('onfullscreenchange')falsetrue–
Property order moved on Element, Document and CustomElementRegistryObject.getOwnPropertyNames(Document.prototype).indexOf('customElementRegistry') < Object.getOwnPropertyNames(Document.prototype).indexOf('fonts')falsetrue–
Property order moved on Element, Document and CustomElementRegistryObject.getOwnPropertyNames(CustomElementRegistry.prototype).indexOf('initialize') < Object.getOwnPropertyNames(CustomElementRegistry.prototype).indexOf('upgrade')falsetrue–
RTCDataChannel options now reject out-of-range values(() => { const pc = new RTCPeerConnection(); try { pc.createDataChannel('x', { maxRetransmits: -1 }); return 'no throw'; } catch (e) { return e.name; } finally { pc.close(); } })()"no throw""TypeError"–
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 moved to a Rust parser, and its error messages changednew DOMParser().parseFromString('<a><b></a>', 'application/xml').querySelector('parsererror div').textContent.trim()"error on line 1 at column 11: Opening and ending tag mismatch: b line 1 and a""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"–
Canvas 2D no longer draws a zero-length stroke(() => { const c = document.createElement('canvas'); c.width = c.height = 20; const x = c.getContext('2d'); x.lineWidth = 10; x.lineCap = 'round'; x.beginPath(); x.moveTo(10, 10); x.lineTo(10, 10); x.stroke(); return x.getImageData(10, 10, 1, 1).data[3]; })()2550–
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: scroll-axis-lockCSS.supports('scroll-axis-lock', 'auto')falsetrue–
scroll-marker-group: the tabs and links modes turned offCSS.supports('scroll-marker-group', 'after tabs')truefalsetrue–
<area> is display: none by default(() => { const a = document.body.appendChild(document.createElement('area')); const d = getComputedStyle(a).display; a.remove(); return d; })()"inline""none"–
color-mix() now serialises the implied percentage((s) => { s.color = 'color-mix(in oklab, red 30%, blue)'; return s.color; })(document.createElement('i').style)"color-mix(red 30%, blue)""color-mix(red 30%, blue 70%)"–
New CSS property: frame-sizingCSS.supports('frame-sizing', 'content-height')falsetrue–
Media and GPU
IAMF immersive audio in MP4document.createElement('video').canPlayType('audio/mp4; codecs="iamf"')"""probably"–
IAMF immersive audio in MP4MediaSource.isTypeSupported('audio/mp4; codecs="iamf"')falsetrue–
New WGSL language features: buffer_view and texture_formats_tier1navigator.gpu.wgslLanguageFeatures.has('buffer_view')falsetrue–
New WGSL language features: buffer_view and texture_formats_tier1navigator.gpu.wgslLanguageFeatures.has('texture_formats_tier1')falsetrue–
WebGL shader and program info logs no longer end in a NUL character(() => { const gl = document.createElement('canvas').getContext('webgl'); const s = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(s, 'void main(){ undeclared_x; }'); gl.compileShader(s); const l = gl.getShaderInfoLog(s); return l.charCodeAt(l.length - 1) === 0; })()truefalse–
New WGSL language feature: swizzle_assignmentnavigator.gpu.wgslLanguageFeatures.has('swizzle_assignment')falsetrue–
Automation
DevTools no longer runs Proxy getters when it serialises a logged object(() => { let hit = false; const e = new Error('x'); Object.defineProperty(e, 'stack', { configurable: true, get: new Proxy(function () {}, { apply() { hit = true; return ''; } }) }); console.log(e); return hit; })()truefalsen/a
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.

How these pages are made

Every comparison uses the same method, so anyone can repeat it. We run Google's own Chrome for Testing builds of both versions on one machine, dump what a page can observe and what the server receives, and diff the two. We then find each difference in Chromium's source at the two release tags and link it. A change Google announces but the source does not turn on by default is marked as unverified, not listed as fact.

To see how your own browser measures up against these values, run the browser fingerprint test, or read how detection uses them in Research.