posthog-js
posthog-js copied to clipboard
'dangerouslySetInnerHTML' warning when initializing posthog and next-theme
When I try to use posthog in addition to next-theme I get an error in the browser saying Warning: Prop dangerouslySetInnerHTML did not match. I'm using Next 13 app router. It seems as though adding my posthog provider to the layout component strips some attributes related to my theme from my project at build time, which later get applied and loaded client side, causing a mismatch. Here's a code sandbox with the minimal code to reproduce the issue. Note, to actually see the error in the sandbox you'll need to pass in your own API key for Posthog and view the application in it's own browser tab and then check the logs from there.
Also running into this issue, any fixes?
bumping this! having the same issue
same issue here
So I originally posted my question a few months back. The response from the posthog team was underwhelming. They just told me to leave as is. I actually ended up using a different project called highlight.io for session recording, because I couldn't figure out the proper workaround. It probably exists, though it might just be to suppress the hydration warning.
https://nextjs.org/docs/messages/react-hydration-error
I've narrow it down to the session recordings.
https://github.com/PostHog/posthog-js/assets/1843792/c1d80d03-d462-4d96-a38a-eacd7c16ad66
Everything else seems to be working fine
Can we init posthog after first render, by useEffect? Works for me:
export default function CSPostHogProvider({ children }: { children: ReactNode }) {
useEffect(() => {
if (!posthog.__loaded) {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY || "", { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST });
}
}, []);
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
}
Has anybody found a solution for this?
+1 seeing this in remix with prop mismatches if I add posthog
The solution I've found for this is to create a new org for development only and disable screen recording on PH's dashboard
hey all, sorry we missed this!
i'm just investigating to see what I can find out (but I'll admit to not having used SSR or Next JS much so feel free to prompt or correct me!)
I've forked the supplied code sandbox and can replicate the issue whether or not I include posthog
That might only mean I'm confused about the problem :)
If I open the application in incognito mode then I don't get the error
Adding posthog back in using just the JS snippet (and in incognito mode) I don't get the error
And doing the same with the code sandbox in the initial OP I don't get an error in incognito but I do in my normal browser
So I originally posted my question a few months back.
@msquinn sorry you weren't happy with the response... you linked to the nextjs link in your comment so I can't follow up, but I'm happy to look into it 💖
So, I'm only getting the error because I have the locator js extension installed
are others able to test if they still get the error in an incognito window or with all browser extensions disabled
(I'm super happy to investigate further but need to be able to consistently repro or i'll just be chasing my tail - and you all will know next/ssr better than me 😊)
@wladpaiva toggling session replay didn't change anything for me but then I may just not be replicating the problem correctly)
also see https://x.com/martinamps/status/1811491989084577911 https://github.com/martinamps/posthog-repro/tree/main
We are indeed using radix components, specifically shadcn/ui
so looking at the repro provided by martin i get the same error if i don't include posthog
import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode, useEffect } from "react";
import { hydrateRoot } from "react-dom/client";
// import posthog from "posthog-js";
function PosthogInit() {
// useEffect(() => {
// posthog.init('phc_RpO1rh8u4ZgIDxSelv4kQDvyiyyty6iUiLpbs3sTOyb', {
// api_host: 'https://us.i.posthog.com',
// person_profiles: 'identified_only',
// });
// }, []);
return null;
}
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
<PosthogInit/>
</StrictMode>
);
});
causes the error
if you comment out <PosthogInit/> then the hydrate error goes away
(i also had to disable two browser extensions that caused a similar error in order to test this)
So, I could still be misunderstanding but still can't repro :)
Ahh nice catch - thanks for looking. We'll add this to the list of reasons I have largely avoided frontend for the past decade 😂 .... For remix at least, this may simply be a documentation issue.. some googling/testing suggests this is a better implementation -- it works + no warnings:
import * as React from 'react';
import { RemixBrowser } from '@remix-run/react';
import { hydrateRoot } from 'react-dom/client';
import posthog from 'posthog-js';
function hydrate() {
posthog.init('token', {
api_host: 'https://us.i.posthog.com',
person_profiles: 'identified_only',
});
React.startTransition(() => {
hydrateRoot(
document,
<React.StrictMode>
<RemixBrowser />
</React.StrictMode>,
);
});
}
if (window.requestIdleCallback) {
window.requestIdleCallback(hydrate);
} else {
window.setTimeout(hydrate, 1);
}
likely could go even simpler and throw the
disclaimer: I started learning Remix last week, so I'm no expert
you've got a week on me @martinamps 🤣
hey all, i'm going to close this so that future travellers see that the problem/solution here was never related to PostHog and it's only that SSR is tricky
ofc if someone can come up with a repro of where posthog isn't working well here do reopen this or log a new issue - we love fixing things - i just can't find anything for us to fix here 😊 😌
@pauldambra though I can't speak tot he original nextjs issue, it seems reasonably likely the documentation/instructions provided by PostHog are wrong for remix though. So I'd advocate updating those to mitigate new users people churning or opening issues like this
For Next.js, you can use next/dynamic like this:
// app/layout.js
import './globals.css'
import { PHProvider } from './providers'
import dynamic from 'next/dynamic'
const PostHogPageView = dynamic(() => import('./PostHogPageView'), {
ssr: false,
})
export default function RootLayout({ children }) {
return (
<html lang="en">
<PHProvider>
<body>
<PostHogPageView />
{children}
</body>
</PHProvider>
</html>
)
}
See our docs for more: https://posthog.com/docs/libraries/next-js#app-router
For Next.js, you can use
next/dynamiclike this:// app/layout.js import './globals.css' import { PHProvider } from './providers' import dynamic from 'next/dynamic' const PostHogPageView = dynamic(() => import('./PostHogPageView'), { ssr: false, }) export default function RootLayout({ children }) { return ( <html lang="en"> <PHProvider> <body> <PostHogPageView /> {children} </body> </PHProvider> </html> ) }See our docs for more: https://posthog.com/docs/libraries/next-js#app-router
we've been doing this since the beginning and still seeing the warning every time
I am still facing this issue:
My PHProvider:
"use client";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
import { IS_POSTHOG_ENABLED } from "./client";
if (IS_POSTHOG_ENABLED) {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
capture_pageview: false,
session_recording:
process.env.NODE_ENV === "production"
? {
maskAllInputs: true,
}
: undefined,
});
}
export function PHProvider({ children }: { children: React.ReactNode }) {
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
}
Aggregating all my providers like this here here:
export function Providers({
children,
language,
currentUser,
}: React.PropsWithChildren<{ language: string; currentUser: User | null }>) {
return (
<SessionProvider>
<CurrentUserProvider serverValue={currentUser}>
<I18nProvider language={language}>
<SWRConfig value={SwrConfig}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
<PHProvider>{children}</PHProvider>
</ThemeProvider>
</SWRConfig>
</I18nProvider>
</CurrentUserProvider>
</SessionProvider>
);
}
And then in layout/app I import them:
export default async function RootLayout({ children }: React.PropsWithChildren) {
// ... doing here some stuff around session and language
return (
<html lang={lang} suppressHydrationWarning>
<body>
<Providers language={lang} currentUser={currentUser}>
<NextTopLoader color="#6AA0A0" showSpinner={false} />
<Toaster position="top-right" richColors />
{children}
</Providers>
<Analytics />
</body>
</html>
);
}
It still leads to:
Though I followed the guides here: Posthog Guide Vercel Guide
Any idea how to get this solved?
@maakle I'm not working at the moment so may not react quickly here but... in previous reproductions people shared I completely removed PostHog and they still got the error. In your example the error appears to be to do with a theme. If you completely remove PostHog do you still get the error
@maakle , try init posthog inside PHProvider in useEffect. This is possible solution for many NextJS SSR issues (https://nextjs.org/docs/messages/react-hydration-error)
I think the issue was added in a newer package. When reverting back to an older version of the sdk e.g. "posthog-js": "^1.130.2", it works.
@andlipro your approach also works with the latest "posthog-js": "^1.154.5" as of this writing. Thank you!
"use client";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
import { useEffect } from "react";
import { IS_POSTHOG_ENABLED } from "./client";
export function PHProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (IS_POSTHOG_ENABLED) {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
capture_pageview: false,
session_recording:
process.env.NODE_ENV === "production"
? {
maskAllInputs: true,
}
: undefined,
});
}
}, []);
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
}
cc @ivanagas for docs inspiration maybe
Ty, documenting here: https://github.com/PostHog/posthog.com/pull/9143
If this doesn't work for someone, please send recreation of issue and I will try to debug.
@ivanagas without if (!posthog.__loaded) { check inside useEffect it shows warning about double initialization to me. Can we use this check or there are public method instead?
@ivanagas without
if (!posthog.__loaded) {check insideuseEffectit shows warning about double initialization to me. Can we use this check or there are public method instead?
What is the warning? When you call init, the library will check the __loaded method itself and return the current instance. See: https://github.com/PostHog/posthog-js/blob/f5a0d12603197deab305a7e25843f04f3fa4c99e/src/posthog-core.ts#L365-L376
yes, this warning. I see warning and I assume that calling init twice is wrong, and I should take care about this check in my code. But there are no other method to check __loaded