PostHog / posthog

🦔 PostHog provides open-source product analytics, session recording, feature flagging and A/B testing that you can self-host.
https://posthog.com
Other
21.78k stars 1.3k forks source link

Load the toolbar without loading posthog-js #9100

Open pauldambra opened 2 years ago

pauldambra commented 2 years ago

Is your feature request related to a problem?

maybe associated with https://github.com/PostHog/posthog-js/issues/65

Currently posthog-js controls toolbar initialisation. In toolbar.js/maybeLoadEditor

If you want to use, for example, only Segment on your site. You can use app.posthog.com to analyse your data. But can't use the toolbar on your site.

Describe the solution you'd like

If posthog-js only used the decide call to choose whether to add toolbar.js into the page and toolbar was responsible for its own initialisation then you could use toolbar without using posthog-js

The code could still live in the PostHog-js library and continue to be bundled separately

Describe alternatives you've considered

Not fixing this

Additional context

Thank you for your feature request – we love each and every one!

mariusandra commented 2 years ago

You can still use posthog-js for the toolbar, just turn off all data capturing. It'll load more bytes of javascript than you might want, but it should work.

pauldambra commented 2 years ago

Harder to explain to users

to get library B you add library A with particular config

over

to get library B you add library B

pauldambra commented 2 years ago

I tested this and for the workaround of including posthog-js but disabling all capture you set config

{api_host:'https://blah.com', autocapture: false, capture_pageview: false, disable_session_recording: true,}
mariusandra commented 2 years ago

The usual scope creep alert, but... damn that's 3 different styles of writing "foo is enabled" 🤣

"One day" we would benefit from an unified approach like:

{ apiHost: 'https://foobar.com/', captureClicks: true, capturePageviews: true, captureRecording: false )

... but don't get me started about what other things should be refactored in that library... :D

IntelliAssistHQ commented 1 year ago

Shopify redirects the hash param url back to homepage, so the toolbar doesn't load in Shopify.

eromero90 commented 1 year ago

Hey team, I just noticed this issue.

The toolbar won't load if you have a frontend that overrides the injected API token (the information after the #) before the posthog-js library (or snippet) loads and has a chance to read the API token.

This can be fixed using Window PostMessage API.

Possible solution:

1) In PostHog app when you enable toolbar, Create a Listener to listen for messages sent via Window.postMessage attached to the site you want to use the toolbar (ie, mysite.com).

2) Create a Listener in posthog-js to listen for messages sent via Window.postMessage. When the posthog-js script loads on the site (mysite.com), it should set up a listener to receive messages and send a message to posthog.com to tell the app that the app is ready.

3) In PostHog app where the listener is ready, get the message from mysite.com and return the credentials to enable the toolbar.

So using postMessage API you should be able to enable cross-window communication without worrying about query params being overridden by the frontend.

matthewwong525 commented 1 month ago

Hello! I'm trying to install the toolbar on my shopify website with no success. I noticed that the hash is updated so i tried saving it into a variable and then loading it (see below). I'm able to do that but nothing seems to happen regardless.

Please help. I'm so close to switching over to posthog for my analytics for shopify. I just need the toolbar and it'll be perfect. 🙏

// store toolbarJSON
const toolbarJSON = new URLSearchParams(window.location.hash.substring(1)).get('__posthog');

// initialize posthog
!function(t,e){var o,n,p,r;e.__SV||(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.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 capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep 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 createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug".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_XXX',{
  api_host:'https://us.i.posthog.com',
  person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
  loaded: () => {
    if (toolbarJSON) {
      posthog.loadToolbar(JSON.parse(toolbarJSON));
    }
  },
})
matthewwong525 commented 1 month ago

Just to update anyone reading this in the future. I figured out the problem. It was because my shopify store had global css that set the display to none for empty divs. This effectively hid the toolbar. The workaround was to add a timeout (to wait for the toolbar to load) and set the display to block. Here's the code i used to do that:

!function(t,e){var o,n,p,r;e.__SV||(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.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 capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep 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 createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug".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_XXX',{
  api_host:'https://us.i.posthog.com',
  person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
  loaded: () => {
    // make posthog toolbar visible
    setTimeout(() => {
      document.getElementById('__POSTHOG_TOOLBAR__').style.display = 'block';
    }, 1000);
  },
})