@jaseeey/vue-umami-plugin
v1.6.0
Published
A plugin designed for Vue 3 which enables the use of Umami Analytics
Readme
Vue Umami Plugin
The Vue Umami Plugin integrates Umami analytics by loading the library and injecting it into your application's DOM, allowing you to easily track page views and events.
Background and Scope
This library was created to reduce duplication and streamline the integration of Umami analytics into a number of my personal Vue projects. Though, I decided to share it with the community in the hope that others may find it useful for similar purposes, either as-is, or as a starting point.
Given its focused nature, the plugin has limitations and may lack functionality available through the official Umami library API.
Features
- Automatic Page Tracking: Automatically track page views through your Vue router.
- Event Tracking: Easily track custom events with minimal configuration.
- Lazy Loading: The Umami script is loaded only when the document is ready, ensuring minimal impact on performance.
- Queue System: Events are queued until the Umami script is loaded, with the oldest items dropped once the configurable queue limit is reached.
- Full Tracker Configuration: Forward any Umami tracker option (custom host, allowed domains, Core Web Vitals performance tracking, and more) to the injected script via
extraDataAttributes.
Requirements
- Vue 3.x
- Vue Router (optional, for automatic page tracking)
Installation
To install and use this plugin, you can include the library via npm:
npm install @jaseeey/vue-umami-pluginModule Format Support (ESM + CJS)
This library ships dual builds and uses conditional exports:
dist/esmfor ESM consumersdist/cjsfor CommonJS consumers
Consumers should always import from the package root. Runtime/module resolution will select the correct build automatically.
import { VueUmamiPlugin, trackUmamiEvent } from '@jaseeey/vue-umami-plugin';const { VueUmamiPlugin, trackUmamiEvent } = require('@jaseeey/vue-umami-plugin');Avoid importing from dist/esm or dist/cjs directly.
Usage
To use the Vue Umami Plugin in your project, import it and use it within your Vue application setup:
import { createApp } from 'vue';
import { VueUmamiPlugin } from '@jaseeey/vue-umami-plugin';
import App from './App.vue';
import router from './router';
const app = createApp(App);
app.use(
VueUmamiPlugin({
websiteID: 'YOUR_UMAMI_WEBSITE_ID',
scriptSrc: 'https://us.umami.is/script.js', // Optional
router,
// Optional, defaults to false. Keep false with a router so the
// plugin's router.afterEach hook is the page-view source.
// Enable true without a router to use Umami's native auto-tracking.
// autoTrack: false,
// Optional, defaults to false. When true, logs successful
// plugin load events to the console.
// debug: false,
// Optional, defaults to 100 (must be >= 1):
// oldest queued events are dropped if the limit is reached,
// including calls queued before installation.
// maxQueuedEvents: 100,
// Optionally forward any Umami tracker option to the injected
// <script> tag. See the "Tracker Configuration" section below and
// https://docs.umami.is/docs/tracker-configuration
// extraDataAttributes: {
// 'data-host-url': 'https://stats.mywebsite.com',
// 'data-domains': 'mywebsite.com,mywebsite2.com',
// ... etc.
// }
})
);
app.use(router).mount('#app');Tracking Events
To track custom events:
import { trackUmamiEvent } from '@jaseeey/vue-umami-plugin';
trackUmamiEvent('button-click', { buttonName: 'subscribe' });Identifying Sessions
import { identifyUmamiSession } from '@jaseeey/vue-umami-plugin';
identifyUmamiSession({
userId: 'alice',
email: '[email protected]',
name: 'Alice Smith',
});
identifyUmamiSession('alice-123', {
email: '[email protected]',
name: 'Alice Smith',
});TypeScript
Plugin and helper types are exported so you can type shared config objects:
import {
VueUmamiPlugin,
type UmamiPluginOptions,
type UmamiRouterLike,
} from '@jaseeey/vue-umami-plugin';
const umamiOptions: UmamiPluginOptions = {
websiteID: 'YOUR_UMAMI_WEBSITE_ID',
router,
autoTrack: false,
};
app.use(VueUmamiPlugin(umamiOptions));Why router uses structural types (UmamiRouterLike)
The optional router option is typed as UmamiRouterLike, not as Vue Router's
Router type from the vue-router package. That is deliberate:
No
vue-routerdependency. Automatic page tracking is optional. Projects that only calltrackUmamiEvent/trackUmamiPageViewshould not needvue-routerinstalled for this plugin to typecheck or install cleanly.No version pinning. Importing
Router(even as a peer dependency) would couple consumers to a specific major range ofvue-router. Structural typing only requires the small surface the plugin actually uses, so Vue Router 4.x (and compatible future majors or adapters) keep working without a package upgrade solely for types.Honest contract. At runtime the plugin only calls
router.afterEachand readsto.fullPath. The public types describe that contract:UmamiRouterLike— object withafterEach(handler)UmamiRouteLike— object withfullPath
A real Vue Router instance satisfies both, so you pass
routeras usual. Test doubles and custom routers that implement the same shape also work.
Using a vue-router peerDependency would only signal an optional
integration; it would not remove the need for that package to resolve when
publishing or consuming types that re-export Router. Structural types avoid
that trade-off for this narrow integration.
Tracker Configuration
This plugin injects Umami's tracking <script> for you. Every option from the
official Umami tracker configuration
is supported. Pass it through extraDataAttributes and it is applied to the
script tag as-is.
app.use(
VueUmamiPlugin({
websiteID: 'YOUR_UMAMI_WEBSITE_ID',
router,
extraDataAttributes: {
'data-host-url': 'https://stats.mywebsite.com',
'data-domains': 'mywebsite.com,mywebsite2.com',
},
})
);Available attributes
The most commonly used options are listed below. See the official documentation for the complete list.
| Attribute | Description | Since |
|-----------------------|----------------------------------------------------------------------------------------------|---------|
| data-host-url | Send tracking data to a custom Umami host instead of where the script is served from. | v2.0 |
| data-domains | Comma-separated list of domains the tracker is allowed to run on. | v2.0 |
| data-auto-track | Enable/disable Umami's built-in automatic tracking. Defaults to "false" (see below). | v2.0 |
| data-tag | Group events under a named tag for filtering and A/B testing. | v2.11 |
| data-exclude-search | Omit URL search/query parameters from collected URLs. | v2.11 |
| data-exclude-hash | Omit URL hash fragments from collected URLs. | v2.16 |
| data-do-not-track | Respect the visitor's browser Do Not Track setting. | v2.17 |
| data-before-send | Name of a global function called to inspect, modify, or cancel each payload before it's sent. | v2.18 |
| data-performance | Collect Core Web Vitals from your visitors' browsers. | v3.1 |
Note: Values are always strings, so booleans must be passed as
'true'or'false', e.g.'data-do-not-track': 'true'.
Plugin-specific behaviour
The plugin applies a few rules to the attributes you pass:
- Only
data-*keys are applied. Any key that does not start withdata-is ignored. data-website-idcannot be overridden. It is always derived from thewebsiteIDoption.data-auto-trackdefaults to"false". The plugin records page views itself through Vue Router, so Umami's automatic tracking is turned off to avoid duplicates. You can override it (see Performance tracking below).
Performance tracking (Core Web Vitals)
Since Umami v3.1, the tracker can automatically collect
Core Web Vitals (LCP, CLS, INP, and more)
from your visitors. Enable it with data-performance:
app.use(
VueUmamiPlugin({
websiteID: 'YOUR_UMAMI_WEBSITE_ID',
// Note: no `router` here (see the caveat below).
extraDataAttributes: {
'data-auto-track': 'true',
'data-performance': 'true',
},
})
);Important: Umami only collects Core Web Vitals while its built-in automatic tracking is enabled. Because this plugin sets
data-auto-trackto"false"by default, you must re-enable it with'data-auto-track': 'true'for performance tracking to work.With auto-tracking enabled, Umami tracks page views on its own, including SPA navigations, via the History API that Vue Router uses. To avoid counting every page view twice, omit the
routeroption and let Umami handle page views when you turn auto-tracking on.
Modifying or filtering payloads (data-before-send)
data-before-send references the name of a function on window, which
Umami calls before every request. Return the payload to send it, or a falsy
value to drop it:
window.umamiBeforeSend = (type, payload) => {
// Drop events coming from internal/admin routes.
if (payload.url?.startsWith('/admin')) {
return false;
}
return payload;
};
app.use(
VueUmamiPlugin({
websiteID: 'YOUR_UMAMI_WEBSITE_ID',
router,
extraDataAttributes: {
'data-before-send': 'umamiBeforeSend',
},
})
);API Reference
VueUmamiPlugin(options)
Initializes the Umami tracking plugin with specified options.
- Parameters
options(Object):websiteID(String): The Umami website ID required for tracking.scriptSrc(String, optional): Custom URL for the Umami script source, default:https://us.umami.is/script.jsrouter(UmamiRouterLike, optional): A router-compatible object that exposesafterEachand navigates to routes withfullPath(typically a Vue Router instance). Typed structurally so this package does not depend on or pin avue-routerversion; see Whyrouteruses structural types.allowLocalhost(Boolean, optional): Whether to allow tracking on localhost, default:falseautoTrack(Boolean, optional): Enables Umami's built-in auto-tracking by settingdata-auto-track="true"on the injected script. When arouteris also provided, the plugin continues to forward every route change so browser history and hash navigation are not missed; native auto-tracking may therefore duplicate History API page views. Default:false. See Single-page application tracking for guidance.debug(Boolean, optional): Logs successful plugin load events to the console when set totrue. Default:false.maxQueuedEvents(Number, optional): Maximum number of queued calls kept whilewindow.umamiis unavailable. Oldest items are dropped when the limit is reached, including if installation lowers the cap below calls already queued. Default:100.extraDataAttributes(Object, optional): Additionaldata-*attributes to apply to the injected Umami<script>element. These are applied after the default attributes;data-auto-trackcan be overridden here only whenautoTrackis not explicitly set, whiledata-website-idis always taken fromwebsiteIDand cannot be overridden. Non-data-*keys are ignored. Defaults to{}. See Tracker Configuration for the supported options and examples.
Invalid autoTrack values are treated as false, and invalid maxQueuedEvents values fall back to the default limit of 100.
Repeated successful installs keep the existing tracker configuration. A later install can attach a different router for another Vue root, but it does not inject a second script or change the first tracker configuration. If the Umami script fails to load, you can call install() again to retry with updated options.
trackUmamiPageView(options)
Manually tracks a page view with Umami, useful when you are not using Vue Router or need to trigger a view outside normal navigation.
- Parameters
options(Object, optional): A partial page view payload that can override values such asurl,title, orreferrer.
trackUmamiEvent(event, eventParams)
Sends a custom tracking event to Umami.
- Parameters
event(String): The name of the event to track.eventParams(Object, optional): Additional parameters for the event; typically includes details like page URL or user actions.
identifyUmamiSession(sessionData)
identifyUmamiSession(id, sessionData?)
Identifies a user session with Umami.
- Parameters
id(String, optional): A custom identifier for the session.sessionData(Object): The session data to identify.
Single-page application tracking
The plugin defaults to autoTrack: false so Vue Router integration (via router.afterEach) remains the single source of truth for page views. This is the recommended configuration for most single-page applications.
If you prefer Umami's built-in auto-tracking, consider the tradeoffs:
- With a router: keep
autoTrack: false. The plugin forwards everyafterEachnavigation, including browser history and hash navigation, so it has complete SPA coverage. If you setautoTrack: trueas well, the router hook remains active to avoid missed page views, but Umami may also record History API navigation and duplicate those views. - Without a router: either set
autoTrack: trueand let Umami handle navigation via the History API, or keepautoTrack: falseand calltrackUmamiPageView()manually at navigation points.
Build and Packaging
npm run buildBuilds both module formats:
- ESM output:
dist/esm - CJS output:
dist/cjs
During build, module-type markers are written to each output directory:
dist/esm/package.jsonwith{ "type": "module" }dist/cjs/package.jsonwith{ "type": "commonjs" }
For publishing and local package testing:
npm run prepack
npm packprepack runs the full build automatically before npm pack/npm publish, ensuring tarballs always contain fresh ESM + CJS outputs.
Contributions
You can contribute to this project by submitting a pull request or reporting issues in the issues section of this repository.
License
This project is licensed under the MIT License, see the LICENSE file for details.
