---
title: "Pageviews"
description: "Configure automatic Vue Router pageviews, page metadata and runtime hooks."
canonical_url: "https://mixpanel-nuxt.vercel.app/integration/pageviews"
---
# Pageviews

> Configure automatic Vue Router pageviews, page metadata and runtime hooks.

The module integrates automatic pageviews with Vue Router. By default, pageviews enabled through the SDK options use this integration.

Set `client.config.track_pageview` to `'url-with-path'` to record the first page and subsequent path changes. The module waits for the page and its title to render before sending the event.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['mixpanel-nuxt'],
  mixpanel: {
    client: {
      token: 'your-project-token',
      config: {
        track_pageview: 'url-with-path',
      },
    },
  },
})
```

Pageviews use the SDK's `$mp_web_page_view` event. Navigations cancelled by a guard or middleware send no pageview. Redirects record the final destination.

## Choosing which URL changes to track

Choose a mode based on which URL changes represent a new visit in your app:

<table>
<thead>
  <tr>
    <th>
      <code>
        track_pageview
      </code>
    </th>
    
    <th>
      When a pageview is sent
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Automatic pageviews are disabled.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Once, for the initial page.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        'url-with-path'
      </code>
    </td>
    
    <td>
      On the initial page and path changes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        'url-with-path-and-query-string'
      </code>
    </td>
    
    <td>
      Also when the query string changes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        'full-url'
      </code>
    </td>
    
    <td>
      Also when the hash changes.
    </td>
  </tr>
</tbody>
</table>

If you enable autocapture, set the mode through `autocapture.pageview`. It takes precedence over `track_pageview` and defaults to `'full-url'`:

```ts [mixpanel.client.config.ts]
import { defineMixpanelClientConfig } from 'mixpanel-nuxt/config'

export default defineMixpanelClientConfig({
  autocapture: {
    pageview: 'url-with-path',
  },
})
```

Autocapture's `allow_url_regexes` and `block_url_regexes` also filter these pageviews. Use a [configuration file](https://mixpanel-nuxt.vercel.app/get-started/configuration#configuration-files) to supply regular expressions. Other autocapture events keep their SDK behavior.

## Page properties

Add properties through `definePageMeta()`:

```vue [app/pages/reports.vue]
<script setup lang="ts">
definePageMeta({
  mixpanel: {
    pageview: {
      properties: { section: 'reports' },
    },
  },
})
</script>
```

The pageview includes `section: 'reports'`. Nested routes inherit parent properties; a child replaces a parent's property when both use the same key. See the [page meta reference](https://mixpanel-nuxt.vercel.app/api/page-meta) for the type and inheritance rules.

The module also adds `route_name` when the route has a name. Apps without a `pages/` directory can track pageviews, but have no page meta or `route_name`.

## Excluding a page

Set `pageview: false` to exclude a route and its children:

```vue [app/pages/internal.vue]
<script setup lang="ts">
definePageMeta({
  mixpanel: {
    pageview: false,
  },
})
</script>
```

For a condition evaluated during navigation, use the [pageview hook](#skipping-a-pageview) and set `context.skip`.

## Enriching pageviews

Use `mixpanel:pageview` to add properties before a pageview is sent:

```ts [app/plugins/analytics.client.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('mixpanel:pageview', (context) => {
    context.properties.app = 'dashboard'
  })
})
```

### Async data

The hook can await data needed by the event:

```ts [app/plugins/analytics.client.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('mixpanel:pageview', async (context) => {
    const workspace = await $fetch<{ plan: string }>('/api/workspace', {
      signal: context.signal,
    })
    context.properties.plan = workspace.plan
  })
})
```

`/api/workspace` is an application endpoint that returns the current workspace's plan. A new navigation aborts `context.signal` and drops the pending pageview.

Pageviews wait for the hook and page rendering.

## Skipping a pageview

Set `context.skip` when an event should be excluded based on a condition evaluated during navigation:

```ts [app/plugins/analytics.client.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('mixpanel:pageview', (context) => {
    if (context.properties.internal === true) {
      context.skip = true
    }
  })
})
```

The hook receives properties from page meta, so this example omits events for pages with `internal: true`. For a route that always excludes pageviews, use [page meta](#excluding-a-page).

See the [hook reference](https://mixpanel-nuxt.vercel.app/api/hooks/pageview) for context fields, invocation, property precedence and error behavior.

## Pageview strategy

`client.pageviewStrategy` selects how automatic pageviews follow navigation:

- `'router'` (default): the Nuxt Router integration records confirmed navigations after the page and title render.
- `'native'`: Mixpanel native tracking records URL changes directly.

Both strategies use `track_pageview` or `autocapture.pageview` to enable tracking and select which URL changes to record.

To use Mixpanel native tracking:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  modules: ['mixpanel-nuxt'],
  mixpanel: {
    client: {
      token: 'your-project-token',
      pageviewStrategy: 'native',
      config: {
        track_pageview: 'url-with-path',
      },
    },
  },
})
```

<table>
<thead>
  <tr>
    <th>
      Behavior
    </th>
    
    <th>
      Nuxt Router integration (<code>
        'router'
      </code>
      
      )
    </th>
    
    <th>
      Mixpanel native tracking (<code>
        'native'
      </code>
      
      )
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Event timing
    </td>
    
    <td>
      After page rendering and title updates
    </td>
    
    <td>
      On URL changes
    </td>
  </tr>
  
  <tr>
    <td>
      Identity on the initial pageview
    </td>
    
    <td>
      Includes identity set during plugins, middleware and page setup
    </td>
    
    <td>
      Sent during SDK initialization
    </td>
  </tr>
  
  <tr>
    <td>
      Cancelled or redirected back/forward navigation
    </td>
    
    <td>
      Records the resulting route
    </td>
    
    <td>
      Can record the intervening URL
    </td>
  </tr>
  
  <tr>
    <td>
      Page meta and <code>
        mixpanel:pageview
      </code>
    </td>
    
    <td>
      Applied
    </td>
    
    <td>
      Not applied
    </td>
  </tr>
</tbody>
</table>

<warning>

With `client.pageviewStrategy: 'router'` and `record_heatmap_data` enabled, the SDK also records its own pageviews, causing duplicate pageviews in recorded sessions.

</warning>

## Manual pageviews and runtime changes

Calling `track_pageview()` yourself records an extra event even when automatic pageviews are enabled.

With router pageviews, changing `autocapture` through `set_config()` can turn the SDK pageview listeners back on. Set `autocapture.pageview` to `false` in those updates to keep them disabled.

Router pageviews also wait for page and layout transitions. If a leave transition never finishes, Nuxt retains the previous page head and the next pageview remains pending.


## Sitemap

See the full [sitemap](https://mixpanel-nuxt.vercel.app/sitemap.md) for all pages.
