posthog-js icon indicating copy to clipboard operation
posthog-js copied to clipboard

The posthog-js library is throwing error, when user is iddle

Open lukasbicus opened this issue 2 months ago • 18 comments

Bug description

Our Sentry reported over 170 errors during the last month, with this error thrown:

SecurityError: Failed to read a named property 'removeEventListener' from 'Window': Blocked a frame with origin "https://app.tradespace.io" from accessing a cross-origin frame.
    at h (../../../node_modules/.pnpm/@[email protected]_patch_hash=4a974d451d029e3ef6c302f641dfaf41fb0881146b6d5198ccdbe8d50776b64f/node_modules/@rrweb/record/dist/record.js:3615:1)
    at forEach (../../../node_modules/.pnpm/@[email protected]_patch_hash=4a974d451d029e3ef6c302f641dfaf41fb0881146b6d5198ccdbe8d50776b64f/node_modules/@rrweb/record/dist/record.js:5571:27)
    at Array.forEach (<anonymous>)
    at call (../../../node_modules/.pnpm/@[email protected]_patch_hash=4a974d451d029e3ef6c302f641dfaf41fb0881146b6d5198ccdbe8d50776b64f/node_modules/@rrweb/record/dist/record.js:5571:14)
    at LazyLoadedSessionRecording.stop (../src/extensions/replay/external/lazy-loaded-session-recorder.ts:791:9)
    at this._onSessionIdleResetForcedListener (../src/extensions/replay/external/lazy-loaded-session-recorder.ts:704:22)
    at SimpleEventEmitter.emit (../../../node_modules/posthog-js/src/utils/simple-event-emitter.ts:21:13)
    at this._enforceIdleTimeout (../../../node_modules/posthog-js/src/sessionid.ts:329:36)
    at sentryWrapped (../../../node_modules/@sentry/browser/src/helpers.ts:117:17)

Please describe.

How to reproduce

  1. The users were idle for a long period of time

Related sub-libraries

  • [ ] All of them
  • [x] posthog-js (web)
  • [ ] posthog-js-lite (web lite)
  • [ ] posthog-node
  • [ ] posthog-react-native
  • [ ] @posthog/react
  • [ ] @posthog/ai
  • [ ] @posthog/nextjs-config

Additional context

The bug seems to happen to me, originating in the @rrweb/[email protected] / using the @rrweb/[email protected] in Posthog.

Updating to @rrweb/[email protected] may help.

Any advice, how can this be fixed in our repository?

lukasbicus avatar Oct 31 '25 07:10 lukasbicus

I noticed, we still use PostHogProvider from posthog-js/react. Is this package deprecated? Should we use @posthog/react?

lukasbicus avatar Oct 31 '25 07:10 lukasbicus

@PostHog/team-replay probably a replay issue since i see 'rrweb' logs

marandaneto avatar Nov 01 '25 07:11 marandaneto

hey @lukasbicus can you share a little more about how you're using posthog replay - since there's an iframe cross origin issue here... this is our tidy-up code running, i guess there's an assumption about the context it's running in that isn't true for your setup

I noticed, we still use PostHogProvider from posthog-js/react. Is this package deprecated? Should we use @posthog/react?

i don't think that will help here, but yep you should move over at some point - although posthog-js/react is just a passthrough to @posthog/react so it won't change anything except tidiness

pauldambra avatar Nov 03 '25 09:11 pauldambra

Hi @pauldambra - thanks for taking a look.

Here is what I found when I investigated the setup on our project:

// We init PostHog like this:
posthog.init(process.env.POST_HOG_API_KEY, {
  api_host: process.env.POST_HOG_HOST,
  defaults: '2025-05-24',
  disable_session_recording: currentUser?.tradespaceEmployee ? true : false,
  session_recording: {
    recordCrossOriginIframes: false
  }
});

if (currentUser) {
  posthog.identify(currentUser.uuid, {
    email: currentUser.email,
    name: currentUser.fullName,
    account_id: currentAccount.id,
    account_user_id: currentAccountUser.id
  });
}
import posthog from 'posthog-js';
// We wrap the app in the PostHogProvider:
// ...
  <PostHogProvider client={posthog}>
    {
      //... the app itself.
    }
  </PostHogProvider>

We also use some feature flags on our project (useFeatureFlagEnabled from posthog-js/react).

Is this helpful? I'm not quite sure, how to answer this question. I watch videos of users' behavior only on Sentry.

lukasbicus avatar Nov 03 '25 12:11 lukasbicus

Does your application run in an iframe?

When a user is idle for a long time and posthog recording is running we shut down the recorder to save resources and the error message looks like for some reason we can create the event listeners but when we are tearing down we get an error removing them 🫠

pauldambra avatar Nov 03 '25 12:11 pauldambra

No, our application doesn't run in an iframe.

lukasbicus avatar Nov 03 '25 13:11 lukasbicus

Hmmm, surprising the error has Blocked a frame with origin "https://app.tradespace.io/" from accessing a cross-origin frame.

something is in a frame 🙈

pauldambra avatar Nov 03 '25 13:11 pauldambra

Hmmm, surprising the error has Blocked a frame with origin "https://app.tradespace.io/" from accessing a cross-origin frame.

something is in a frame 🙈

Ouu, that can be a clue. Our app runs on https://app.tradespacestaging.io/ or https://app.tradespace.io/. Usually, people use it from the browser. If it is used in an iframe, it has to be a very specific kind of usage. I'll discuss with my team and let you know with further findings.

lukasbicus avatar Nov 03 '25 13:11 lukasbicus

awesome, thank you! very happy to ship a fix here but don't know what it would be 🙈 😅

pauldambra avatar Nov 03 '25 13:11 pauldambra

Hi @pauldambra - We get your point. Of course, this package can't resolve our CORS issues.

Right now, we don't understand where the root of the issue is, as we don't use our app in an iframe 99 percent of the time, and the error happens on pages distant from this iframe. We will watch this issue further. Thanks for your insights.

lukasbicus avatar Nov 05 '25 07:11 lukasbicus

No worries, thanks for you patience with the back-and-forth here

Do let us know how it goes, since even if it's not something we could fix (and ofc it might still be) we might be able to output a nicer error that makes this easier for the future traveller!

pauldambra avatar Nov 05 '25 08:11 pauldambra

I was also able to reproduce this one on my local, by just idling for a longer period of time ~30 mins on the screen where the posthog is called. No iframe here as well

record.js:3615 Uncaught SecurityError: Failed to read a named property 'removeEventListener' from 'Window': Blocked a frame with origin "https://localhost.test" from accessing a cross-origin frame. at Ie.stop (lazy-loaded-session-recorder.ts:876:9) at lazy-loaded-session-recorder.ts:753:22 at Cn.emit (simple-event-emitter.ts:21:13) at sessionid.ts:330:36

using the php sdk, probably after reply inactivity it tries to do a cleanup?

Seems to fail on this._stopRrweb?.()

filipgymdesk avatar Nov 11 '25 10:11 filipgymdesk

👋 hey @filipgymdesk the php sdk doesn't use rrweb at all, this could only come from the posthog-js SDK

SecurityError: Failed to read a named property 'removeEventListener' from 'Window': Blocked a frame with origin "localhost.test" from accessing a cross-origin frame.

this error is specifically referencing a frame.

do you run a CSP on your site?

the only thing I can think is that the rrweb SDK is trying to get a vanilla removeEventListener from an iframe (a very common technique) and that your CSP is blocking that

it's definitely not a general problem with all instances of stopping on idle so it's hard to investigate without more detail

pauldambra avatar Nov 11 '25 10:11 pauldambra

My bad, it's JS indeed

public function posthog(): string {

     $script = '<script>'
                 . '!function(t,e){var o,n,p,r;e.__SV||(window.posthog && window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init Ce Ds js Te Os As capture Ye calculateEventProperties Us register register_once register_for_session unregister unregister_for_session Hs getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey displaySurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty qs Ns createPersonProfile Bs Cs Ws opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing get_explicit_consent_status is_capturing clear_opt_in_out_capturing Ls debug L zs getPageViewId captureTraceFeedback captureTraceMetric".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);'
                 . "posthog.init('phc_.......', {"
                     . "api_host: 'https://us.i.posthog.com',"
                     . "defaults: '2025-05-24',"
                     . "person_profiles: 'always',"
                 . "})";

     if (Users::isLogged() && !isset($this -> view -> skipPosthogIdentify)) {
         $script .= "
             posthog.identify(
                 '" . Users::getId() . "',
                 { email: '" . Users::getIdentity() -> email . "', name: '" . Users::getIdentity() -> name . "' },
         );";
     }

     $script .= "</script>";

     return $script;
 }

filipgymdesk avatar Nov 11 '25 11:11 filipgymdesk

I'm getting this error

SecurityError: Failed to read a named property 'removeEventListener' from 'Window': An attempt was made to break through the security policy of the user agent.

Found the culprit call to be this from Sentry error stack:

posthog.stopSessionRecording();

My site uses CSP.

pkpio avatar Nov 12 '25 22:11 pkpio

hey @pkpio could you share the CSP?

we do remove event listeners when people call stop, but they're event listeners we added suggesting we had permission to add event listeners but not remove them 🤯

pauldambra avatar Nov 12 '25 22:11 pauldambra

This is our CSP for the auth pages where we do this call - it's more relaxed than all our other pages

"default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';"

pkpio avatar Nov 12 '25 22:11 pkpio

We are seeing something similar; in our case, we're mostly following the recommended policy, though I will try adding worker-src

wyardley avatar Dec 18 '25 16:12 wyardley