reactjsnext.jsgoogle-tag-managergoogle-optimize

General problems with Google Optimize in React / Next.js


The title might seem a bit vague, but that's because I'm currently experiencing multiple problems integrating Google Optimize in our React / Next.js project. I'm going to try to explain my problems and actions as detailed as possible. However, let me know if something's unclear.

The problems:

  1. Although Google Optimize is added at the top of the head, we always experience a page flash. Meaning users first see our page, then nothing (async hide function kicks in), then the page again with changes.
  2. I've created an experiment that re-orders navigation links, removes one navigation link, and changes our CTA text. I've set the variant to 100% for testing purpose. What happens (related to problem 1), is that we first see our original webpage, then the changes, then again our original webpage with one navigation link removed. Meaning it added the variant, but removed some changes.
  3. When adding an experiment on a dynamic page, the changes cannot be applied. When I run the experiment, nothing changes, and when I re-open the visual editor, it says there are issues with the changes. Even if the change is just a simple text change.

What I've tried:

  1. Adding the "async-hide" className by default on html. This sets the webpage by default hidden. If I use Google Optimize synchronous, this works good. If I set it to async, however, it takes 1 to 2 seconds before it shows the page, which isn't good performance.
  2. I added Google Optimize in Google Tag Manager by following the exact steps mentioned by Google here. Yes, I did change the Google Optimize container ID in my async-hide function to GTM container ID.
  3. I undid part 2 above and added Google Optimize manually like this.
<Html lang="en" className="async-hide">
<Head>
  {/* 
    Google Optimize Ant-Flicker Snippet
    https://support.google.com/optimize/answer/9692472?ref_topic=6197443
  */}
  <style
    dangerouslySetInnerHTML={{
      __html: `.async-hide { opacity: 0 !important}`,
    }}
  />
  <script
    dangerouslySetInnerHTML={{
      __html: `
      (function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
      h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
      (a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
      })(window,document.documentElement,'async-hide','dataLayer',4000,
      {'OPT-OPTIMIZE_ID':true});
    `,
    }}
  />
  <script src="https://www.googleoptimize.com/optimize.js?id=OPT-OPTIMIZE_ID"></script>

  {/* Google Tag Manager */}
  <script async src="https://www.googletagmanager.com/gtm.js?id=GTM-TAGMANAGER_ID"></script>
  <script
    dangerouslySetInnerHTML={{
      __html: `
        (function(w,l){w[l]=w[l]||[];w[l].push({'gtm.start':
        new Date().getTime(),event:'gtm.js'});
        })(window,'dataLayer');
      `,
    }}
  ></script>
...
[rest of code]

Questions I'm having

  1. Is this problem related to Next.js? The fact that we work with static multipages in a react application instead of single page
  2. What is the best method to implement Google Optimize in a React / Next.js project: via Google Tag Manager or Google Optimize
  3. What is the best loading method for Google Optimize in a React / Next.js project: async or sync?

Solution

  • It's a quite common problem you're experiencing here. Google Optimize and other A/B testing solutions that change website content through Javascript on the client create a flicker effect, as the scripts have to be downloaded before it can change anything.

    To answer your questions:

    1. As you're working with next.js some special problems arise. Next.js uses a server (or static render phase) on the server as well as a hydration phase at the client side. When you place Google Optimize (and it loads) before the hydration started it will render the correct experiment but will get overwritten as soon as the hydration kicks in.

    2. How could you integrate it properly with Tagmanger: In the most outer component, e.x. <App/> you could use a useEffect() hook which throws a tagmanager event to trigger the insertion of the optimize experiement.

      !Please be aware! through this you will get a flicker effect or slow down your site as you have to wait until everything is hydrated which can take some seconds on slow devices and then will rerender your content.

      This is a common problem with Jamstack Pages - which can be solved through integration the experimentation api directly in the code which for sure is more complex.

    3. Sync loading will slow down you're site as it blocks the rendering until the JS and content is loaded, async loading will make the site flicker. That's the two options when working with tag based A/B testing - you have to choose the lesser evil.