Install

Add analytics and revenue attribution to Nuxt

Nuxt has a first-class place for third-party scripts: the app.head config in nuxt.config.ts. One entry there and every route is instrumented, including client-side Vue Router navigations.

Start a 14-day trialLast reviewed August 2026
  1. Declare the script in nuxt.config.ts

    app.head.script accepts the same attributes as the HTML tag. Nuxt renders it into every page's head, so there's no plugin file and nothing to import.

    nuxt.config.ts
    export default defineNuxtConfig({
      app: {
        head: {
          script: [
            {
              src: "https://revtrail.pyln.dev/track.js",
              defer: true,
              "data-site": "SITE_KEY",
            },
          ],
        },
      },
    });
  2. Leave Vue Router alone

    Vue Router navigates through the History API, so route changes are reported automatically. Don't add a router.afterEach that fires a pageview — you'd count every navigation twice.

  3. Confirm it's receiving

    Open your site in a normal browser tab, then check Realtime in the Revtrail dashboard — your own visit should appear within a few seconds. If nothing arrives, the usual causes are a mistyped site key, an ad blocker on your own browser, or a Content-Security-Policy that blocks the script origin.

  4. Instrument the conversion that matters

    Pageviews tell you traffic; a goal tells you whether the traffic worked. Call revtrail() at the moment of signup, trial start, or booking, then register it as a goal in the dashboard. This is the one step people skip, and it's the step that makes every other number worth reading.

    anywhere in your client code
    revtrail('signup')
  5. Wire revenue in from Stripe

    Point a Stripe webhook at Revtrail for checkout.session.completed and invoice.payment_succeeded, save the signing secret in your site settings, and pass the visitor id as the Checkout session's client_reference_id. Payments then attach to the visitor's first-touch channel, including renewals months later. Revenue is never accepted from the browser, so this webhook is the only way money reaches your dashboard.

    when you create the Checkout session
    const visitorId = await revtrail.visitorIdAsync();
    // best-effort: omit when null, never block checkout on analytics
    stripe.checkout.sessions.create({
      client_reference_id: visitorId ?? undefined,
      // …line items, success_url, etc.
    });

Calling revtrail() from a composable

The global only exists in the browser, so guard it for SSR: wrap the call in import.meta.client (or a process.client check on older Nuxt) and use optional-call syntax. A composable that calls window.revtrail?.('signup') is safe to import anywhere, including in code that also runs on the server.

Universal, SPA, and static modes all behave the same

ssr: true, ssr: false, and nuxt generate all end up with the same tag in the same head, and tracking happens in the browser either way. Rendering mode isn't a factor in what gets reported.

Questions people actually ask

Do I need a Nuxt module for this?
No. The app.head.script entry in nuxt.config.ts is the complete install.
How do I fire a conversion event safely in Nuxt?
Guard for the client — window.revtrail?.('signup') inside an import.meta.client branch — so the same code can be imported by anything without breaking SSR.
Do I need a cookie banner for this?
Not for Revtrail. The default identity is a daily rotating hash — no cookies, no persistent identifier, nothing stored on the device. If you run ad pixels or other analytics that do use cookies, their obligations are unchanged.
Will this slow my site down?
The script is deferred, so it never blocks rendering, and it's about 3KB over the wire gzipped. It fires one beacon per pageview.

Install guides

All install guides