An impression is when any form of digital media appears on a user’s screen. Knowing what kind of content your users often view can help you focus on delivering better content to improve user experience.
This article demonstrates how to track image impressions using Intersection Observer API and store impression counts in your browser’s local storage.
According to MDN Docs:
“The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport.”
With this API, you can track your images and execute a callback function when each image comes into view on your browser.
NuxtJS is an open-source framework that enhances the capabilities of VueJS with features such as fast server-side rendering, pre-configurations, and a large ecosystem of modules. All these tools provide an excellent developer experience.
Click the CodeSandbox link below to view a complete demo of the content presented in this article:
https://codesandbox.io/embed/silly-curie-89ek8e?fontsize=14&hidenavigation=1&theme=dark
To view its source code on GitHub, click here.
To understand the concepts presented in this article, you need the following:
- Good knowledge of JavaScript and VueJS.
- Experience with NuxtJS is not strictly required, but it will make things easier.
- Create a free Cloudinary account to store, manipulate, and deliver your images.
In your terminal, navigate to your preferred project folder and run the command below to set up Nuxt for the project:
npx create-nuxt-app nuxt-image-impressions
You will be prompted with selections to aid project setup. Choose based on the recommendations below:
After a successful setup, open the project in your preferred code editor, and run the command below in its terminal:
yarn dev
This will set up a dev environment with hot reload that you can view on your browser at localhost:3000
.
In your project, navigate to pages/index.vue
and update <script>
with the code below:
<script>
export default {
name: 'IndexPage',
data() {
return {
count: 0,
poems: [
{
text: `Low-anchored cloud, Newfoundland air, fountain head and source of rivers, dew-cloth, dream drapery, and napkin spread by fays; Drifting meadow of the air, where bloom the dasied banks and violets, and in whose fenny labyrinth the bittern booms and heron wades; Spirit of the lake and seas and rivers, bear only perfumes and the scent Of healing herbs to just men's fields! - Henry David Thoreau`,
imageUrl: `https://res.cloudinary.com/dpkreativ/image/upload/v1646749176/wallpapers/mist.jpg`,
imageAlt: `mist`,
},
{
text: `Last night I drove a car, not knowing how to drive; not owning a car, I drove and knocked down people I loved...went 120 through one town. I stopped at Hedgeville and slept in the back seat... excited about my new life. - Gregory Corso`,
imageUrl: `https://res.cloudinary.com/dpkreativ/image/upload/v1646483551/wallpapers/car.jpg`,
imageAlt: `car`,
},
{
text: `As your screen began to fade & flicker, and I shut you down & closed your cover, I knew all you needed was a little rest; I am so sorry for putting you to the test, but I cannot get through a day without you; You know how much I need you in all I do; You knew I would just die without your light; Good little laptop you gave me such a fright - Tia Maria`,
imageUrl: `https://res.cloudinary.com/dpkreativ/image/upload/v1646695756/wallpapers/laptop.jpg`,
imageAlt: `laptop`,
},
],
}
},
}
</script>
In the code above, data()
returns a count
variable with its initial value at 0; it also returns an array of objects accessed by the variable poems
.
You will use this data to set up the project’s markup dynamically.
In your pages/index.vue
, update <template>
with the code below:
<template>
<div>
<nav class="sticky top-0 bg-white font-bold text-2xl p-5 shadow">
<h1>Impressions: {{ count }}</h1>
</nav>
<div class="w-full max-w-4xl p-5 mx-auto">
<div v-for="(poem, idx) in poems" :key="idx"
class="grid lg:grid-cols-12 gap-4 min-h-screen content-center"
>
<div class="lg:col-span-7">
<div>
<img :src="poem.imageUrl" :alt="poem.imageAlt"
class="w-full" />
</div>
</div>
<div class="lg:col-span-5">
<p class="text-xl">{{ poem.text }}</p>
</div>
</div>
</div>
</div>
</template>
In this step, you created a sticky nav
to display the image impressions when you begin tracking them. You also used v-for
to iterate through the poems
array, showing each of the poems and their images.
In Vue/Nuxt applications, you can implement the Intersection Observer API manually or use [vue-intersection-observer](https://www.npmjs.com/package/vue-intersection-observer)
, a component that greatly simplifies the process.
To install, run the command below in your project’s terminal:
yarn add vue-intersection-observer
After its successful installation, update <script>
in your pages/index.vue
with the code below:
<script>
import Observer from 'vue-intersection-observer'
export default {
// pre-existing code, add the new ones below
components: {
Observer,
},
methods: {
onChange(entry) {
if (entry.isIntersecting) {
this.count = this.count + 1;
}
}
}
}
</script>
In the code above:
- You imported
Observer
fromvue-intersection-observer
and specified it as a component. -
entry.isIntersecting
checks whether the specified element is in view and runs theonChange
function to update the impressioncount
.
Next, update your <template>
code to implement the Observer
component on the images you want to track:
<template>
<!-- pre-existing code, update only parent div for img element -->
<observer @on-change="onChange">
<img :src="poem.imageUrl" :alt="poem.imageAlt" class="w-full" />
</observer>
</template>
In the code above:
- You changed the parent
<div>
of your<img />
element to<observer>
. - You added an
@on-change
attribute to execute the callback function when the view is active.
When you scroll up and down in your browser, you will notice that the number of image impressions is being recorded and displayed on the nav
, as shown below:
To store your impression counts in localStorage
, navigate to pages/index.vue
and update methods:
in your <script>
with the code below:
<script>
export default {
// pre-existing code
methods: {
onChange(entry) {
if (entry.isIntersecting) {
this.count = this.count + 1
localStorage.setItem('Impressions', this.count)
}
}
}
}
</script>
In your browser, check your localStorage to be sure it works:
In this article, you learned how to track impressions in your Nuxt project with Intersection Observer API and store impression counts in your browser’s local storage. To learn more about these concepts, check out the resources below.