Skip to content
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
112 changes: 112 additions & 0 deletions docs/content/scripts/mixpanel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---

title: Mixpanel
description: Use Mixpanel in your Nuxt app.
links:
- label: Source
icon: i-simple-icons-github
to: https://github.com/nuxt/scripts/blob/main/src/runtime/registry/mixpanel-analytics.ts
size: xs

---

[Mixpanel](https://mixpanel.com) is a product analytics platform that helps you understand how users interact with your application through event tracking, funnels, and retention analysis.

Nuxt Scripts provides a registry script composable [`useScriptMixpanelAnalytics()`](/scripts/mixpanel){lang="ts"} to easily integrate Mixpanel in your Nuxt app.

::script-stats
::

::script-docs
::

::script-types
::

## Composable Usage

The simplest way to load Mixpanel is through `nuxt.config`:

```ts
export default defineNuxtConfig({
scripts: {
registry: {
mixpanelAnalytics: {
token: 'YOUR_PROJECT_TOKEN',
}
}
}
})
```

### Tracking Events

```vue
<script setup lang="ts">
const { proxy } = useScriptMixpanelAnalytics()

function trackSignup() {
proxy.mixpanel.track('Sign Up', {
plan: 'premium',
source: 'landing_page',
})
}
</script>
```

### Identifying Users

```vue
<script setup lang="ts">
const { proxy } = useScriptMixpanelAnalytics()

function login(userId: string) {
proxy.mixpanel.identify(userId)
proxy.mixpanel.people.set({
$name: 'Jane Doe',
$email: 'jane@example.com',
plan: 'premium',
})
}
</script>
```

### Registering Super Properties

Super properties are sent with every subsequent event:

```vue
<script setup lang="ts">
const { proxy } = useScriptMixpanelAnalytics()

proxy.mixpanel.register({
app_version: '2.0.0',
platform: 'web',
})
</script>
```

### Environment Variables

```ts [nuxt.config.ts]
export default defineNuxtConfig({
scripts: {
registry: {
mixpanelAnalytics: true,
}
},
runtimeConfig: {
public: {
scripts: {
mixpanelAnalytics: {
token: '', // NUXT_PUBLIC_SCRIPTS_MIXPANEL_ANALYTICS_TOKEN
},
},
},
},
})
```

```text [.env]
NUXT_PUBLIC_SCRIPTS_MIXPANEL_ANALYTICS_TOKEN=YOUR_PROJECT_TOKEN
```
1 change: 1 addition & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ const PARTYTOWN_FORWARDS: Record<string, string[]> = {
umami: ['umami', 'umami.track'],
matomo: ['_paq.push'],
segment: ['analytics', 'analytics.track', 'analytics.page', 'analytics.identify'],
mixpanelAnalytics: ['mixpanel', 'mixpanel.track', 'mixpanel.identify', 'mixpanel.people.set', 'mixpanel.reset', 'mixpanel.register'],
metaPixel: ['fbq'],
xPixel: ['twq'],
tiktokPixel: ['ttq.track', 'ttq.page', 'ttq.identify'],
Expand Down
12 changes: 12 additions & 0 deletions src/registry-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,18 @@
"code": "interface RybbitQueueState {\n queue: Array<[string, ...any[]]>\n flushed: boolean\n}"
}
],
"mixpanel-analytics": [
{
"name": "MixpanelAnalyticsOptions",
"kind": "const",
"code": "export const MixpanelAnalyticsOptions = object({\n /**\n * Your Mixpanel project token.\n * @see https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#1-initialize-the-library\n */\n token: string(),\n})"
},
{
"name": "MixpanelAnalyticsApi",
"kind": "interface",
"code": "export interface MixpanelAnalyticsApi {\n mixpanel: {\n track: (event: string, properties?: Record<string, any>) => void\n identify: (distinctId: string) => void\n reset: () => void\n people: {\n set: (properties: Record<string, any>) => void\n }\n register: (properties: Record<string, any>) => void\n init: (token: string, config?: Record<string, any>) => void\n }\n}"
}
],
"segment": [
{
"name": "SegmentOptions",
Expand Down
10 changes: 10 additions & 0 deletions src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ export async function registry(resolve?: (path: string, opts?: ResolvePathOption
from: await resolve('./runtime/registry/segment'),
},
},
{
label: 'Mixpanel',
src: 'https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js',
category: 'analytics',
logo: `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="#7856FF" d="M128 0C57.308 0 0 57.308 0 128s57.308 128 128 128s128-57.308 128-128S198.692 0 128 0m-26.461 176.882c-14.478 0-26.221-11.743-26.221-26.221s11.743-26.221 26.221-26.221s26.221 11.743 26.221 26.221s-11.743 26.221-26.221 26.221m52.922 0c-14.478 0-26.221-11.743-26.221-26.221s11.743-26.221 26.221-26.221s26.221 11.743 26.221 26.221s-11.743 26.221-26.221 26.221m0-52.442c-14.478 0-26.221-11.743-26.221-26.221s11.743-26.221 26.221-26.221s26.221 11.743 26.221 26.221s-11.743 26.221-26.221 26.221"/></svg>`,
import: {
name: 'useScriptMixpanelAnalytics',
from: await resolve('./runtime/registry/mixpanel-analytics'),
},
},
{
label: 'Meta Pixel',
proxy: 'metaPixel',
Expand Down
69 changes: 69 additions & 0 deletions src/runtime/registry/mixpanel-analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { RegistryScriptInput } from '#nuxt-scripts/types'
import { useRegistryScript } from '../utils'
import { MixpanelAnalyticsOptions } from './schemas'

export { MixpanelAnalyticsOptions }

export type MixpanelAnalyticsInput = RegistryScriptInput<typeof MixpanelAnalyticsOptions>

export interface MixpanelAnalyticsApi {
mixpanel: {
track: (event: string, properties?: Record<string, any>) => void
identify: (distinctId: string) => void
reset: () => void
people: {
set: (properties: Record<string, any>) => void
}
register: (properties: Record<string, any>) => void
init: (token: string, config?: Record<string, any>) => void
}
}

declare global {
interface Window {
mixpanel: MixpanelAnalyticsApi['mixpanel']
}
}

const methods = ['track', 'identify', 'reset', 'register'] as const
const peopleMethods = ['set'] as const

export function useScriptMixpanelAnalytics<T extends MixpanelAnalyticsApi>(_options?: MixpanelAnalyticsInput) {
return useRegistryScript<T, typeof MixpanelAnalyticsOptions>('mixpanelAnalytics', (options) => {
return {
scriptInput: {
src: 'https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js',
},
schema: import.meta.dev ? MixpanelAnalyticsOptions : undefined,
scriptOptions: {
use() {
return {
mixpanel: window.mixpanel,
}
},
},
clientInit: import.meta.server
? undefined
: () => {
window.mixpanel = window.mixpanel || [] as any
for (const method of methods) {
(window.mixpanel as any)[method] = (window.mixpanel as any)[method] || ((...args: any[]) => {
(window.mixpanel as any).push([method, ...args])
})
}
window.mixpanel.people = window.mixpanel.people || {} as any
for (const method of peopleMethods) {
(window.mixpanel.people as any)[method] = (window.mixpanel.people as any)[method] || ((...args: any[]) => {
(window.mixpanel as any).push([`people.${method}`, ...args])
})
}
window.mixpanel.init = window.mixpanel.init || ((...args: any[]) => {
(window.mixpanel as any).push(['init', ...args])
})
if (options?.token) {
window.mixpanel.init(options.token)
}
},
}
}, _options)
}
8 changes: 8 additions & 0 deletions src/runtime/registry/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,14 @@ export const RybbitAnalyticsOptions = object({
apiKey: optional(string()),
})

export const MixpanelAnalyticsOptions = object({
/**
* Your Mixpanel project token.
* @see https://docs.mixpanel.com/docs/tracking-methods/sdks/javascript#1-initialize-the-library
*/
token: string(),
})

export const SegmentOptions = object({
/**
* Your Segment write key.
Expand Down
Loading