Articles with the tag Javascript

Add Google Analytics To A Nuxt Js App

3 years ago Fri, Oct 2, 2020

Over recent weeks, I've been working hard to make this blog look and work well. Now that I'm writing more often, I wanted a way to see what's working and what's not. My first thought was to add Google Analytics as I remember it being a quick and easy process.

That said, the days when you could just add analytics without thinking about the privacy of your users is thankfully coming to an end. As it turns out, some more work is needed to comply with GDPR and other legislation. In this article, I'll show you how I went about adding Google Analytics and a compliant Cookie Banner to this site.

If you've installed Google Analytics on a website in the past, you might be familiar with the analytics.js script. Google has now moved away from this script in favour of its gtag.js or Global Site Tag solution. They strongly recommend that we should upgrade to the new "modern measurement library" and so we'll do just that.

#Install GTAG on a simple HTML website

If you're looking to install gtag on a simple HTML website, you can simpy follow Google's instructions to paste the following code immediately after the <head> tag on every page of your site, making sure to replace GA_MEASUREMENT_ID with the Google Analytics property that you want to send the data to.

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'GA_MEASUREMENT_ID');
</script>

If you're using a templating engine, you can paste the code in of your layout file, so that it is loaded automatically on every page that uses that layout.

#Installing GTAG in a Nuxt JS app

Nuxt allows you to customise the app html template by creating an app.html file in the src directory of your project. We could easily place the gtag.js script there, but we can do better than that by pulling in a small npm package that wraps the gtag script. I've chosen to use vue-gtag, but you could use the same technique with another package if you prefer.

  1. Install vue-gtag in your application:
npm install vue-gtag
  1. Create a new javascript file in the plugins directory and load the vue-gtag plugin, making sure to replace the following properties with your own:
  • GA_MEASUREMENT_ID - the ID of the property to which you want to send data.
  • APP_NAME - The name of your application.
import Vue from 'vue';
import VueGtag from 'vue-gtag';

Vue.use(VueGtag, {
    config: { id: 'GA_MEASUREMENT_ID' },
    appName: 'APP_NAME',
});
  1. Tell Nuxt to load your Google Analytics plugin.
plugins: [
    {
        src: './plugins/GoogleAnalytics.js',
        mode: 'client'
    }
]

At this point, the gtag.js script should load on all pages and environments in your app, but you really shouldn't stop here. Read on to find out how to make sure you only load the script once you have obtained the consent of your users.

#GDPR, PECR and EU cookie compliance

When you install gtag.js, Google will place cookies in the user's browser to track the user uniquely. There are three things we need to do to make sure that we comply with PECT, GDPR, and other similar regulations as well as Google's own terms. Let's discuss each of these in turn.

  1. Tell visitors to our site that we are using cookies.

The convention is to add a banner to inform users that the site uses cookies. The banner should load immediately when the user first visits the site.

Cookie Banner Cookie Banner

  1. Explain what the cookies are doing and why.

The cookie banner should have a link to a clear explanation describing the cookies that will be used as well as their purpose. This will help the user to make an informed decision.

Privacy Policy Privacy Policy

  1. Get the user's consent before placing cookies on their device.

The banner should be displayed until the user specifies whether they accept the use of cookies. If they click yes, we can go ahead and load the analytics plugin which will store cookies on their device. If they click no, we will prevent the analytics tracker from loading. In both cases, we will remove the banner once the user has made their choice.

Now we know what needs to be done, we can make a CookieAlert vue component to add the banner to our site. I'm using Tailwind CSS for styling, but you can change the template to suit your needs.

First, we will define the way the banner should look in the template tag of our component:

    <div v-if="isOpen"
         class="fixed bottom-0 left-0 lg:flex items-center p-4 bg-gray-100 shadow-sm justify-center w-full">
        <div class="text-5xl pb-2 leading-none">
            🍪
        </div>
        <div class="lg:mx-8">
            <p>
                Can I use cookies for analytics? Read
                <nuxt-link class="text-link" to="/privacy-policy">the privacy policy</nuxt-link>
                for more information.
            </p>
        </div>
        <div class="flex justify-center mt-4 lg:mt-0">
            <div class="button ml-2 md:ml-0" @click="accept">Yes, sure</div>
            <div class="button md:ml-2" @click="deny">&times;</div>
        </div>
    </div>

Next, we will add a data property to track whether the cookie banner should be shown:

data() {
    return {
        isOpen: false
    };
}

We can now create a method to call when the user denies our request to use cookies. If the clicks deny, then we will hide the banner and save their preference to local storage.

deny() {
    if (process.browser) {
        this.isOpen = false;
        localStorage.setItem('GDPR:accepted', false);
    }
}

Similarly, we can create a method to call when the user accepts our request to use cookies. If the user clicks accept, we will hide the banner, save their preference to local storage and bootstrap the vue-gtag plugin.

import {bootstrap} from 'vue-gtag';

export default {
    methods: {
        accept() {
            if (process.browser) {
                bootstrap().then(gtag => {
                    this.isOpen = false;
                    localStorage.setItem('GDPR:accepted', true);
                    location.reload();
                })
            }
        },
        ...
    },
}

We should also make sure the component knows whether the banner should be shown when it is first loaded.

created() {
    if (!this.getGDPR() === true) {
        this.isOpen = true;
    }
},

methods() {
    getGDPR() {
        if (process.browser) {
            return localStorage.getItem('GDPR:accepted', true);
        }
    },
    ...
}

You may be wondering what the bootstrap method is doing here. Happily, vue-gtags allows us to load the plugin conditionally. This means the script will only load when we want it to. Lets' head back to our own analytics plugin and modify the code like this:

import Vue from 'vue';
import VueGtag from 'vue-gtag';

const getGDPR = localStorage.getItem('GDPR:accepted');

Vue.use(VueGtag, {
    config: { id: 'GA_MEASUREMENT_ID' },
    bootstrap: getGDPR === 'true',
    appName: 'APP_NAME',
    enabled: getGDPR === 'true',
});

You can read more about this in the vue-gtag documentation.

#Tracking page views

Since we are using vue-router as part of Nuxt JS, we can pass the application router to vue-gtag so that it can associate tracking information with the specific page the user is viewing.

import Vue from 'vue';
import VueGtag from 'vue-gtag';

export default ({ app }) => {
    const getGDPR = localStorage.getItem('GDPR:accepted');

    Vue.use(VueGtag, {
        config: { id: 'GA_MEASUREMENT_ID' },
        bootstrap: getGDPR === 'true',
        appName: 'APP_NAME',
        enabled: getGDPR === 'true',
        pageTrackerScreenviewEnabled: true
    }, app.router);
}

#Conclusion

Google Analytics is undoubtedly easy to install, but it takes a bit more work to inform your users that you are using cookies to track their use of your website and give them the option to opt out entirely. This process has made me think about whether this really is the right solution for me. I've been looking into cookie-free, privacy-focused tracking solutions and hope to be able to remove Google Analytics soon. I'd love to hear about how you measure visits to your blog and whether you've used any cookie-free solutions.

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading

Add Comments To Your Blog In Under Five Minutes

3 years ago Sat, Feb 8, 2020

While reading a blog post on web mentions I noticed that the author, Freek Van der Herten was using a comment system that I had never seen before. It looked very similar to a GitHub issue, which piqued my interest. After some digging, I found that it was powered by a free and open source tool called Utterances.

Utterances provides a GitHub app and a lightweight script to embed a comment widget on your website. When Utterances loads, it will use the GitHub API to find a matching issue based on one of the following criteria:

  • the article pathname
  • the site url
  • the page title
  • the page open graph title
  • a specific issue number
  • an issue title containing a specific term

The comments from that issue are displayed inline on your site as you can see in the comment section at the bottom of this article.

#Who is this for?

Before we jump into installation instructions, I thought it best to mention that this tool is not for everyone. Utterances will require users to be signed in with a valid GitHub account to post a comment. This means that it is better suited to technical and software development blogs or sites whose users are familiar with GitHub. If you are catering to a wider audience, it is probably better to use a more generic solution such as Disqus or Commento.

#Installation

Follow these steps to install the Utterances comment widget on your site:

  1. Create a new public GitHub repository. Be sure to make it public, or your readers will not be able to see the comments.

Create a new public GitHub repository Create a new public GitHub repository

  1. Head over to https://github.com/apps/utterances to install the GitHub app and give Utterances permission to access your public repository.

Utterances permissions Utterances Permissions

  1. Use the tool at https://utteranc.es/ to configure the comment section to match the style of your site. Once you have configured your options, you will see and be able to copy a script that looks something like this:
<script src="https://utteranc.es/client.js"
            repo="carlcassar/blog-comments"
            issue-term="pathname"
            theme="github-light"
            crossorigin="anonymous"
            async>
  1. Paste the script into your code. The widget will be loaded at the location at which you paste the code snippet.

You should now be able to see the comment section and sign in to post a comment. After this, you can go to the issues tab of your public repository where you will see that Utterances has created a new issue. From now on, Utterances will synchronise issues between GitHub and your site.

#Nuxt / Vue sites

This blog, carlcassar.com, is built using the Vue.js base framework, Nuxt JS. There are several ways to add external scripts to a Nuxt project.

First, Nuxt allows you to add a file called app.html in the root directory of your project. In this file, you can modify the template into which Nuxt will inject your code. In my case, this option was not a viable solution as I only want the comment section to load on blog articles and not on every page of the site.

Ordinarily, Nuxt also lets you inject external scripts in the scripts property of the head() method. In this case, however, Utterances does not let you specify which div to attach the comment section to, which means that this method will load the Utterances widget in the head tag of the page, rendering it invisible.

The solution I ended up using was to simply copy and paste the auto-generated script tag into the view component for this page adding the attribute type="application/javascript".

<script type="application/javascript"
        src="https://utteranc.es/client.js"
        repo="carlcassar/blog-comments"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async>
</script>

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading

Reset Data In A Vue Component

4 years ago Tue, Jan 1, 2019

Data is declared on a vue component using a function that returns the initial data object. Vue will recursively convert the properties of the data object to getters and setters to make it ‘reactive’. It is often useful to be able to reset this data to its original state (the way it was when the component was initialised). It might not be immediately obvious how to do this, so we’ll take a look at two good options.

#1. Create an initial data function

Let’s imagine that we have the following data structure:

data() {
    return {
        a: 1,
        b: 2,
        c: 3
    }
}

Instead of setting the initial values of a, b, and c in the declaration of the data function, we can create a method that stores their initial value:

methods: {
    initialState() {
        return {
            a: 1,
            b: 2,
            c: 3,
        }
    },
},

We can then set the data to this initial state:

data() {
    return this.initialState();
}

Now that we have a handle on the original data, we can reset the data to its original state by mapping each property to its original state:

methods: {
    reset() {
        this.a = this.initialState().a,
        this.b = this.initialState().b,
        this.c = this.initialState().c
    },
},

Or even easier, we can reset all properties at once:

methods: {
    reset() {
        Object.assign(this.$data, this.initialState());
    },
},

#2. Get the original data state from the component object

Now that we have seen how we can use an initial state function, we can look at another method to achieve the same result. A component’s data is stored on the component in the $options property. Let’s assume, once again, that we have declared the following data on a component:

data() {
    return {
        a: 1,
        b: 2,
        c: 3
    }
}

We can reset the data to its initial state in the following way:

methods: {
    reset() {
        Object.assign(this.$data, this.$options.data());
    },
},

Although we have set the data to its original state, we have one more thing to consider. this.$options.data() does not bind the current context (this) into the data() function, so if we tried to reference this in the data function, we would get an error. To get around this, we can bind the current context into the data function as follows:

methods: {
    reset() {
        Object.assign(this.$data, this.$options.data.apply(this);
    },
},

Both of the options we have looked at have their pros and cons. Whilst it might be easier to get the data from the $options object, an initial state method can be useful for resetting some of the options and not others.

#Credit and References

  1. Stack Overflow
  2. GitHub Issue
  3. Credit also goes to my work colleague, who originally showed me how to use the initial state method.

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading

Prop Destructuring In Vue Js

5 years ago Tue, Aug 21, 2018

In a couple of recent tweets, Caleb Porzio demonstrated an easy way to pass Javascript object properties to a child component without declaring a separate prop for each property.

Here's how it works. Let's say that we have a Javascript object with several properties in the data object of a Vue JS component:

data() {
    return {
        post: {
            id: 1,
            name: 'Prop destructuring in Vue Js',
            author: 'Carl Cassar'
        }
    };
}

Imagine that you want to pass this data to a child component. One way of doing it, is to declare a prop for each of the object's properties and pass each one through individually.

<post :id="post.id" :name="post.name" :author="post.author"> </post>

Whilst there is nothing wrong with this approach, it is also possible to pass through the whole object at once by using the v-bind directive.

<post v-bind="post"></post>

Behind the scenes, Vue will 'destructure' the post object and pass through each property to the 'post` component as a prop.

props: {
    id: Number,
    name: String,
    author: Object
}

As you can see, this still allows us to validate the prop and set a sensible default as we would normally.

In the interest of giving credit where credit is due, here's the original tweet with Caleb's great tip:


You can see all of the uses for the v-bind directive in the docs and follow @calebporzio on Twitter. He's been posting some great tips recently and is well worth following.

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading