vTilt
Why vTiltHow It WorksFeaturesFAQDocs
Docs / Nuxt.js
Quick startEvent forwarding
MCP server
Guides
OverviewAuthenticationOAuthAgent skills (prompts)AI intelligenceGoogle Ads
Client setup
CursorClaude DesktopVS CodeCodex
Realtime
Debug ViewRealtime Dashboard
Integration guides
Frontend frameworks
Next.jsNuxt.jsVue.jsReactReact RouterRemixGatsbySvelte / SvelteKitAstroAngularTanStack StartDocusaurus
Backend frameworks
NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails
Backend languages
PythonPHPRubyElixirGoJava.NET / C#Rust
Stack guides
Vue + PHP
SDK
Browser SDK
InstallScript bundlesEvent trackingAutocaptureIdentify & aliasWeb VitalsSession recordingChat widgetFeature readinessRemote configurationReverse proxyDebug logging
Node SDK
Install & setupCapture, identify & aliasContext & shutdown

Documentation

vTilt
Quick startEvent forwarding

MCP server

Realtime

Debug ViewRealtime Dashboard

Integration guides

Next.jsNuxt.jsVue.jsReactReact RouterRemixGatsbySvelte / SvelteKitAstroAngularTanStack StartDocusaurus

SDK

DocsIntegration guidesNuxt.js

Nuxt.js

Integrate vTilt with Nuxt 3 / Nuxt 4 — npm package or inline script, identify on every authenticated page load, server-side events with Nitro.

vTilt drops into Nuxt 3/4 on the client. Nitro server routes can also emit events using the Node SDK so server actions and webhooks land on the same person record.

#1. Runtime config

Expose the token and ingest origin via nuxt.config.ts. The public block is readable on the client; values without public stay server-only.

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    vtiltTrackerToken: process.env.VTILT_TRACKER_TOKEN,
    public: {
      vtiltToken: process.env.NUXT_PUBLIC_VTILT_TOKEN,
      vtiltHost: process.env.NUXT_PUBLIC_VTILT_HOST,
    },
  },
})
typescript
# .env
NUXT_PUBLIC_VTILT_TOKEN=YOUR_PROJECT_TOKEN
NUXT_PUBLIC_VTILT_HOST=https://www.vtilt.com
VTILT_TRACKER_TOKEN=YOUR_PROJECT_TOKEN
text

#2. Install & initialise

Choose how you load the Browser SDK. npm boots the SDK from a client-only plugin; the inline script injects a stub via useHead with no package to install. Both expose the same window.vt global — the rest of this guide is identical either way.

Install the package:

npm install @v-tilt/browser
bash

Create plugins/vtilt.client.ts — the .client suffix keeps it out of SSR:

// plugins/vtilt.client.ts
import { vt } from '@v-tilt/browser'

export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig()

  vt.init(config.public.vtiltToken, {
    api_host: config.public.vtiltHost,
    autocapture: true,
    capture_pageview: false, // captured on Vue Router navigation below
    capture_pageleave: true,
  })

  const router = useRouter()
  router.afterEach((to, from) => {
    vt.capture('$pageview', {
      $current_url: window.location.href,
      $pathname: to.fullPath,
      $referrer: from.fullPath,
    })
  })

  return { provide: { vt } }
})
typescript

Now useNuxtApp().$vt returns the SDK from any component.

Tip

Tip: Need chat on first paint? Swap array.js for array.chat.js and add chat: { enabled: true }. See Script bundles.

#3. Identify on every authenticated page load

Important

Important: Identifying users only inside your login handler leaves every visitor with an existing session cookie anonymous. Identify on every page load when the user is known.

// plugins/vtilt-identify.client.ts
import { vt } from '@v-tilt/browser'

export default defineNuxtPlugin(() => {
  const user = useState<{ id: string; email: string } | null>('user')

  watchEffect(() => {
    if (user.value) {
      vt.identify(user.value.id, { email: user.value.email })
    }
  })
})
typescript

Note

Note: Using the inline script? Replace vt with window.vt and drop the import.

See Identify & alias for the full model.

#4. Server-side events from Nitro

For events from server routes, install the Node SDK:

npm install @v-tilt/node
bash

Reuse a single client across requests:

// server/utils/vtilt.ts
import { VTiltNode } from '@v-tilt/node'

let _client: VTiltNode | null = null
export function vtilt() {
  if (!_client) {
    const cfg = useRuntimeConfig()
    _client = new VTiltNode(cfg.vtiltTrackerToken, {
      host: cfg.public.vtiltHost,
    })
  }
  return _client
}
typescript
// server/api/checkout.post.ts
import { vtilt } from '~/server/utils/vtilt'

export default defineEventHandler(async event => {
  const body = await readBody(event)

  vtilt().capture({
    distinctId: body.userId,
    event: 'purchase_completed',
    properties: { amount: body.amount },
  })

  await vtilt().shutdown()
  return { ok: true }
})
typescript

#Next steps

  • Vue + PHP integration guide — the same identify-on-page-load pattern with a PHP back-end.
  • Identify & alias — full identification model.
  • Reverse proxy — block-resistant ingestion.
  • Node SDK / Capture, identify & alias — server-side event shapes.
PreviousNext.jsIntegration guidesNextVue.jsIntegration guides

On this page

  • 1. Runtime config
  • 2. Install & initialise
  • 3. Identify on every authenticated page load
  • 4. Server-side events from Nitro
  • Next steps