Stickybeak Docs Dashboard Get early access

Frameworks

Vue

Vue analytics with Stickybeak starts by adding its script to your rendered pages; this guide shows you where it belongs and how to track page views, goals and purchase revenue. It is a lighter alternative to Google Analytics for Vue, with live visitors, goals and revenue attribution in one script.

Using Nuxt?

Nuxt renders the HTML for you, so it has its own guide: Nuxt. For VitePress, see VitePress.

Add the script

  1. Copy your snippet

    In Stickybeak, open Settings, pick your site and copy the HTML snippet.

  2. Paste it into index.html

    It's at the root of your project. Paste the snippet before </head>.

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>My app</title>
        <script
          defer
          data-site="YOUR_SITE_ID"
          data-domain="example.com"
          src="https://app.usestickybeak.com/_cfw/s.js"
        ></script>
      </head>
      <body>
        <div id="app"></div>
        <script type="module" src="/src/main.ts"></script>
      </body>
    </html>

    Keep it a plain <script>, without type="module".

  3. Build and deploy

    Visits appear as soon as the new build is live.

Keep the site ID in an environment variable

Vite fills in %NAME% in index.html from your VITE_ variables. Put the ID in .env.production and use data-site="%VITE_STICKYBEAK_SITE_ID%". Local development is already left out, because the script switches itself off on localhost.

VITE_STICKYBEAK_SITE_ID=YOUR_SITE_ID

Check it's working

Test the deployed site, then verify your install.

Track goals

Add data-goal to rendered links or buttons. For other events, use the typed queued helper below. See Custom goals.

<button data-goal="initiate_checkout" data-goal-plan="pro" @click="openCheckout">
  Upgrade
</button>
type GoalProps = Record<string, string | number | boolean>;
type Stickybeak = ((goal: string, props?: GoalProps) => void) & { q?: unknown[][] };

declare global {
  interface Window {
    stickybeak?: Stickybeak;
  }
}

export function track(goal: string, props?: GoalProps): void {
  if (typeof window === "undefined") return; // on the server: nothing to do
  if (!window.stickybeak) {
    // Hold calls made before the script loads; it sends them when it arrives.
    const queue: Stickybeak = (...args) => {
      (queue.q ??= []).push(args);
    };
    window.stickybeak = queue;
  }
  window.stickybeak(goal, props);
}
<script setup lang="ts">
import { ref } from "vue";
import { track } from "../stickybeak";

const rating = ref("5");

async function submit() {
  const res = await fetch("/api/feedback", { method: "POST", body: JSON.stringify({ rating: rating.value }) });
  if (res.ok) track("feedback_sent", { rating: rating.value });
}
</script>

<template>
  <form @submit.prevent="submit">
    <select v-model="rating">
      <option v-for="n in 5" :key="n" :value="String(n)">{{ n }}</option>
    </select>
    <button>Send</button>
  </form>
</template>

Track purchases

After confirming an order in the browser, send:

window.stickybeak?.("purchase", { revenue: 49, currency: "USD", order_id: "ORDER_ID" });

Use real values; see Revenue.

Page changes

History routes count new paths. Replace, query-only, hash-only and createWebHashHistory() changes do not. See Single-page apps.

If it isn't working

Check the production site ID and domain, then see Troubleshooting.