UNPKG

@jaseeey/vue-umami-plugin

Version:

A plugin designed for Vue 3 which enables the use of Umami Analytics

361 lines (267 loc) 15.6 kB
# 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: ```bash npm install @jaseeey/vue-umami-plugin ``` ## Module Format Support (ESM + CJS) This library ships dual builds and uses conditional exports: - `dist/esm` for ESM consumers - `dist/cjs` for CommonJS consumers Consumers should always import from the package root. Runtime/module resolution will select the correct build automatically. ```javascript import { VueUmamiPlugin, trackUmamiEvent } from '@jaseeey/vue-umami-plugin'; ``` ```javascript 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: ```javascript 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: ```javascript import { trackUmamiEvent } from '@jaseeey/vue-umami-plugin'; trackUmamiEvent('button-click', { buttonName: 'subscribe' }); ``` ### Identifying Sessions ```javascript import { identifyUmamiSession } from '@jaseeey/vue-umami-plugin'; identifyUmamiSession({ userId: 'alice', email: 'alice@example.com', name: 'Alice Smith', }); identifyUmamiSession('alice-123', { email: 'alice@example.com', name: 'Alice Smith', }); ``` ### TypeScript Plugin and helper types are exported so you can type shared config objects: ```typescript 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-router` dependency.** Automatic page tracking is optional. Projects that only call `trackUmamiEvent` / `trackUmamiPageView` should not need `vue-router` installed 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 of `vue-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.afterEach` and reads `to.fullPath`. The public types describe that contract: - `UmamiRouterLike` — object with `afterEach(handler)` - `UmamiRouteLike` — object with `fullPath` A real Vue Router instance satisfies both, so you pass `router` as 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](https://docs.umami.is/docs/tracker-configuration) is supported. Pass it through `extraDataAttributes` and it is applied to the script tag as-is. ```javascript 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](https://docs.umami.is/docs/tracker-configuration) 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](https://web.dev/articles/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 with `data-` is ignored. - **`data-website-id` cannot be overridden.** It is always derived from the `websiteID` option. - **`data-auto-track` defaults 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](https://web.dev/articles/vitals) (LCP, CLS, INP, and more) from your visitors. Enable it with `data-performance`: ```javascript 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-track` to > `"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 `router` option** 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: ```javascript 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.js` - `router` (`UmamiRouterLike`, optional): A router-compatible object that exposes `afterEach` and navigates to routes with `fullPath` (typically a Vue Router instance). Typed structurally so this package does not depend on or pin a `vue-router` version; see [Why `router` uses structural types](#why-router-uses-structural-types-umamirouterlike). - `allowLocalhost` (Boolean, optional): Whether to allow tracking on localhost, default: `false` - `autoTrack` (Boolean, optional): Enables Umami's built-in auto-tracking by setting `data-auto-track="true"` on the injected script. When a `router` is 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](#single-page-application-tracking) for guidance. - `debug` (Boolean, optional): Logs successful plugin load events to the console when set to `true`. Default: `false`. - `maxQueuedEvents` (Number, optional): Maximum number of queued calls kept while `window.umami` is 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): Additional `data-*` attributes to apply to the injected Umami `<script>` element. These are applied after the default attributes; `data-auto-track` can be overridden here only when `autoTrack` is not explicitly set, while `data-website-id` is always taken from `websiteID` and cannot be overridden. Non-`data-*` keys are ignored. Defaults to `{}`. See [Tracker Configuration](#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 as `url`, `title`, or `referrer`. ### `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 every `afterEach` navigation, including browser history and hash navigation, so it has complete SPA coverage. If you set `autoTrack: true` as 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: true` and let Umami handle navigation via the History API, or keep `autoTrack: false` and call `trackUmamiPageView()` manually at navigation points. ## Build and Packaging ```bash npm run build ``` Builds 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.json` with `{ "type": "module" }` - `dist/cjs/package.json` with `{ "type": "commonjs" }` For publishing and local package testing: ```bash npm run prepack npm pack ``` `prepack` 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](LICENSE) file for details.