If you blog a lot and have a lot of page views, you would also like to know how many of those page views are real users and users who read your post. Research varies, but generally, the average adult reads 200–250 words in one minute.

We will take 200 as a base.

Writing the logic

No need, there is a ton of javascript libs to use :)

My favourite is https://github.com/ngryman/reading-time

We will just take some parts of it and build our own single lib that pushes to GA.

Depending on your Shopify store, you will take a main div element(id or class name eg blog__article__content) which contains the content, trim it and call the function to calculate the read time. After you get the read time, call the timeout function that will call google analytic event after X time is passed (the X is the read time).

Sending to Google Analytics

We will measure events with analytics.js.

Events are user interactions with content that can be measured independently from a web page or a screen load. Downloads, mobile ad clicks, gadgets, Flash elements, AJAX embedded elements, and video plays are all examples of actions you might want to measure as Events.

You can find more information about it on Google Analytics documentation website. If the user is still on the page after the X time is passed, we will send event which contains the article name with action name called “read”. Now you can track which article is people tend to read!

Use it on your Shopify store

In your theme editor, on theme.liquid, add this code before </body> tag:

{% if article %}

<script type="text/javascript">
    (function () {

        var articleName = "{{article.title}}";
        //IMPORTANT! Change this to the class name of the div article content
        var articleContent = "blog__article__content";


        function init() {
            if (typeof gtag === 'function') {
                var content = document.getElementsByClassName(articleContent);
                if (content.length <= 0) {
                    console.error("No content found for class name " + articleContent);
                content = content[0].innerText.trim();
                var time = readingTime(content);
                if (time <= 0) {
                    console.error("Reading time is 0! Seems like no content or wrong class name");
                setTimeout(gTrack, time);
            } else {
                console.log('Not loaded');
                setTimeout(init, 500);

        function ansiWordBound(c) {
            return (
                (' ' === c) ||
                ('\n' === c) ||
                ('\r' === c) ||
                ('\t' === c)

        function readingTime(text, options) {
            var words = 0, start = 0, end = text.length - 1, wordBound, i

            options = options || {}

            // use default values if necessary
            options.wordsPerMinute = options.wordsPerMinute || 200

            // use provided function if available
            wordBound = options.wordBound || ansiWordBound

            // fetch bounds
            while (wordBound(text[start])) start++
            while (wordBound(text[end])) end--

            // calculate the number of words
            for (i = start; i <= end;) {
                for (; i <= end && !wordBound(text[i]); i++) ;
                for (; i <= end && wordBound(text[i]); i++) ;

            var minutes = words / options.wordsPerMinute;
            return minutes * 60 * 1000;

        function gTrack() {
            gtag('event', 'read', {
                'event_category': 'Article',
                'event_label': articleName



{% endif %}

Important: don’t forget to inspect your article class name for content and change to that name on line 8.

Now, open an article and start to read it. Good? Now, open again, but go through it fast. Done? Now check your GA events. What do you see?

Google Event

If you read your article as a normal person will do, you should see an Event Action called read with the article title under Event Label. That’s it! Now you need more data to filter and see which articles performs better and cross-reference with page views.