<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: theItalianDev</title>
    <description>The latest articles on DEV Community by theItalianDev (@theitaliandev).</description>
    <link>https://dev.to/theitaliandev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F795370%2Fe33d55aa-dbd7-401c-a665-b93b7a036ecb.png</url>
      <title>DEV Community: theItalianDev</title>
      <link>https://dev.to/theitaliandev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theitaliandev"/>
    <language>en</language>
    <item>
      <title>How to add Google Analytics to Next.js using the Script Component (🙏 Stop using inline script)</title>
      <dc:creator>theItalianDev</dc:creator>
      <pubDate>Mon, 17 Jan 2022 10:18:37 +0000</pubDate>
      <link>https://dev.to/theitaliandev/how-to-add-google-analytics-to-nextjs-using-the-script-component-stop-using-inline-script-3kec</link>
      <guid>https://dev.to/theitaliandev/how-to-add-google-analytics-to-nextjs-using-the-script-component-stop-using-inline-script-3kec</guid>
      <description>&lt;p&gt;If you are going to use Next.js for your future project, or you've already deployed a Next.js web app,  &lt;strong&gt;please be sure that the Google Analytics script is not added via an inline script ⚠️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/wfv1wVwt74kmI/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/wfv1wVwt74kmI/giphy.gif" alt="please gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's widely known that the &lt;strong&gt;website loading performance&lt;/strong&gt; hugely impacts on User Experience and, since the &lt;a href="https://web.dev/vitals/" rel="noopener noreferrer"&gt;latest Google Algorithm updates&lt;/a&gt;, on SEO (Search Engine Optimization).&lt;/p&gt;

&lt;p&gt;We can literally make our website &lt;strong&gt;fall down&lt;/strong&gt; in Google SERPs rankings if we don't follow the best practices in loading strategy of third-party scripts. Going deep into the complex world of third-party scripts is out of the scope of this guide, if you want to read more about it I suggest  &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript" rel="noopener noreferrer"&gt;this amazing article.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So now you may be wondering: Which is the "right way" to add Google Analytics script to a Next.js website?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/dXICCcws9oxxK/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/dXICCcws9oxxK/giphy.gif" alt="That is an excellent question question gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The answer comes directly from  &lt;a href="https://nextjs.org/docs/messages/next-script-for-ga" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are using the gtag.js script to add analytics, use the 'next/script' component with the right loading strategy to defer loading of the script until necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks to the &lt;a href="https://nextjs.org/docs/basic-features/script" rel="noopener noreferrer"&gt;Next.js Script Component&lt;/a&gt; we can choose the &lt;strong&gt;right load strategy&lt;/strong&gt; and defer the load of the Google Analytics script until necessary, so it will no longer be able to render-block and delay any page content from loading. 🥳&lt;/p&gt;

&lt;h2&gt;
  
  
  Globally Inject Google Analytics Script in Next.js
&lt;/h2&gt;

&lt;p&gt;Navigate to Google Analytics website and grab the Measurement ID. If you don't have one, all you have to do is to create a new Data Stream.&lt;/p&gt;

&lt;p&gt;-----&amp;gt; Admin ----&amp;gt; Data Streams&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642370811919%2FQEibPr_wj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642370811919%2FQEibPr_wj.png" alt="data streams.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;----&amp;gt; Web&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642370919953%2F27HqGIDao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642370919953%2F27HqGIDao.png" alt="choose web.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add your website url&lt;/li&gt;
&lt;li&gt;Add your website name&lt;/li&gt;
&lt;li&gt;Click Create Stream button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642371194645%2F-G3TK0iHZ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642371194645%2F-G3TK0iHZ.png" alt="create stream.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy the Measurement ID &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642371448732%2F2RUvb8rc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642371448732%2F2RUvb8rc5.png" alt="measurement id and script.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's open now the Next.js project into Visual Studio Code and create (if you don't already have one) a &lt;code&gt;.env.local&lt;/code&gt; file (at root level) so we can set our Measurement ID inside an &lt;a href="https://nextjs.org/docs/basic-features/environment-variables" rel="noopener noreferrer"&gt;Environment Variable&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_MEASUREMENT_ID: 'xxxxxx Your measurement id xxxxxx'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NEXT_PUBLIC prefix is needed to let our Next.js app know that this env variable has to be &lt;strong&gt;exposed to the browser.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that we have our Measurement ID set up inside and env variable, we can &lt;strong&gt;globally inject&lt;/strong&gt; the Google Analytics script code via the &lt;strong&gt;Next.js Script Component&lt;/strong&gt; and define in it our loading strategy.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;pages/_app.js&lt;/code&gt; file type/paste 🤫  the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import '../styles/globals.css'
import Script from 'next/script'

function MyApp({ Component, pageProps }) {
  return(
    &amp;lt;&amp;gt;
      &amp;lt;Script src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_MEASUREMENT_ID}`} strategy='afterInteractive' /&amp;gt;
      &amp;lt;Script id="google-analytics" strategy='afterInteractive'&amp;gt;
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());

          gtag('config', '${process.env.NEXT_PUBLIC_MEASUREMENT_ID}');
        `}
      &amp;lt;/Script&amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;
    &amp;lt;/&amp;gt;
  ) 
}

export default MyApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see the &lt;strong&gt;two Script Components handle the script code&lt;/strong&gt; taken from the Google Analytics website, as shown in the image above, inject it globally (since the MyApp component exported from the _app.js wraps the entire app) and load it in base of the  value passed inside the &lt;code&gt;strategy&lt;/code&gt; prop.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;strategy&lt;/code&gt; prop accepts three possible loading strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;beforeInteractive&lt;/li&gt;
&lt;li&gt;afterInteractive&lt;/li&gt;
&lt;li&gt;lazyOnload&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;afterInteractive&lt;/code&gt;, the loading strategy we've chosen, is the one &lt;a href="https://nextjs.org/docs/messages/next-script-for-ga" rel="noopener noreferrer"&gt;suggested by Next.js&lt;/a&gt; to handle the Google Analytics script. What it does is to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Load immediately after the page becomes interactive&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; prop we pass inside the second Script Component is a &lt;strong&gt;unique arbitrary attribute&lt;/strong&gt; we are obliged to set in order to allow Next.js track and optimize, under the hood, all the scripts it needs to handle and load. Imagine a common scenario in which you have multiple third-party scripts loaded by multiple Script Components (for ex. Ads, Social Media Widget, Cookie Consent Banner etc etc), having these unique ids for each of them will let Next.js &lt;em&gt;"organize its work"&lt;/em&gt; to handle them in the best and fastest way (just like the unique &lt;code&gt;key&lt;/code&gt; prop we need to pass for each &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; tag inside a list).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hei hei hei!!! Where are you going now?!?! We are not done yet!!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/KVDpqMY28c2M40hRIp/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/KVDpqMY28c2M40hRIp/giphy.gif" alt="not done yet gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a custom function to track pageviews
&lt;/h2&gt;

&lt;p&gt;Now that the Google Analytics script is globally injected we need to define a &lt;strong&gt;custom function to track pageviews&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s a common practice to put all the third-party library related code into a &lt;strong&gt;separate folder&lt;/strong&gt;. So, always starting at the root level of our project, let's create this folders structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642375994760%2FoNwjj8vCu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642375994760%2FoNwjj8vCu.png" alt="folder structure.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;index.js&lt;/code&gt; we define and export an anonymous function named &lt;code&gt;pageview&lt;/code&gt;, that takes an &lt;code&gt;url&lt;/code&gt; as parameter. Inside this function we call the &lt;code&gt;gtag&lt;/code&gt; method on the &lt;code&gt;window&lt;/code&gt; object, and pass to &lt;code&gt;gtag&lt;/code&gt; three arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;'config'&lt;/li&gt;
&lt;li&gt;our measurement id via env variable&lt;/li&gt;
&lt;li&gt;an options object in which we assign the value &lt;code&gt;url&lt;/code&gt; to the key &lt;code&gt;path_url&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const pageview = (url) =&amp;gt; {
    window.gtag('config', process.env.NEXT_PUBLIC_MEASUREMENT_ID, {
        path_url: url,
    })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Subscribe and listen to Next.js Router &lt;code&gt;routeChangeComplete&lt;/code&gt; event
&lt;/h2&gt;

&lt;p&gt;We still have one problem to face to let Google Analytics &lt;strong&gt;know how to track pageviews&lt;/strong&gt; when someone on our website is browsing between &lt;strong&gt;different pages/routes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/1wnK5Qgwj6OkkckCv5/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/1wnK5Qgwj6OkkckCv5/giphy.gif" alt="we can fix this gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to go back to &lt;code&gt;pages/_app.js&lt;/code&gt; and make the magic happen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import '../styles/globals.css'
import {useEffect} from 'react'
import {useRouter} from 'next/router'
import Script from 'next/script'

import * as ga from '../lib/google-analytics'

function MyApp({ Component, pageProps }) {
  const router = useRouter()

  useEffect(() =&amp;gt; {
    const handleRouteChange = (url) =&amp;gt; {
      ga.pageview(url)
    }

    router.events.on('routeChangeComplete', handleRouteChange)
    return () =&amp;gt; {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [router.events])
  return(
    &amp;lt;&amp;gt;
      &amp;lt;Script src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_MEASUREMENT_ID}`} strategy='afterInteractive' /&amp;gt;
      &amp;lt;Script id="google-analytics" strategy='afterInteractive'&amp;gt;
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());

          gtag('config', '${process.env.NEXT_PUBLIC_MEASUREMENT_ID}');
        `}
      &amp;lt;/Script&amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;
    &amp;lt;/&amp;gt;
  ) 
}

export default MyApp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to the &lt;code&gt;useRouter&lt;/code&gt; hook we can use the router object inside the &lt;code&gt;_app.js&lt;/code&gt; and subscribe to the Next.js Router &lt;code&gt;routeChangeComplete&lt;/code&gt; event. This event fires when a route change process is completed (as the name suggests 😅). &lt;/p&gt;

&lt;p&gt;We can subscribe to it calling the &lt;code&gt;on&lt;/code&gt; method on &lt;code&gt;router.events&lt;/code&gt; and, passing the &lt;code&gt;pageview&lt;/code&gt; custom function (previously created), we let Google Analytics know how track pageviews on pages/routes changes.&lt;/p&gt;

&lt;p&gt;The subscription to this event is done inside a &lt;code&gt;useEffect&lt;/code&gt; hook that fires at any &lt;code&gt;router.events&lt;/code&gt; change. As you can see &lt;code&gt;router.events&lt;/code&gt; is the second argument passed to &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To avoid any memory leak we return from &lt;code&gt;useEffect&lt;/code&gt; a clean up function in which we unsubscribe from &lt;code&gt;routeChangeComplete&lt;/code&gt; event calling the &lt;code&gt;off&lt;/code&gt; method on &lt;code&gt;router.events&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Google Analytics script is now successfully integrated into our Next.js app!! 🥳&lt;/p&gt;

&lt;h3&gt;
  
  
  GTmetrix analysis
&lt;/h3&gt;

&lt;p&gt;Time for a little test! &lt;/p&gt;

&lt;p&gt;Try to analyze your Next.js app with a free tool like &lt;a href="https://gtmetrix.com/" rel="noopener noreferrer"&gt;GTmetrix&lt;/a&gt; to check if what we have done so far works properly.&lt;/p&gt;

&lt;p&gt;In the waterfall section of Gtmetrix (selecting the JS tab) you can easily see that the Google Analytics script is loaded only after all the scripts that the web app needs to execute first to be interactive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642379642467%2FD1WE60PyZ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1642379642467%2FD1WE60PyZ.png" alt="gtmetrix.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So it is clear how the Google Analytics script is not render-blocking and delaying any page content from loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add Google Analytics to Next.js - YouTube Video from my YT Channel
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/DT8vx50Asrk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Feel free to check out my Youtube Channel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCPfnsyDEXALlgqZaQXpLpYg" rel="noopener noreferrer"&gt;https://www.youtube.com/channel/UCPfnsyDEXALlgqZaQXpLpYg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;p.s: I hope this guide could be useful to you. For any suggestion please comment in the section down below.&lt;/p&gt;

&lt;p&gt;Thank you for reading. From the bottom of my heart.&lt;br&gt;
theItalianDev&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>analytics</category>
    </item>
  </channel>
</rss>
