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
) before loading GB seems insurmountable at this point. It seems to me like using a conditional to check that the
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
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

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

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

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

    const appContext = <|> || {}

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

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


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


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