@openmost/nuxt-matomo

Matomo Tag Manager for Nuxt, powered by Nuxt Scripts
6,806 4
Install
npm install @openmost/nuxt-matomo
Latest Version:3.0.0
Vue:3
License:MIT
Last Updated:Oct 19, 2026
Links: GitHub  ·  npm
Maintainer: ronan-hello

Matomo for Nuxt

npm version npm downloads License Nuxt

Matomo Tag Manager for Nuxt 4.1+, built on top of Nuxt Scripts.

Features

  • 🚀 Loads your Matomo Tag Manager container with Nuxt Scripts: non-blocking by default (onNuxtReady), shows up in Nuxt DevTools, SSR-safe.
  • 🧭 Single-page app page views that just work: a page_view event with the resolved URL, referrer and final page title is pushed on every navigation, so your Matomo tag never records a stale title.
  • 🍪 Consent-friendly: set trigger: 'manual' and load the container once the visitor opts in.
  • ☁️ Self-hosted and Matomo Cloud: the container URL is resolved for you.
  • 🧩 Typed composables for events, goals, custom dimensions, custom variables, site search and the data layer.
  • ⚙️ Environment variables: every option can be overridden at runtime with NUXT_PUBLIC_MATOMO_*.

Quick setup

Install the module (Nuxt Scripts comes with it and is registered for you):

npm install @openmost/nuxt-matomo

Then add it to your modules with your Matomo URL and container id:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@openmost/nuxt-matomo'],
  matomo: {
    host: 'https://matomo.example.com',
    containerId: 'aBcD1234',
  },
})

That's it: the container loads on every page, and a page_view event is pushed on every navigation. Follow Configure your container once in Matomo so those page views are tracked.

Options

Option Env var Default Description
host NUXT_PUBLIC_MATOMO_HOST none Your Matomo URL, e.g. https://matomo.example.com or https://example.matomo.cloud.
containerId NUXT_PUBLIC_MATOMO_CONTAINER_ID none Your Tag Manager container id (Tag Manager → Install code).
trigger NUXT_PUBLIC_MATOMO_TRIGGER 'onNuxtReady' When the container loads: 'onNuxtReady', 'client' (as soon as possible) or 'manual'.
dataLayerName NUXT_PUBLIC_MATOMO_DATA_LAYER_NAME 'dataLayer' The queue useDataLayerPush and the page_view event write to ('dataLayer' or '_mtm').
pageViewEvent none true Push a page_view event to the data layer on every page.

Environment variables override nuxt.config at runtime, so one build can target several environments:

NUXT_PUBLIC_MATOMO_HOST=https://matomo.example.com
NUXT_PUBLIC_MATOMO_CONTAINER_ID=aBcD1234

Container URL

The container URL is built for you:

host Container URL
https://matomo.example.com https://matomo.example.com/js/container_<id>.js
https://example.matomo.cloud https://cdn.matomo.cloud/example.matomo.cloud/container_<id>.js

If your Install code shows another URL (for example a custom domain on Matomo Cloud), copy it into src:

useScriptMatomoTagManager({
  src: 'https://cdn.example.com/container_aBcD1234.js',
})

Configure your container

Matomo Tag Manager's default Page view trigger only fires on the first page load. The module pushes a page_view event on every navigation instead, once the destination page has rendered its title:

dataLayer.push({
  event: 'page_view',
  page_url: '/about',         // route fullPath
  referrer_url: '/',          // previous route fullPath ('' on the first page)
  page_title: 'About us',     // document.title, after useHead / useSeoMeta
})

In your Matomo Tag Manager container:

  1. Read the data layer. Either enable Synchronize with GTM Data Layer events in the container settings (default dataLayerName: 'dataLayer'), or set dataLayerName: '_mtm' to push directly into Matomo's own queue.
  2. Create two Data-Layer variables: DLV - page_url (name page_url) and DLV - page_title (name page_title).
  3. Create a Custom Event trigger CE - page_view with the event name page_view.
  4. Edit your Matomo Analytics tag: set Custom Page URL to {{DLV - page_url}}, Custom Page Title to {{DLV - page_title}}, and replace its Page view trigger with CE - page_view so each page is tracked once.
  5. Publish a new container version.

Consent

Set trigger: 'manual' so the container never loads on its own, then load it when the visitor accepts:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@openmost/nuxt-matomo'],
  matomo: {
    host: 'https://matomo.example.com',
    containerId: 'aBcD1234',
    trigger: 'manual',
  },
})
<script setup lang="ts">
const { load, status } = useScriptMatomoTagManager()
</script>

<template>
  <button v-if="status !== 'loaded'" @click="load()">
    Accept analytics
  </button>
</template>

Commands pushed to _mtm and _paq before consent stay queued and are processed once the container loads.

Composables

All composables are auto-imported and safe to call during SSR (they do nothing on the server).

useScriptMatomoTagManager

The Nuxt Scripts instance of your container. Without arguments, it returns the container registered by the module.

const { status, load, proxy } = useScriptMatomoTagManager()

// Push to Matomo Tag Manager's queue, even before the container has loaded
proxy._mtm.push({ event: 'newsletter_signup' })

useDataLayerPush

Pushes any payload to the configured data layer (window.dataLayer by default).

useDataLayerPush({ event: 'cta_click', label: 'hero' })

useMatomoEvent

Tracks an event. The 5th argument holds optional custom dimensions.

useMatomoEvent('Category', 'Action', 'event_name', 23, { dimension1: 'Some value' })

useMatomoGoal

Converts a goal, with an optional revenue.

useMatomoGoal(4)
useMatomoGoal(4, 49.9)

useMatomoCustomDimension

Sets a custom dimension value.

useMatomoCustomDimension(1, 'premium')

useMatomoCustomVariable

Sets a custom variable, scoped to the 'page' (default) or the 'visit'.

useMatomoCustomVariable(1, 'plan', 'pro', 'visit')

useMatomoSearch

Tracks an internal site search: keyword, category (or false) and result count.

useMatomoSearch(query.value, 'docs', results.value.length)

useMatomoEvent, useMatomoGoal, useMatomoCustomDimension, useMatomoCustomVariable and useMatomoSearch push to window._paq, which is read by the Matomo Analytics tag of your container.

Upgrade from v2

  • Nuxt 4.1 or later is required.
  • The container is now loaded by Nuxt Scripts, once the app is ready (trigger: 'onNuxtReady'). Set trigger: 'client' to load it as early as v2 did.
  • The page_view event payload is unchanged. Set pageViewEvent: false to disable it.
  • runtimeConfig.public.matomo and the NUXT_PUBLIC_MATOMO_* env vars keep working.

Contributing

npm install
npm run dev:prepare   # generate type stubs
npm run dev           # start the playground on http://localhost:3000
npm run lint
npm run test
npm run test:types

The playground serves a fake container from playground/public/js, so you can try every feature without a Matomo instance.

Related Packages

vue3-matomo

A Vue 3 and Nuxt 3 plugin for Matomo Analytics.

13,580 4
@databuddy/nuxt

Official Databuddy Nuxt module

2,572 1,204
nuxt-matomo

Matomo analytics for Nuxt.js

18,183 85
@gbbluspark/nuxt-matomo

Matomo analytics for Nuxt.js

2,596 0
nuxt-hubspot

HubSpot analytics integration for Nuxt with typesafe event tracking and DevTools...

1,165 0

Version History

Version Released Vue License
3.0.0 ^3.0 MIT
2.2.0 ^3.0 MIT
2.1.4 ^3.0 MIT
2.1.2 ^3.0 MIT
2.1.1 ^3.0 MIT