docs / install / javascript

JavaScript, React and Vue

The same tracker as the script tag, as an npm package for bundled apps, with a React provider and a Vue plugin.

All three use your site key (kst_...), take the same options and send the same events as the script tag, so read that page for events, identifying users and privacy. They send nothing during server rendering.

@knockstat/browser

npm install @knockstat/browser
import { init, track, identify, reset } from "@knockstat/browser";

init({ site: "kst_xxxx" }); // sends to https://app.knockstat.com/v1/e by default
track("signup", { plan: "pro", seats: 3 });

init({ site, api, autoPageviews = true, outboundLinks = true, engagement = true, allowLocalhost = false, distinctId }) starts tracking once; later calls return the same client. Pass distinctId when you know the user at load, so the first page view carries it.

CallDoes
track(name, props?)Sends a custom event. Name and property rules are the tag’s.
pageview()Sends a $pageview for the current URL. Needed only with autoPageviews: false.
identify(distinctId)Sets distinct_id on later events, in memory only. identify(null) clears it.
reset()Clears the id (log out).

Page views follow history.pushState, replaceState and popstate, so routers that use the History API need nothing more.

React and Next.js

npm install @knockstat/react

Wrap your app in the provider once. Its props after site are the init options, read on first mount. It is StrictMode-safe and sends one initial page view.

// src/main.tsx (Vite)
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { KnockstatProvider } from "@knockstat/react";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <KnockstatProvider site="kst_xxxx">
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </KnockstatProvider>
  </StrictMode>,
);
import { useKnockstat } from "@knockstat/react";

function SignupButton() {
  const { track, identify } = useKnockstat();
  return (
    <button onClick={() => { identify("user-123"); track("signup", { plan: "pro" }); }}>
      Sign up
    </button>
  );
}

React Router (BrowserRouter), Next.js, TanStack Router and Remix navigate through the History API, so you add nothing per route. For a router that does not (for example a memory router), set autoPageviews={false} and call usePageview(path) in each page. Requires React 18 or later.

Next.js app router: put the provider in the root layout. The package entry is marked "use client", so a server component can import it; call useKnockstat() only from client components.

// app/layout.tsx
import { KnockstatProvider } from "@knockstat/react";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <KnockstatProvider site="kst_xxxx">{children}</KnockstatProvider>
      </body>
    </html>
  );
}

Vue and Nuxt

npm install @knockstat/vue
// src/main.ts
import { createApp } from "vue";
import { createRouter, createWebHistory } from "vue-router";
import knockstat from "@knockstat/vue";
import App from "./App.vue";
import routes from "./routes";

createApp(App)
  .use(createRouter({ history: createWebHistory(), routes }))
  .use(knockstat, { site: "kst_xxxx" })
  .mount("#app");
<script setup lang="ts">
import { useKnockstat } from "@knockstat/vue";

const { track, identify } = useKnockstat();
function signup() {
  identify("user-123");
  track("signup", { plan: "pro" });
}
</script>

<template>
  <button @click="signup">Sign up</button>
  <button @click="$knockstat.track('cta_click')">Try it</button>
</template>

Vue Router’s createWebHistory() uses the History API, so page views are automatic. createWebHashHistory() changes only the hash, which is not sent as part of the path: use autoPageviews: false and call pageview() in router.afterEach. Requires Vue 3.3 or later.

Nuxt 3: install the plugin in the browser only, in a .client.ts plugin:

// plugins/knockstat.client.ts
import knockstat from "@knockstat/vue";

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(knockstat, { site: useRuntimeConfig().public.knockstatSite });
});

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: { public: { knockstatSite: "kst_xxxx" } },
});

On the server useKnockstat() is a queue that is never sent, so call track from event handlers or onMounted.

Self-hosted ingest

Every entry point takes an api option for the beacon URL: init({ site, api: "https://stats.example.com/v1/e" }), <KnockstatProvider site="kst_xxxx" api="..."> or app.use(knockstat, { site, api }).

Stuck? Email [email protected].