DEV Community

Privatus Analytics
Privatus Analytics

Posted on

How to Add Privacy-Friendly Analytics to a Next.js App in 5 Minutes (No Cookie Banner)

You ship a Next.js app. You want to know if anyone uses it. So you add Google Analytics.

Then the trouble starts. You add a cookie pop-up, because the tool tracks people. Some visitors click "no". Their visits vanish from your numbers. Other visitors just get annoyed and leave. The reports are slow and hard to read. And every visit is sent to Google, which you may not want to do to your users.

There is a simpler way. In this tutorial you will add a small analytics script to a Next.js app. It sets no tracking cookies. It filters out bots. It takes about five minutes.

We will use Privatus Analytics. It is a web analytics tool that does not use cookies. Other tools like Plausible, Fathom and Umami work in a similar way, so pick what fits you. I will show the steps for Privatus Analytics because that is what I know best.

What you need

  • A Next.js app. Either the App Router or the Pages Router works.
  • A free Privatus Analytics account. The free plan gives you 10,000 events a month and up to 3 sites. You do not need a card.

An "event" is one thing that gets counted, like a page view or a button click.

Step 1: Add your site and copy the site ID

Sign in and add your site. You will get a site ID that looks like pa_7Q2K9XH3AB. Copy it. It is not a secret. It is printed in the page for everyone to see, just like the ID of any other analytics tool.

The Add a site guide shows each click if you get lost.

Step 2: Put your site ID in an environment variable

Open .env.local in the root of your project and add this line:

NEXT_PUBLIC_PA_SITE_ID=pa_YOURSITEID
Enter fullscreen mode Exit fullscreen mode

Swap in your real ID. The NEXT_PUBLIC_ part is a Next.js rule. It tells Next.js that this value may be used in the browser.

Restart your dev server after you save the file. Next.js only reads this file when it starts.

Step 3: Add the script (App Router)

Open app/layout.tsx. Add the Script component from next/script:

import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          defer
          src="https://privatusstats.com/js/pa.js"
          data-site={process.env.NEXT_PUBLIC_PA_SITE_ID}
          data-modules="engage,auto,vitals,clicks,ask"
          strategy="afterInteractive"
        />
      </body>
    </html>
  )
}
Enter fullscreen mode Exit fullscreen mode

Let me explain the parts:

  • src is the tracking script.
  • data-site tells the script which site the numbers belong to.
  • data-modules turns on extra features. engage measures time on a page and how far people scroll. vitals measures how fast your pages feel. clicks records where people click. If you only want page views, you can remove this line. The script attributes page lists every option.
  • strategy="afterInteractive" makes Next.js load the script after the page is ready. It will not slow down your first paint.

Using the Pages Router instead?

Put the same <Script> in pages/_app.tsx:

import type { AppProps } from 'next/app'
import Script from 'next/script'

export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Script
        defer
        src="https://privatusstats.com/js/pa.js"
        data-site={process.env.NEXT_PUBLIC_PA_SITE_ID}
        strategy="afterInteractive"
      />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Check that page changes are counted

Next.js does not reload the whole page when someone clicks a link. It changes the page with JavaScript. Many old analytics setups miss these clicks.

You do not need extra code here. The script follows these changes by default. The setting is called data-spa and its default is auto. So a visitor who clicks through five pages is counted as five page views.

Step 5: Test it on your computer

By default the script does not send anything from localhost. This keeps your own testing out of your numbers. But then you see nothing while you build.

To see what would be sent, add data-debug="true" to the script for now:

<Script
  defer
  src="https://privatusstats.com/js/pa.js"
  data-site={process.env.NEXT_PUBLIC_PA_SITE_ID}
  data-debug="true"
  strategy="afterInteractive"
/>
Enter fullscreen mode Exit fullscreen mode

Open your browser console and click around. The script prints each hit instead of sending it. Remove data-debug when you are happy.

Then deploy. Visit your live site and look at the dashboard. The Verify the installation guide tells you what a good result looks like.

Step 6 (optional): Track a button click

Page views are a good start. But you may want to know how many people click "Upgrade". The script puts a small object on window.privatus. You call track on it.

Make a client component:

'use client'

export function UpgradeButton() {
  return (
    <button
      onClick={() => window.privatus?.track('Upgrade', { plan: 'pro' })}
    >
      Upgrade
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode

The ?. means "only call this if it exists". So your button still works if a visitor uses an ad blocker.

The second part, { plan: 'pro' }, is a property. It is extra detail that you can later use to split your numbers, like "Upgrade clicks by plan".

If you use TypeScript, you will see an error because window.privatus is not known. The JavaScript API page has a short type declaration you can copy.

About the cookie pop-up

The Privatus Analytics script does not set tracking cookies. So the script itself does not need a cookie pop-up. The only thing it can store in the browser is a small "do not track me" flag, and only if a visitor asks for it.

Rules about this are different in each country, and your other tools may still need a pop-up. So check the rules where your visitors live. But for your analytics, there is one less thing to ask people about.

Why bots matter

Many numbers in old analytics tools are padded with bots. These are programs that visit your pages. They are not people. Privatus Analytics checks every visit against rules for known crawlers, test tools, and servers in big data centers. Bots are kept out of your reports and do not count against your event limit. The bot filtering page lists every rule.

What you get

  • A working analytics setup in one file, with no extra packages
  • Page views that follow Next.js page changes
  • No tracking cookies, so no pop-up for this tool
  • Bot visits filtered out of your numbers
  • Optional click and button tracking with one line of code
  • Visitor data that is not sent to Google
  • A free plan with 10,000 events a month and up to 3 sites, no card needed

Try it

You can set this up on a side project tonight. The free plan needs no card, and the script is one tag. Start at privatusanalytics.com and see the pricing page for what each plan includes.

The Next.js guide is in the docs. If you find a problem, the tracker code and plugins live in the Privatus Analytics GitHub organization.

Top comments (0)