https://www.growthbook.io/ logo
n

nutritious-beach-21644

08/11/2023, 8:44 PM
Following the documentation for setting up GTM with Growthbook. We are trying to set a client_id for our AB testing. Our website has only anonymous users, so we don't have session / user id stored in a cookie. At first we tried the GTM approach because it's tempting to use their client_id, because it should "play nicely" with our GA4 / BigQuery setup. However, overcoming the race condition of GTM not being instantiated (no
window.gtag
) before loading GB seems insurmountable at this point. It seems to me like using a conditional to check that the
gtag
is available on the window means that growthbook just won't load in some or all situations, so that approach is out. The same problem is compounded in the documentation where it's suggested that we wrap growthbook instance inside the
gtag('get', 'G-XXXXXX', 'client_id', fn()
call. We need that growthbook instance to create the Provider... right? Lastly it's suggested that we should wait for the
window.onLoad()
or a GTM Trigger to run before instantiating. I think we will have the same problem here, and (this doesn't affect us yet but) it will cause UI flashing. I can't seem to figure out a good way to get this off the ground.
Copy code
// in our client.js
let growthbook
if ("gtag" in window) {
  // If !window.gtag is unavailable (and it likely will be), this never runs
  window.gtag('get', env.GA_TRACKING_ID, 'client_id', (clientId) => {
    growthbook = new GrowthBook({
      apiHost: env.GROWTHBOOK_HOST,
      clientKey: env.GROWTHBOOK_KEY,
      attributes: {
        client_id: clientId
      },
      enableDevMode: true,
      trackingCallback: (experiment, result) => {
        // track using GA4
        window.gtag("event", "experiment_viewed", {
          event_category: "experiment",
          experiment_id: experiment.key,
          variation_id: result.variationId,
        })
      }
    })
    // Load features from the GrowthBook API
    growthbook.loadFeatures()
  })
}

const render = () => {
  loadableReady(() => {
    const state = window.__APP_STATE__ || {}

    const client = createClient({ url: state.env.API_URL })
    client.hydrate(state.api)

    const loc = window.location
    const url = `${loc.origin}${loc.pathname === '/' ? '' : loc.pathname}`

    const appContext = <http://state.app|state.app> || {}

    const Root = (
      <Sentry.ErrorBoundary fallback={ErrorPage}>
        {/* potentially empty growthbook */}
        <GrowthBookProvider growthbook={growthbook}>
          <CookieProvider value={new Cookies()}>
            <ApiProvider client={client}>
              <HelmetProvider>
                <NotificationProvider>
                  <BrowserRouter>
                    <AppContext.Provider value={appContext}>
                      <App url={url} />
                    </AppContext.Provider>
                  </BrowserRouter>
                </NotificationProvider>
              </HelmetProvider>
            </ApiProvider>
          </CookieProvider>
        </GrowthBookProvider>
      </Sentry.ErrorBoundary>
    )

    hydrateRoot(document.getElementById('root'), Root )
  })
}
f

fresh-football-47124

08/11/2023, 9:17 PM
one way to avoid the lag between when google loads, is to use your own ID
you can generate it, and pass it to gtag as a custom identifier, or just pass it in the trackingCallback
you can store this ID in a long lived cookie too
n

nutritious-beach-21644

08/11/2023, 9:20 PM
What are the benefits of passing it to the gtag? what are the downsides of not passing it to the gtag?
Switched to the cookie strategy
Thanks @fresh-football-47124
2 Views