A browser extension hydration error happens when an extension changes the page before React hydrates. React then sees attributes or elements the server did not send. First reproduce the page in a clean browser profile. Ignore the difference only after you have confirmed its source.
Symptoms
The warning may name an unfamiliar attribute on <html>, <body>, or a form
field:
Warning: Extra attributes from the server: cz-shortcut-listen
Warning: Extra attributes from the server: data-new-gr-c-s-check-loaded,data-gr-ext-installed
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up.A Grammarly hydration error is one example. cz-shortcut-listen="true"?
Next.js did not add that attribute; check ColorZilla on <body>.
| Attribute or element | Added by |
|---|---|
data-new-gr-c-s-check-loaded, data-gr-ext-installed, <grammarly-desktop-integration> | Grammarly |
cz-shortcut-listen="true" | ColorZilla |
data-lt-installed | LanguageTool |
bis_skin_checked | Commonly traced to Bitdefender's browser extension |
Their own data-* attributes on forms and inputs | Password managers such as LastPass, Dashlane and 1Password |
data-darkreader-* and inline styles | Dark Reader |
__gchrome_uniqueid on inputs | Chrome and Edge on iPad, not an extension |
The __gchrome_uniqueid hydration warning can come from Chrome or Edge on iPadOS,
not an extension (Next.js issue).
Confirm it the same way before adding an ignore rule.
hydration-proof reports recognized extension changes as HP4002, an informational finding by default. Other pre-hydration changes appear as HP4001.
Why a browser extension hydration error happens
An extension can mark <body>, modify an input, or insert an element before
your app starts. React compares against that changed DOM, not just the server
response.
React 19 tolerates some extra tags, but changed attributes or text can still
mismatch. A script inserted before <head> can also break hydration
(React issue).
How to fix it
Do not change app code until you have confirmed the extension caused it.
Confirm it in a clean profile
- Open the page in a private window with extensions disabled, or in a new browser profile.
- Reload with the console open. If the warning is gone, an extension caused it.
- Turn extensions back on one at a time to find which one, if you need to know.
If the warning stays in a clean profile, inspect your app and its third-party scripts.
Silence the development warning on html and body only
If an extension changes an attribute on <body> or <html>, you can put
suppressHydrationWarning on that element during development:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body suppressHydrationWarning>{children}</body>
</html>
);
}This covers only that element's own attributes. It does not cover inputs or text below it. See suppressHydrationWarning before using it elsewhere.
Catch it with ESLint
A linter cannot see browser extensions. The
audit-suppress-hydration-warning
rule checks where you use React's suppression prop.
Catch it in CI
hydration-proof test uses a clean browser, so extensions in your everyday
profile do not affect it. If you simulate one with a scenario's initScripts,
recognized changes appear as HP4002. To ignore a confirmed attribute, name it
in the config:
import { defineConfig } from "hydration-proof";
export default defineConfig({
ignore: {
attributes: ["cz-shortcut-listen", /^data-gr-/],
},
});Ignored findings remain visible in the report. See ignoring findings.