DEV Community

Cover image for How I created a live subscribers counter in NextJS (with source code)
Pierre Mouchan
Pierre Mouchan

Posted on

How I created a live subscribers counter in NextJS (with source code)

How I Created a Live Subscribers Counter in NextJS

Hey web developers,
I built an engaging feature on a newsletter subscription page to enhance the user experience and trust of my Obsibrain landing page. One intriguing way of doing this is by displaying a live subscriber counter. In this article, I will walk you through how I created such a feature using Next.js API and the Brevo API.

Introduction

In this tutorial, we will build a function that fetches the number of subscribers from Brevo and displays the total number on the front-end. Whenever there is a new subscriber, the counter will be updated in real-time.

First things first, the basic Next.js API route

This is the foundation of a Next.js API route.
The GET function is an asynchronous function that serves as the request handler for HTTP GET requests to this API endpoint.

This API route is located under:
app > api > get-subscriptions > route.ts

import type { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest, res: NextResponse) {
  // More code...
}
Enter fullscreen mode Exit fullscreen mode

Getting the Subscribers from Brevo

First things first, let's fetch the list of subscribers. We use the Brevo API for this purpose.
(explanation inside the code snippet)

Here's the code snippet:

import dotenv from 'dotenv'
import type { NextRequest, NextResponse } from 'next/server'

dotenv.config()

const BASE_URL = `https://api.brevo.com/v3`
const API_KEY = process.env.BREVO_API_KEY

// full url
const url = [BASE_URL, 'contacts'].join('/')

export async function GET(req: NextRequest, res: NextResponse) {
    try {
    // making the request with the required headers
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'Accept': 'application/json',
          'api-key': `${API_KEY}`,
        }
      })

      const data = await response.json()

    // checking for the response to be 'ok' and be successful
      if (!response.ok) {
        return new Response(JSON.stringify({ message: 'Error getting list of subscriptions' }), { status: 500 })
      }
    } catch (error) {
      return new Response(JSON.stringify({ message: 'Error getting list of subscriptions', error }), { status: 500 })
    }
}
Enter fullscreen mode Exit fullscreen mode

Invalidating on Each New Subscriber

To keep our subscriber list fresh and updated, we use the revalidation option provided by Next.js to invalidate the cached data and fetch fresh data periodically both on backend and frontend.

export const revalidate = 300

export async function GET(req: NextRequest, res: NextResponse) {
//...
}
Enter fullscreen mode Exit fullscreen mode

By setting revalidate to 300 seconds, the data will be revalidated every 5 minutes (backend) to ensure we are displaying the most current subscriber count.

const response = await fetch(url, {
        method: 'GET',
        headers: {
          'Accept': 'application/json',
          'api-key': `${API_KEY}`,
        },
        next: { tags: ['subscriptions'] }, // NextJS tags

      })
Enter fullscreen mode Exit fullscreen mode

The tags property is an array of strings that can be used to uniquely identify a request. This is particularly useful when you want to invalidate the cache for a specific request in the future.

This means that whenever the cache for this specific request needs to be invalidated (for example, when a new subscriber is added), Next.js can target this request by looking for the 'subscriptions' tag (used in frontend in our case but can be invalidated on backend as well).

import { revalidateTag } from 'next/cache'

revalidateTag('subscriptions') // revalidate the cache for the get-subscriptions route
Enter fullscreen mode Exit fullscreen mode

Returning the Data

Once we've fetched the subscriber data, the final step is to return this information in a structured format. The function wraps up the data in a JSON response that includes the total number of subscribers.

Here's the concluding part of the code:

return new Response(
  JSON.stringify({
    message: 'Subscriptions fetched successfully',
    data: { totalSubscriptions },
  }),
  { status: 200 },
)
Enter fullscreen mode Exit fullscreen mode

This structured response allows the front-end to easily consume the data and dynamically update the subscriber count, ensuring a live, optimized (with cache) and interactive user experience.

Any Questions?

If you have any questions about my setup or if you encounter any issues while implementing this feature, feel free to reach out. I'm more than happy to provide additional explanations, give advice, or help troubleshoot any problems you might run into.

Top comments (0)