Skip to main content

Overview

Plausible Analytics can be integrated with any modern web framework. This guide covers common integration patterns for popular frameworks and provides framework-specific examples.

General Approach

All frameworks support one or both of these integration methods:
  1. Script Tag - Add the Plausible script to your HTML template
  2. NPM Package - Install @plausible-analytics/tracker and initialize programmatically
The NPM package only works in browser environments. For SSR frameworks, ensure tracking code runs client-side only.

React

Create React App

Add the script to public/index.html:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script defer data-domain="yourdomain.com" 
      src="https://plausible.io/js/script.js"></script>
    <title>My App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

React Router

For single-page applications with React Router, pageviews are automatically tracked when using the NPM package. For manual pageview tracking:
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { track } from '@plausible-analytics/tracker';

function usePageViews() {
  const location = useLocation();

  useEffect(() => {
    track('pageview');
  }, [location]);
}

function App() {
  usePageViews();
  
  return (
    // Your app
  );
}

Custom Events in React

import { track } from '@plausible-analytics/tracker';

function SignupButton() {
  const handleSignup = () => {
    track('Signup', {
      props: {
        plan: 'premium',
        method: 'email'
      },
      callback: () => {
        console.log('Event tracked');
      }
    });
  };

  return <button onClick={handleSignup}>Sign Up</button>;
}

Next.js

App Router (Next.js 13+)

Add to app/layout.tsx:
import Script from 'next/script'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <head>
        <Script
          defer
          data-domain="yourdomain.com"
          src="https://plausible.io/js/script.js"
        />
      </head>
      <body>{children}</body>
    </html>
  )
}

Pages Router (Next.js 12 and earlier)

Add to pages/_app.js:
import Script from 'next/script'

function MyApp({ Component, pageProps }) {
  return (
    <>
      <Script
        defer
        data-domain="yourdomain.com"
        src="https://plausible.io/js/script.js"
      />
      <Component {...pageProps} />
    </>
  )
}

export default MyApp

Tracking Route Changes

Next.js App Router automatically triggers pageviews on route changes. For Pages Router with manual tracking:
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import { track } from '@plausible-analytics/tracker'

function MyApp({ Component, pageProps }) {
  const router = useRouter()

  useEffect(() => {
    const handleRouteChange = () => track('pageview')
    router.events.on('routeChangeComplete', handleRouteChange)
    return () => router.events.off('routeChangeComplete', handleRouteChange)
  }, [router.events])

  return <Component {...pageProps} />
}

Vue.js

Vue 3

Add to public/index.html:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script defer data-domain="yourdomain.com" 
      src="https://plausible.io/js/script.js"></script>
    <title>My Vue App</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

Vue Router

Track route changes:
import { createRouter, createWebHistory } from 'vue-router'
import { track } from '@plausible-analytics/tracker'

const router = createRouter({
  history: createWebHistory(),
  routes: [...]
})

router.afterEach(() => {
  track('pageview')
})

export default router

Custom Events in Vue

<template>
  <button @click="handleSignup">Sign Up</button>
</template>

<script>
import { track } from '@plausible-analytics/tracker'

export default {
  methods: {
    handleSignup() {
      track('Signup', {
        props: {
          plan: 'premium'
        }
      })
    }
  }
}
</script>

Nuxt.js

Nuxt 3

Create a plugin at plugins/plausible.client.ts:
import { init } from '@plausible-analytics/tracker'

export default defineNuxtPlugin(() => {
  init({
    domain: 'yourdomain.com'
  })
})
The .client suffix ensures it only runs on the client side.

Nuxt 2

Create plugins/plausible.client.js:
import { init } from '@plausible-analytics/tracker'

export default () => {
  init({
    domain: 'yourdomain.com'
  })
}
Register in nuxt.config.js:
export default {
  plugins: [
    { src: '~/plugins/plausible.client.js', mode: 'client' }
  ]
}

Astro

Add the script to your base layout:
---
// src/layouts/Layout.astro
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script defer data-domain="yourdomain.com" 
      src="https://plausible.io/js/script.js"></script>
    <title>My Astro Site</title>
  </head>
  <body>
    <slot />
  </body>
</html>
For client-side tracking with NPM:
---
// src/components/Analytics.astro
---

<script>
import { init } from '@plausible-analytics/tracker'

init({
  domain: 'yourdomain.com'
})
</script>

Svelte / SvelteKit

SvelteKit

Add to src/routes/+layout.svelte:
<script>
  import { onMount } from 'svelte'
  import { init } from '@plausible-analytics/tracker'

  onMount(() => {
    init({
      domain: 'yourdomain.com'
    })
  })
</script>

<slot />
Or use the script tag in src/app.html:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script defer data-domain="yourdomain.com" 
      src="https://plausible.io/js/script.js"></script>
    %sveltekit.head%
  </head>
  <body>
    %sveltekit.body%
  </body>
</html>

Angular

Add to src/index.html:
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <script defer data-domain="yourdomain.com" 
    src="https://plausible.io/js/script.js"></script>
  <title>My Angular App</title>
</head>
<body>
  <app-root></app-root>
</body>
</html>
For NPM package with router tracking:
import { Component } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { init, track } from '@plausible-analytics/tracker';
import { filter } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  constructor(private router: Router) {
    init({ domain: 'yourdomain.com' });

    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd)
    ).subscribe(() => {
      track('pageview');
    });
  }
}

Gatsby

Install the plugin:
npm install gatsby-plugin-plausible
Configure in gatsby-config.js:
module.exports = {
  plugins: [
    {
      resolve: 'gatsby-plugin-plausible',
      options: {
        domain: 'yourdomain.com'
      }
    }
  ]
}

WordPress

For WordPress sites, use one of these methods:
  1. Official Plugin - Install the Plausible Analytics WordPress plugin from the plugin directory
  2. Manual Integration - Add the script tag to your theme’s header
  3. Theme Functions - Add via functions.php:
function add_plausible_analytics() {
  ?>
  <script defer data-domain="yourdomain.com" 
    src="https://plausible.io/js/script.js"></script>
  <?php
}
add_action('wp_head', 'add_plausible_analytics');

Static Site Generators

Jekyll

Add to _includes/head.html:
<script defer data-domain="{{ site.domain }}" 
  src="https://plausible.io/js/script.js"></script>

Hugo

Add to layouts/partials/head.html:
<script defer data-domain="{{ .Site.Params.domain }}" 
  src="https://plausible.io/js/script.js"></script>

Eleventy (11ty)

Add to your base layout:
<script defer data-domain="yourdomain.com" 
  src="https://plausible.io/js/script.js"></script>

Single Page Applications (SPAs)

For SPAs, the tracker automatically detects URL changes via:
  • history.pushState
  • history.replaceState
  • Hash changes (with hashBasedRouting: true)
No additional configuration needed when using autoCapturePageviews: true (the default).

Hash-based Routing

For apps using hash-based routing (e.g., #/page):
init({
  domain: 'yourdomain.com',
  hashBasedRouting: true
})
Or with script tag:
<script defer data-domain="yourdomain.com" 
  src="https://plausible.io/js/script.hash.js"></script>

Server-Side Rendering (SSR)

The Plausible tracker only works in browser environments. For SSR frameworks, ensure initialization happens client-side only.

Detecting Client-Side

import { init } from '@plausible-analytics/tracker'

if (typeof window !== 'undefined') {
  init({
    domain: 'yourdomain.com'
  })
}

Testing

When testing your integration:
1

Enable Localhost Tracking

init({
  domain: 'yourdomain.com',
  captureOnLocalhost: true
})
2

Check Browser Console

Open DevTools and look for Plausible-related messages.
3

Verify Network Requests

Check the Network tab for POST requests to /api/event with status 202.
4

Use Real-time Dashboard

Visit your Plausible dashboard to see live visitor count.

Next Steps

Tracker Script

Full tracker configuration reference

Custom Events

Track custom goals and conversions

Custom Properties

Add metadata to your events

Events API

Server-side event tracking

Build docs developers (and LLMs) love