Skip to content

RESOURCES / BLOG

Track Image Impressions in Gatsby.js with Supabase

How can we know if our efforts are worth the time and resources if we don’t measure the most crucial digital analytics metrics? Understanding and tracking the correct metrics is critical in ensuring that marketing activities are effective.

Impression as a form of metric refers to the number of times a web content was displayed to users. This metric vastly differs from reach, which only measures the number of people that have viewed your content. It is important not to confuse an impression with an engagement.

This article demonstrates how to track image impressions using Gatsby.js and Supabase — a serverless database.

We completed this project in CodeSandbox. Fork it to get started quickly.

The source code is on GitHub.

To get the most out of this article, the following requirements apply:

  • Basic understanding of Gatsby.js
  • Supabase account (sign up here)
  • Cloudinary account (sign up here)

Create a Gatsby.js app in a new folder by running the following command in the terminal:

    npm init gatsby

It will request a project title and the directory name for the project. Continue to follow the prompts to select a preferred language (JavaScript or TypeScript), CMS, styling tools, and other features. Then Gatsby.js will ask to create a Gatsby site in the directory of the project:

    Create a new Gatsby site in the folder <project-name>
    Shall we do this? <Y/n> : Yes
Code language: JavaScript (javascript)

Navigate into the project directory and install Cloudinary React SDK, Supabase, and react-intersection-observer dependencies.

    cd <project-name>
    npm install cloudinary-react @supabase/supabase-js react-intersection-observer
Code language: HTML, XML (xml)

Running npm run develop starts the project on the local development server at https://localhost:8000 in our browser.

Supabase is an open-source Firebase alternative made up of tools that help developers build projects faster by handling backend functions.

Behind the scenes, Supabase uses the PostgreSQL database and it is regarded widely as one of the best tools based on Postgres – a highly scalable relational database. The platform develops a REST API from the database’s tables and columns. Its autogenerated APIs include built-in features like filtering and sorting.

To get started, create an account in Supabase here. We’ll also need a GitHub account; click here to create one.

After logging in, we’ll be redirected to the Supabase dashboard, as shown below, where we’ll create a new Supabase project for the demo application.

image

Set a name and password for the new project and click on the “New project” button to create the project as shown below.

image

As the project is being built, we’ll create the database for the image impressions by clicking on the database icon shown on the sidebar. After that, click on the “New” button at the top right of the screen to create a table for the database.

image

We created multiple columns for the database table in the above image. The created columns represent the following:

  • id – key value to access the database
  • name – name of the database
  • created_at – time stamp for creating the database
  • views – number of image impressions

After creating these columns, we’ll access the Table editor by clicking the Table icon shown on the sidebar to add a default value for our table. Click on “insert row” and add the default values below.

image

Navigate to the SQL editor and create a query tab to add a stored procedure to our database. A stored procedure allows us to add or extend functionality to the database.

image

Add the code snippet below to the new query to create the stored procedure for our database:

    create function increment (row_id int)
    returns void as
    $$
      update pages
      set views = views + 1
      where id = row_id;
    $$ 
    language sql volatile;

Code language: JavaScript (javascript)

Let’s break down the query above:

  • Creates an increment function, with the row id as an argument
  • set views = views + 1 updates/increases the image impressions value called views in the database table by 1

Then, click the “RUN” button to create the function. Later we’ll utilize the function to update the image impressions.

Cloudinary is a cloud-based picture and video management service that includes uploads, storage, manipulations, optimizations, and distribution. It also enables developers to include video players in their apps that properly handle video events.

After successfully creating an account, Cloudinary will redirect us to our account’s dashboard page, where we can upload the demo image.

image

Click on the “Upload” button as shown above and select the image file to be uploaded.

In the index.js file, we’ll import the required components from Cloudinary React SDK and integrate the Cloudinary image, as shown below:

    //pages/components/index.js
    
    import React from "react";
    import { Image, CloudinaryContext } from "cloudinary-react";
    
    const IndexPage = () => {
    return(
    <CloudinaryContext cloud_name="OUR-CLOUD-NAME">
    <div className="image-container">
        <Image
         publicId="OUR-IMAGE-NAME"
         width="300px"
         height="400px"
        />
    </div>
    </CloudinaryContext>
    )};
    
    export default IndexPage;
Code language: JavaScript (javascript)

In the code above, we do the following:

  • Apply the Cloud name from our Cloudinary account details on the dashboard page
  • Include the name of the image from Cloudinary in the Image component
  • Give the image a width of 300px and a height of 400px

Next, we’ll loop through an array of dummy text to make the app look better:

    const IndexPage = () => {
    return(
     <main className="container">
          <title>Track Image impressions in Gatsby.js with Supabase</title>
          <h1>tracking image impressions in gatsby.js with supabase</h1>
          {Array.from(Array(5).keys()).map((i) => (
            <p key={i}>
              Irure pariatur velit est anim ipsum anim aliquip officia velit
              consectetur. Duis sint ut consectetur ea anim. Sit proident culpa
              velit officia do incididunt Lorem in deserunt non adipisicing occaecat
              magna. Occaecat occaecat esse excepteur consequat occaecat cupidatat
              aliquip labore esse ad ea. Laboris id excepteur nisi voluptate sunt
              anim commodo amet reprehenderit.
            </p>
          ))}
    
     // ... { Cloudinary Image }
    
      {Array.from(Array(8).keys()).map((i) => (
            <p key={i}>
              Irure pariatur velit est anim ipsum anim aliquip officia velit
              consectetur. Duis sint ut consectetur ea anim. Sit proident culpa
              velit officia do incididunt Lorem in deserunt non adipisicing occaecat
              magna. Occaecat occaecat esse excepteur consequat occaecat cupidatat
              aliquip labore esse ad ea. Laboris id excepteur nisi voluptate sunt
              anim commodo amet reprehenderit.
            </p>
          ))}
        </main>
      );
    };
    export default IndexPage;
Code language: JavaScript (javascript)

After configuring the dummy text, the demo application will look like this:

image

Integrating react-intersection-observer

react-intersection-observer is the React implementation of the Intersection Observer API that indicates when an element enters or leaves the viewport. It contains a hook, renders props, and plain children implementation.

It provides a useInView hook, which makes it easy to monitor the state of our components. We’ll use the custom InView component, which will be called whenever the state changes, with a ref that should be assigned to the element root. The InView component uses a default state of true or false, so if the image enters the viewport, its state is true, and if it leaves the viewport, its state is false.

//index.js

import React from "react";
import { Image, CloudinaryContext } from "cloudinary-react";

const IndexPage = () => {
return( 

//array of dummy text

<CloudinaryContext cloud_name="OUR-CLOUD-NAME">
    <InView>
          {({ ref }) => (
            <div className="image-container" ref={ref}>
              <Image
                publicId="OUR-IMAGE-NAME"
                width="300px"
                height="400px"
              />
            </div>
          )}
        </InView>
      </CloudinaryContext>

// array of dummy text

)};
export default IndexPage;
Code language: JavaScript (javascript)

We’ll need to link our Supabase API URL and API Key to the demo application. First off, head to Supabase’s settings, then go to the “API” section, where we can access our Supabase project’s API URL and API Key as shown below:

image

Then, create a .env file in the app’s root directory to store the API URL and API Key:

    #.env
    SUPABASE_URL= OUR_PUBLIC_SUPABASE_URL
    SUPABASE_KEY= OUR_PUBLIC_SUPABASE_KEY
Code language: PHP (php)

Next, we’ll add the API URL and API Key to the index.js file:

    //pages/components/index.js
    import { createClient } from "@supabase/supabase-js";
    
    const IndexPage = () => {
    const supabase = createClient(
      process.env.SUPABASE_URL,
      process.env.SUPABASE_KEY
    );
     return (
        // Cloudinary Image
    )};
Code language: JavaScript (javascript)

To update the Supabase database, we’ll create the function, endFunction, which is triggered anytime the state of the InView component changes. The function uses a Supabase Remote Procedure Call (RPC) to increase the number of impressions at Supabase’s database by 1:

    //index.js
    import React, { useState } from "react";
    import { Image, CloudinaryContext } from "cloudinary-react";
    
    const IndexPage = () => {
    const supabase = createClient(
      process.env.SUPABASE_URL,
      process.env.SUPABASE_KEY
    );
      const endFunction = async (inView) => {
        if (inView) {
          const { data, error } = await supabase.rpc("increment", { row_id: 1 });
        }
      };
     return (
        <CloudinaryContext cloud_name="OUR-CLOUD-NAME">
            <InView onChange={(inView) => endFunction(inView)}>
    
              // .....
    
            </InView>
          </CloudinaryContext>
    )};

Code language: JavaScript (javascript)

After testing the demo application, it should look like this:

image

This article discussed what Supabase is, the advantages of implementing it in applications, and, more importantly, how to integrate Supabase into web applications.

Start Using Cloudinary

Sign up for our free plan and start creating stunning visual experiences in minutes.

Sign Up for Free