John Schmidt
Posted on January 6, 2021
I was looking for a pure, lightweight and privacy-friendly way to get simple stats about my personal homepage. I ruled out Google Analytics as they sustain little issues with privacy, and it does not fit into the mentioned attributes. So, what's out there in the market? Until this point, I've come across the following:
- umami (self-hosted, open source),
- Simple Analytics (paid),
- Fathom Analytics (paid),
- Splitbee (paid),
- and Plausible (paid or self-hosted, open source)
If possible, I'd rather avoid a paid service (at least for now). Having used umami for a client project recently being quite fond of it, I've moved to Plausible, an open-source project based in the European Union, for this project. Plausible offers a pretty clean self-hosting setup via Docker. Alternatively, they offer a paid managed service on their own platform for those who prefer.
Either via plausible.io or self-hosted - after creating your site in the Plausible dashboard you're provided with a simple <script>
tag looking somewhat like this:
<script
async
defer
data-domain="johnschmidt.de"
src="https://stats.johnschmidt.cloud/js/plausible.js"
/>
Of course the src
and data-domain
attributes might differ depending on your setup. That's all you need from Plausible itself.
Setting up Your Application
In your Next.js project we need to modify the custom document /pages/_document.js
file. There's a few possible approaches to implement the tracker. In this case I implemented it manually. However, there is a small package providing you with a <PlausibleProvider>
wrapper. The simplest approach is by adding the <script>
tag in the <Head>
component.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class HomepageDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang='en'>
<Head>
<script
async
defer
data-domain='johnschmidt.de'
src='https://stats.johnschmidt.cloud/js/plausible.js'
/>
</Head>
<body className='antialiased dark:bg-black dark:text-white'>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default HomepageDocument
In the easiest scenario this would be it - you're good to go. The script will be included into the app bundle on every page. Once deployed, the script will automatically run the tracker function and count visitors and page views. The results will be displayed in the Plausible dashboard almost instantly.
Avoiding Counts in Preview Deployments
_There's just this one little caveat: _Plausible does not differ between the domain or referring URL (yet) you call the script from. Using Vercel or Netlify for your deployments, you might use preview URLs quite frequently. A visit to one of these would trigger an event like in the production environment. As far as I was able to evaluate, there's essentially two options to avoid:
- exclude yourself from tracking on the client-side or
- include the script only on the desired production URL (e.g. johnschmidt.de)
The First option could be achieved with a custom rule in a script-blocking extension of sorts (e.g. uBlock, Adblock Plus). The second approach is a bit trickier at the time of writing. To avoid the <script>
to render in the preview URLs we need to include the snippet conditionally, based on the current hostname. The Window
object can provide this information quite simply in window.location.hostname
. It'll be offered as a string. This moves the code from /pages/_document.js
to /pages/_app.js
since we need to check our conditions on the client-side.
import Head from 'next/head'
function HomepageApp({ Component, pageProps }) {
return (
<>
<Head>
{typeof window !== 'undefined' &&
window.location.hostname === 'johnschmidt.de' && (
<script
async
defer
data-domain='johnschmidt.de'
src='https://stats.johnschmidt.cloud/js/plausible.js'
/>
)}
</Head>
<Component {...pageProps} />
</>
)
}
export default HomepageApp
Before reading the window.location.hostname
parameter we need to make sure that it is only called in a client-side setting. We can check if the Window
object is defined and render the script tag conditionally. Since Next.js statically generates our page on the server-side, it would try to call the Window
object in a Node.js environment - albeit Window
does not exist there. Once a visitor opens our app on the production URL, the script should be rendered on hydration and Plausible can start collecting your events as usual.
Wrapping up
Plausible provides a good alternative to Google Analytics, especially on the privacy side of things. The only downside is the fairly narrow adjustability within a continuous deployment environment like Vercel or Netlify. With a little tweak however, it can work like a charm. For a small project like this homepage, it seemed like one of the best solutions to get lightweight stats and baseline analytics.
Since this is my first post of this kind, let me know if this post was helpful to you and reach out to me on Twitter (@jope_sh) with feedback and ideas!
Posted on January 6, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.