0

I would like to keep track of page views count for each page that a user visits so I can only fire tags (via GTM) if the page view count is < 2.

This is the structure of my desired localStorage:

Key: {PageTitle1: pageViewCount, PageTitle2: pageViewCount, PageTitle3: pageViewCount}

And this is an example of how it could look like in reality:

PageViewCounter: {Home Page: 8, Blog: 64, Contact Page: 2}

On each page it loads, it would either increment the numerical value of the counter (if the Page Name already exists in the localStorage) or append the new page with value of 1 to the object (if the Page Name doesn't yet exist in the localStorage).

I have tried:

//If it doesn't, create it and set it to 1
  else if (!localStorage.PageViewCounter) {
    console.log('PageViewCounter does not exist, setting to 1...');
    PageViewCounter = 1;
    
    var PageTitle = document.title;  
    PageAndCounter = {
      PageTitle: PageViewCounter
    }
    
    localStorage.setItem('PageViewCounter', JSON.stringify(PageAndCounter));
}

But the PageTitle doesn't get the value from the variable but rather saves it as PageTitle: 1. I have also tried putting it into an array like this:

PageAndCounter = {
    [PageTitle: PageViewCounter]
}

But I am using Google Tag Manager and it won't allow me to use this feature.

Error at line 6, character 3: This language feature is only supported for ECMASCRIPT_2015 mode or better: const declaration.

If this isn't possible, I will just create a new localStorage entry for each page visited, but I assume that's not a good practice?

puk789
  • 322
  • 2
  • 8
  • 28
  • Maybe it lets you do `PageAndCounter = {}; PageAndCounter[PageTitle] = PageViewCounter;` instead? (https://stackoverflow.com/q/4244896/1427878) – CBroe Mar 14 '23 at 11:55

2 Answers2

1

You will need to parse, modify, and then re-stringify the JSON data.

Here is a basic example using two HTML pages i.e. "Home" and "About":

script.js

const incrementCount = (key, propAccessor) => {
  const existing = localStorage.getItem(key) ?? "{}", // Get or default
    parsed = JSON.parse(existing), // Parse JSON string to object
    prop = propAccessor(); // How to obtain obj prop/key
  parsed[prop] = (parsed[prop] ?? 0) + 1; // Increment by 1
  localStorage.setItem(key, JSON.stringify(parsed)); // Update stored value
};

const incrementPageCount = () => {
  incrementCount("PageViewCounter", () => document.title);
};

home.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Home</title>
    <meta name="description" content="Home" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script type="text/javascript" src="./script.js"></script>
    <script type="text/javascript">
      incrementPageCount(); // Run function
    </script>
  </head>
  <body></body>
</html>

about.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>About</title>
    <meta name="description" content="About" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script type="text/javascript" src="./script.js"></script>
    <script type="text/javascript">
      incrementPageCount(); // Run function
    </script>
  </head>
  <body></body>
</html>

Updated script

Here is a more polished script the breaks each process down into individual functions:

const localStorageReducer = (storageKey, producer, defaultValue = {}) => {
  const existing = localStorage.getItem(storageKey),
    obj = existing ? JSON.parse(existing) : defaultValue;
  producer(obj);
  localStorage.setItem(storageKey, JSON.stringify(obj));
};

const incrementCount = (storageKey, accessor, initialValue = 0) =>
  localStorageReducer(storageKey, (obj) => {
    const prop = accessor(obj);
    obj[prop] = (obj[prop] ?? initialValue) + 1;
  });

const incrementPageCount = () =>
  incrementCount("PageViewCounter", (_ref) => document.title);

Legacy script

Here is a legacy version of the script above:

function localStorageReducer(storageKey, producer, defaultValue) {
  if (defaultValue === undefined) {
    defaultValue = {};
  }
  var existing = localStorage.getItem(storageKey);
  var obj = existing !== undefined ? JSON.parse(existing) : defaultValue;
  producer(obj);
  localStorage.setItem(storageKey, JSON.stringify(obj));
}

function incrementCount(storageKey, accessor, initialValue) {
  if (initialValue === undefined) {
    initialValue = 0;
  }
  localStorageReducer(storageKey, function (obj) {
    var prop = accessor(obj);
    if (obj[prop] === undefined) {
      obj[prop] = initialValue;
    }
    obj[prop] += 1;
  });
}

function incrementPageCount() {
  incrementCount("PageViewCounter", (_ref) => document.title);
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • Thank you so much, but Google Tag Manager keeps turning it down because it's not supported in older browsers :/ I guess there's no other (compatible/old school) way of achieving the same, right? – puk789 Mar 14 '23 at 12:56
  • @puk789 I created a legacy version of the final script and added it at the bottom. – Mr. Polywhirl Mar 14 '23 at 13:39
0

Use square bracket notation to set the key dynamically;

{[key]:value}

In your case:

PageAndCounter = {
[PageTitle]: PageViewCounter
}

There are two ways to access properties of an object:

  • Dot notation: something.bar

  • Bracket notation: something['bar']

The value between the brackets can be any expression. Therefore, if the property name is stored in a variable, you have to use bracket notation: