pieowl

How to add analytics to Nuxt

Add cookie-free analytics to your Nuxt app in about 5 minutes with the Pieowl script.

Pieowl TeamBeginner · 5 min · 8 Oct 2026
Guide · Nuxt

This guide shows you how to add Pieowl to a Nuxt app. One script tag in nuxt.config.ts gives you automatic page views, including client-side navigation. @pieowl/bots adds AI crawler tracking and a proxy to get around ad blockers.

The tracker never sets a cookie, so in many cases you don't need a consent banner for your analytics. See when you still do.

Prerequisites

Get your snippet

There is no package to install for the browser. Pieowl is one script tag, loaded from pieowl.com. The snippet has two parts. The first line creates a small queue, so calls made before pieowl.js loads (for example in onMounted) are sent once it's ready. The second loads the script with your Client ID.

Add the script

Add both scripts to app.head in nuxt.config.ts, so they load on every page.

nuxt.config.ts
const pieowlQueue = `window.pieowl=window.pieowl||function(){(window.pieowl.q=window.pieowl.q||[]).push(arguments)};`;

export default defineNuxtConfig({
  app: {
    head: {
      script: [
        { innerHTML: pieowlQueue },
        { src: 'https://pieowl.com/pieowl.js', 'data-client-id': 'your-client-id', defer: true },
      ],
    },
  },
});

That's it. Page views are now tracked as users move through your app.

What gets collected

What the script collects by itself is set in Settings → Site → What Pieowl counts: page views, clicks on links to other sites, clicks on elements with data-track, address changes after #, and session replay. A change reaches your site within about a minute, with no code to edit.

Configuration options

Options that need code go in an init call. To use them, switch to the init form.

OptionDefaultDescription
clientId—Your Pieowl client ID (required)
apiUrlhttps://api.pieowl.comWhere events are sent
disabledfalseHold all events until you call ready()

Using environment variables

In production, keep your Client ID in an environment variable. nuxt.config.ts reads it when the app is built.

nuxt.config.ts
{ src: 'https://pieowl.com/pieowl.js', 'data-client-id': process.env.NUXT_PUBLIC_PIEOWL_CLIENT_ID, defer: true },
.env
NUXT_PUBLIC_PIEOWL_CLIENT_ID=your-client-id

Track custom events

Page views are only part of the story. To see how people use your product, track custom events such as button clicks, form submits or feature use.

Calling window.pieowl

Call window.pieowl('track') from any component. Call it in event handlers or onMounted, not at the top of <script setup>: there is no window during server rendering.

components/SignupButton.vue
<script setup>
function handleClick() {
  window.pieowl('track', 'button_clicked', {
    button_name: 'signup',
    button_location: 'hero',
  });
}
</script>

<template>
  <button type="button" @click="handleClick">Sign Up</button>
</template>

TypeScript

With TypeScript, declare window.pieowl once, in any .d.ts file.

pieowl.d.ts
declare global {
  interface Window {
    pieowl: (method: string, ...args: any[]) => void;
  }
}

export {};

Track form submissions

Form tracking helps you see conversion rates and where users drop off.

components/ContactForm.vue
<script setup>
const email = ref('');

async function handleSubmit() {
  window.pieowl('track', 'form_submitted', {
    form_name: 'contact',
    form_location: 'homepage',
  });

  // Your form submission logic
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="email" type="email" placeholder="Enter your email" />
    <button type="submit">Submit</button>
  </form>
</template>

Use data attributes for declarative tracking

You can also track clicks with data-track attributes, without writing JavaScript.

<template>
  <button
    data-track="button_clicked"
    data-button-name="signup"
    data-button-location="hero"
  >
    Sign Up
  </button>
</template>

When someone clicks this button, Pieowl sends a button_clicked event. The other data-* attributes become properties in camelCase: buttonName and buttonLocation. This needs Clicks you marked in your code to be on in Settings → Site (it is by default).

Identify users

Anonymous data is useful. Knowing who did what is more useful. When you identify users, you can follow them across sessions, filter by their properties and build cohorts.

Call identify after a user logs in.

components/UserProfile.vue
<script setup>
const props = defineProps(['user']);

watch(() => props.user, (user) => {
  if (user && import.meta.client) {
    window.pieowl('identify', {
      profileId: user.id,
      firstName: user.firstName,
      lastName: user.lastName,
      email: user.email,
      properties: {
        plan: user.plan,
        signupDate: user.createdAt,
      },
    });
  }
}, { immediate: true });
</script>

<template>
  <div>Welcome, {{ user?.firstName }}!</div>
</template>

Set global properties

Properties set with setGlobalProperties are sent with every event. Use them for things like the app version or feature flags.

app.vue
<script setup>
onMounted(() => {
  window.pieowl('setGlobalProperties', {
    app_version: '1.0.0',
    environment: useRuntimeConfig().public.environment,
  });
});
</script>

Clear user data on logout

When a user logs out, clear the profile so new events are not linked to them.

components/LogoutButton.vue
<script setup>
function handleLogout() {
  window.pieowl('clear');
  navigateTo('/login');
}
</script>

<template>
  <button @click="handleLogout">Logout</button>
</template>

Set up server-side tracking

To track events in server routes, API endpoints or server middleware, use the @pieowl/sdk package. Server-side tracking needs a client secret.

Install the SDK

npm install @pieowl/sdk

Create a server instance

server/utils/pieowl.ts
import { Pieowl } from '@pieowl/sdk';

export const pieowl = new Pieowl({
  clientId: process.env.PIEOWL_CLIENT_ID!,
  clientSecret: process.env.PIEOWL_CLIENT_SECRET!,
});

Track events in server routes

Nuxt auto-imports what you export from server/utils, so pieowl is ready to use.

server/api/webhook.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);

  await pieowl.track('webhook_received', {
    source: body.source,
    event_type: body.type,
  });

  return { success: true };
});

Never expose your client secret in the browser. Keep it in server-only code.

Awaiting in serverless environments

On a serverless platform like Vercel or Netlify, await the tracking call. That way it finishes before the function stops.

export default defineEventHandler(async (event) => {
  // Always await in serverless environments
  await pieowl.track('my_server_event', { foo: 'bar' });
  return { message: 'Event logged!' };
});

Track AI crawlers

AI crawlers and search bots don't run JavaScript, so the script never sees them. To count them, add @pieowl/bots as server middleware. It uses the same client secret.

npm install @pieowl/bots
server/middleware/pieowl-bots.ts
import { trackBotRequest } from '@pieowl/bots';

export default defineEventHandler((event) => {
  trackBotRequest({ url: getRequestURL(event).href, headers: getRequestHeaders(event) }, {
    clientId: process.env.PIEOWL_CLIENT_ID!,
    clientSecret: process.env.PIEOWL_CLIENT_SECRET!,
  });
});

Bypass ad blockers with proxy

Many ad blockers block requests to analytics domains. @pieowl/bots has a route handler that serves the script and sends events through your Nuxt server.

server/routes/api/pieowl/[...].ts
import { createRouteHandler } from '@pieowl/bots/route-handler';

export default fromWebHandler(createRouteHandler());

Then point the script at that route in nuxt.config.ts, with the init form:

  • Load the script from /api/pieowl/pieowl.js, without data-client-id
  • Set apiUrl: '/api/pieowl' in the init call
  • All tracking requests now go through your Nuxt server

Browser extensions that block third-party analytics no longer see the requests.

Verify your setup

Open your Nuxt app and visit a few pages. Click the elements that send custom events. Then open the Pieowl dashboard and check the realtime view. Events should show up within seconds.

No events? Check the browser console for errors. The most common causes are:

  • A wrong Client ID
  • An ad blocker (add the proxy route)

The Network tab in your browser's developer tools shows whether requests are being sent.

Next steps

The script tag reference covers more features, such as profile counters and event filters. The Nuxt docs cover bot tracking and the proxy. To learn how Pieowl measures visits without cookies, read cookieless analytics.

Does Pieowl work with Nuxt 3 and Nuxt 4?

Yes. The script is added with app.head in nuxt.config.ts, which works the same in Nuxt 3 and Nuxt 4.

Do I need a Nuxt module?

No. Pieowl is one script tag in app.head. Call window.pieowl from any component in the browser.

Does Pieowl use cookies?

No. The tracker never sets a cookie and stores nothing on your visitors' devices. In many cases that means no consent banner for your analytics. See Do you need a cookie banner?.

How do I avoid ad blockers?

Add the proxy route from @pieowl/bots. All tracking requests then go through your Nuxt server at /api/pieowl/*, which ad blockers usually leave alone.

Does Pieowl help with GDPR?

Pieowl is built for GDPR: no cookies, no stored IPs. Your data is stored in the EU. Ask your legal advisor about your own setup.

Your first dashboard in five minutes.

14-day free trial, no card needed. Cloud in the EU. No cookies.