Skip to content

Vite

Vite builds an HTML entry and injects your bundles into it. Statable is a client-only script that belongs in <head> of that entry, outside your application code.

This applies to any Vite project with an index.html, including the React, Vue, Svelte and Solid templates. Framework-specific pages exist for React, Vue, Next.js and Nuxt.

Install

Approach 1: the statable-analytics plugin

npm install statable-analytics
// vite.config.js
import { defineConfig } from 'vite'
import statable from 'statable-analytics/vite'

export default defineConfig({
  plugins: [statable({ siteId: '3270462' })],
})

Replace 3270462 with the numeric Site ID from Site settings → Tracking Code.

Run vite build and look at dist/index.html. The tag is in <head>:

<script defer src="https://statable.com/js/3270462/s.js"></script>

vite dev does not inject it, so local browsing stays out of your numbers. Pass dev: true when you want it there too.

A missing or malformed siteId fails when Vite resolves the config, not when a visitor opens the page.

Options, each mapping to an attribute in the tracking script reference:

OptionTypeDefaultWhat it does
siteIdstring or numberrequiredNumeric Site ID
hoststringhttps://statable.comOrigin the tracker is served from, for proxying through your own domain
trackingApistring<host>/api/eventOverride the ingest endpoint
beforeSendstringnoneName of a global function that may adjust custom props before an event is sent
propsobjectnoneSticky custom properties added to every event from a page load
devbooleanfalseAlso inject in vite dev
disabledbooleanfalseSkip injection entirely

Approach 2: a tag in index.html

No dependency. Vite serves index.html as-is and only rewrites the bundle entries, so a plain tag survives the build.

<!-- index.html -->
<!doctype html>
<html lang="en">
  <head>
    <script defer src="https://statable.com/js/3270462/s.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

The Site ID is written into the file, so this approach cannot switch IDs between staging and production. Use Approach 1 and read the ID from the environment in vite.config.js, for example with Vite's loadEnv.

Multi-page builds

With several entries in build.rollupOptions.input, the plugin adds the tag to each one, and they all report to the same Site ID. With Approach 2 you paste the tag into every HTML file by hand.

Tracking custom events

The tracker exposes window.statable once it has loaded. The script is deferred, so guard the call:

window.statable?.t?.('Signup', { plan: 'pro' })

For TypeScript, declare the global once in src/vite-env.d.ts:

declare global {
  interface Window {
    statable?: {
      t: (event: string, props?: Record<string, unknown>) => void
    }
  }
}

export {}

Event naming is covered in Custom events.

Tracking page views in SPA

A Vite SPA changes the route without reloading the document. Every common router, including React Router, Vue Router and SvelteKit, calls history.pushState. Statable listens for that and counts the pageview. No router hook required.

Excluding internal traffic

Statable respects a per-browser opt-out flag in localStorage. To keep your own visits out, run this once in DevTools on the live site:

localStorage.setItem('analytics_ignore', 'true')

Remove it with localStorage.removeItem('analytics_ignore'). Full procedure in Verify installation.

Verify it's working

  • Open Statable Realtime in your dashboard.
  • Build, preview, and move between routes. Each view should appear within seconds.
  • vite dev shows nothing unless you passed dev: true. That is expected.
  • The full checklist is in Verify installation.

Common pitfalls

  • Importing the tracker as a module. import 'https://statable.com/js/.../s.js' makes Vite try to resolve it as a dependency. It is a plain script tag, not a module.
  • Mixing both approaches. The tracker then loads twice. The second copy exits at once, so nothing is counted twice, but it is a wasted download. Pick one.
  • Expecting numbers from vite dev. The plugin skips the dev server on purpose. Pass dev: true to change that.
  • A multi-page build with the tag in only one entry. The other pages report nothing.
  • Putting the tag at the end of <body>. The tracker registers early to capture engagement. Keep it in <head>.

See also: Astro, Install the tracking script, Custom events, JavaScript API.


Ready to take control of your web analytics? Try Statable free for 30 days. No credit card required, full feature access, built for GDPR. Start your free trial or view a live demo.