title: gtag / google_tag_manager confusion
body: <p>I am using Google Analytics to track custom events in my react application. When I first rolled out the code, I read <a href="https://developers.google.com/analytics/devguides/collection/gtagjs/migration" rel="nofollow noreferrer">this document</a>, suggesting use of <code>gtag</code> method instead of <code>ga</code> method to make the logging calls. This has been working fine.</p>
  
  <p>I am using Google Tag Manager, so these scripts are all loaded via GTM (presumably).</p>
  
  <p>Now I'm doing something a bit trickier, the server needs to tell the client to log on page load in a particular case. So I have adapted the GTM initialization code such that an event fires once GTM has loaded. I read how to do that <a href="https://www.simoahava.com/analytics/notify-page-google-tag-manager-loaded/" rel="nofollow noreferrer">here</a>.</p>
  
  <p>The strange thing is that when the callback indicating the GTM library has loaded fires <code>gtag</code> is not defined and the code to log an event in Analytics fails. By the time I can type <code>gtag</code> in the browser console it's defined, so perhaps the GTM script is loading it secondarily?</p>
  
  <pre><code>if (!!window.google_tag_manager) {
    // Google Tag Manager has already been loaded
    doSomethingWith(window.google_tag_manager);
  } else {
    window.addEventListener('gtm_loaded', function() {
      //----------------------------------------
      // Google Tag Manager has been loaded, but
      // gtag object is not defined :(
      //----------------------------------------
    });
  }
  </code></pre>
  
  <p>Is there some other way to log Analytics events with the <code>google_tag_manager</code> object? Or, is there a way to know when the <code>gtag</code> object is available short of polling (really want to avoid that)?</p>
  
  <p>This is the code I'm using to load GTM</p>
  
  <pre><code>class InitDataLayer extends Component {
      componentDidMount = () =&gt; {
          window.dataLayer = [{
              appName: 'promos',
          }];
      }
      render = () =&gt; (&lt;script id="init-data-layer" /&gt;)
  }
  
  class LoadGtm extends Component {
      componentDidMount = () =&gt; {
          (function(w,d,s,l,i) {
              w[l]=w[l]||[];
              w[l].push({
                  'gtm.start': new Date().getTime(),
                  event:'gtm.js'
              });
              var f=d.getElementsByTagName(s)[0],
                  j=d.createElement(s),
                  dl=l!='dataLayer'?'&amp;l='+l:'';
                  j.async=true;
                  j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
                  f.parentNode.insertBefore(j,f);
  
              j.addEventListener('load', () =&gt; {
                  const _ge = new CustomEvent('gtm_loaded', { bubbles: true });
                  d.dispatchEvent(_ge);
              });
          })(window,document,'script','dataLayer','GTM-XXXXXXX');
      }
      render = () =&gt; (&lt;script id="load-gtm" /&gt;)
  }
  </code></pre>