Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add umami analytics to registry #348

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions docs/content/scripts/analytics/umami-analytics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
title: Umami Analytics
description: Use Umami Analytics in your Nuxt app.
links:
- label: Source
icon: i-simple-icons-github
to: https://github.com/nuxt/scripts/blob/main/src/runtime/registry/umami-analytics.ts
size: xs
---

[Umami](https://umami.is/) collects all the metrics you care about to help you make better decisions.

The simplest way to load Umami Analytics globally in your Nuxt App is to use Nuxt config. Alternatively you can directly
use the [useScriptUmamiAnalytics](#useScriptUmamiAnalytics) composable.

## Loading Globally

If you don't plan to send custom events you can use the [Environment overrides](https://nuxt.com/docs/getting-started/configuration#environment-overrides) to
disable the script in development.

::code-group

```ts [Always enabled]
export default defineNuxtConfig({
scripts: {
registry: {
umamiAnalytics: {
websiteId: 'YOUR_WEBSITE_ID'
}
}
}
})
```

```ts [Production only]
export default defineNuxtConfig({
$production: {
scripts: {
registry: {
umamiAnalytics: {
websiteId: 'YOUR_WEBSITE_ID',
}
}
}
}
})
```

```ts [Environment Variables]
export default defineNuxtConfig({
scripts: {
registry: {
umamiAnalytics: true,
}
},
// you need to provide a runtime config to access the environment variables
runtimeConfig: {
public: {
scripts: {
umamiAnalytics: {
// .env
// NUXT_PUBLIC_SCRIPTS_UMAMI_ANALYTICS_WEBSITE_ID=<your websiteId>
websiteId: ''
},
},
},
},
})
```

::

## useScriptUmamiAnalytics

The `useScriptUmamiAnalytics` composable lets you have fine-grain control over when and how Umami Analytics is loaded on your site.

```ts
const plausible = useScriptUmamiAnalytics({
websiteId: 'YOUR_WEBSITE_ID'
})
```

Please follow the [Registry Scripts](/docs/guides/registry-scripts) guide to learn more about advanced usage.

### Self-hosted Umami

If you are using a self-hosted version of Umami, you will need to provide an explicit src for the script so that
the API events are sent to the correct endpoint.

```ts
useScriptUmamiAnalytics({
scriptInput: {
src: 'https://my-self-hosted/script.js'
}
})
```

### UmamiAnalyticsApi

```ts
export interface UmamiAnalyticsApi {
track: ((payload?: Record<string, any>) => void) &((event_name: string, event_data: Record<string, any>) => void)
identify: (session_data?: Record<string, any>) => void
}
```

### Config Schema

You must provide the options when setting up the script for the first time.

```ts
export const UmamiAnalyticsOptions = object({
websiteId: string(), // required
/**
* By default, Umami will send data to wherever the script is located.
* You can override this to send data to another location.
*/
hostUrl: optional(string()),
/**
* By default, Umami tracks all pageviews and events for you automatically.
* You can disable this behavior and track events yourself using the tracker functions.
* https://umami.is/docs/tracker-functions
*/
autoTrack: optional(boolean()),
/**
* If you want the tracker to only run on specific domains, you can add them to your tracker script.
* This is a comma delimited list of domain names.
* Helps if you are working in a staging/development environment.
*/
domains: optional(array(string())),
/**
* If you want the tracker to collect events under a specific tag.
* Events can be filtered in the dashboard by a specific tag.
*/
tag: optional(string()),
})
```

## Example

Using Umami Analytics only in production while using `track` to send a conversion event.

::code-group

```vue [ConversionButton.vue]
<script setup lang="ts">
const { track } = useScriptUmamiAnalytics()

// noop in development, ssr
// just works in production, client
track('event', { name: 'conversion-step' })

function sendConversion() {
track('event', { name: 'conversion' })
}
</script>

<template>
<div>
<button @click="sendConversion">
Send Conversion
</button>
</div>
</template>
```

::
9 changes: 9 additions & 0 deletions src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,5 +268,14 @@ export const registry: (resolve?: (s: string) => string) => RegistryScripts = (r
return false
},
},
{
label: 'Umami Analytics',
category: 'analytics',
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 24 24"><path fill="currentColor" d="M2.203 8.611H.857a.845.845 0 0 0-.841.841v.858a13 13 0 0 0-.016.6c0 6.627 5.373 12 12 12c6.527 0 11.837-5.212 11.996-11.701c0-.025.004-.05.004-.075V9.452a.845.845 0 0 0-.841-.841h-1.346c-1.159-4.329-5.112-7.521-9.805-7.521S3.363 4.282 2.203 8.611m18.444 0H3.37c1.127-3.702 4.57-6.399 8.638-6.399c4.069 0 7.512 2.697 8.639 6.399"/></svg>`,
import: {
name: 'useScriptUmamiAnalytics',
from: resolve('./runtime/registry/umami-analytics'),
},
},
]
}
64 changes: 64 additions & 0 deletions src/runtime/registry/umami-analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useRegistryScript } from '../utils'
import { object, optional, string, boolean, array } from '#nuxt-scripts-validator'
import type { RegistryScriptInput } from '#nuxt-scripts/types'

export const UmamiAnalyticsOptions = object({
websiteId: string(), // required
/**
* By default, Umami will send data to wherever the script is located.
* You can override this to send data to another location.
*/
hostUrl: optional(string()),
/**
* By default, Umami tracks all pageviews and events for you automatically.
* You can disable this behavior and track events yourself using the tracker functions.
* https://umami.is/docs/tracker-functions
*/
autoTrack: optional(boolean()),
/**
* If you want the tracker to only run on specific domains, you can add them to your tracker script.
* This is a comma delimited list of domain names.
* Helps if you are working in a staging/development environment.
*/
domains: optional(array(string())),
/**
* If you want the tracker to collect events under a specific tag.
* Events can be filtered in the dashboard by a specific tag.
*/
tag: optional(string()),
})

export type UmamiAnalyticsInput = RegistryScriptInput<typeof UmamiAnalyticsOptions, false>

export interface UmamiAnalyticsApi {
track: ((payload?: Record<string, any>) => void) & ((event_name: string, event_data: Record<string, any>) => void)
identify: (session_data?: Record<string, any>) => void
}

declare global {
interface Window {
umami: UmamiAnalyticsApi
}
}

export function useScriptUmamiAnalytics<T extends UmamiAnalyticsApi>(_options?: UmamiAnalyticsInput) {
return useRegistryScript<T, typeof UmamiAnalyticsOptions>('umamiAnalytics', (options) => {
const domains = Array.isArray(options?.domains) ? options.domains.join(',') : options?.domains
return {
scriptInput: {
'src': 'https://cloud.umami.is/script.js',
'data-website-id': options.websiteId,
'data-host-url': options?.hostUrl || undefined,
'data-auto-track': typeof options?.autoTrack === 'boolean' ? options.autoTrack : true,
'data-domains': domains || undefined,
'data-tag': options?.tag || undefined,
},
schema: import.meta.dev ? UmamiAnalyticsOptions : undefined,
scriptOptions: {
use() {
return window.umami
},
},
}
}, _options)
}
2 changes: 2 additions & 0 deletions src/runtime/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type { ClarityInput } from './registry/clarity'
import type { CrispInput } from './registry/crisp'
import type { GoogleAnalyticsInput } from './registry/google-analytics'
import type { GoogleTagManagerInput } from './registry/google-tag-manager'
import type { UmamiAnalyticsInput } from './registry/umami-analytics'
import { object } from '#nuxt-scripts-validator'

export type WarmupStrategy = false | 'preload' | 'preconnect' | 'dns-prefetch'
Expand Down Expand Up @@ -154,6 +155,7 @@ export interface ScriptRegistry {
xPixel?: XPixelInput
youtubePlayer?: YouTubePlayerInput
vimeoPlayer?: VimeoPlayerInput
umamiAnalytics?: UmamiAnalyticsInput
[key: `${string}-npm`]: NpmInput
}

Expand Down