Website analytics
The Vital website client records only the page views and actions you call. It does not patch your router, read forms, create a persistent browser identifier, or capture browser crashes.
Create a website source
An organization owner creates the source and its origin-restricted ingest key.
- Add a Website source.Put it under an existing product or create a new product.
- Enter every production origin.Add the exact scheme and hostname visitors use.
- Review collection.Choose whether usage, country, and device details can be stored.
- Create an ingest key.Save the full value when it appears. Vital shows it once.
Origins are exact. https://example.com and https://www.example.comare separate entries, and a preview host needs its own origin. Check the URL after redirects before adding it. A source accepts up to 20 approved origins.
Install the client
React, Next.js, or another bundler
Download the versioned website package from the source setup screen, place it in a private project folder such as vendor, then install that local file. Replacevital-website-VERSION.tgz below with the exact downloaded filename. The package is not on the public npm registry.
# Use the exact name of the file you downloaded.
npm install ./vendor/vital-website-VERSION.tgzCreate the client in the browser after your component mounts. For Next.js, mount this component once in your layout and expose the source key through a public build variable.
"use client";
import { useEffect, useRef } from "react";
import { usePathname } from "next/navigation";
import { createClient, type Client } from "@vital/website";
const publicPages = new Set(["/", "/features", "/pricing"]);
export function VitalAnalytics() {
const pathname = usePathname();
const client = useRef<Client | null>(null);
useEffect(() => {
const key = process.env.NEXT_PUBLIC_VITAL_INGEST_KEY;
if (!key) return;
client.current = createClient({ key });
return () => {
client.current?.destroy();
client.current = null;
};
}, []);
useEffect(() => {
if (pathname && publicPages.has(pathname)) {
client.current?.pageview(pathname);
}
}, [pathname]);
return null;
}Save the component as app/VitalAnalytics.tsx, import it inapp/layout.tsx, and render <VitalAnalytics /> inside<body> alongside your page content.
Set NEXT_PUBLIC_VITAL_INGEST_KEY in each hosting environment and rebuild. Imports are safe during server rendering, but the client itself should be created in the browser.
HTML without a bundler
Download the standalone vital.js file shown in the source setup screen and place it in your public assets. Keep the initialization in a separate file so sites with a strict Content Security Policy do not need inline scripts.
<script src="/assets/vital.js"></script>
<script src="/assets/vital-init.js"></script>const vital = Vital.createClient({
key: "YOUR_PK_LIVE_INGEST_KEY",
});
const publicPages = new Set(["/", "/features", "/pricing"]);
if (publicPages.has(location.pathname)) {
vital.pageview();
}If your Content Security Policy limits network requests, addhttps://pulse-in.syvr.dev to connect-src. The hostname keeps Vital's original service name for compatibility.
Choose the public pages
Use a route allowlist and call pageview() after navigation. Keep account pages, private documents, and paths that reveal personal information out of the list. Query strings and fragments are removed before a page path leaves the browser.
For a router other than Next.js, subscribe to its normal navigation event and callpageview(pathname). Vital does not watch browser history automatically.
Track an action
Track the small set of actions that answer a product question, such as a download, completed setup, or feature use. Event names use lowercase letters, numbers, and underscores, and must start with a letter.
vital.track("template_downloaded", {
format: "pdf",
placement: "resources_page",
});
// This attempts the current batch before a navigation.
// A resolved promise does not prove every event was delivered.
void vital.flush();Properties may be strings, finite numbers, or booleans. Do not send names, email addresses, tokens, search text, form values, or private URLs. The client drops obvious sensitive fields, but no automatic filter can understand every value your site creates.
Connect consent
If your site requires opt-in consent, start disabled and enable Vital only after the visitor agrees. Disabling the client stops capture, clears its memory queue, and cancels an active send.
import { createClient } from "@vital/website";
const vital = createClient({
key: "YOUR_PK_LIVE_INGEST_KEY",
enabled: false,
});
// Call this from your site's consent controls.
export function setAnalyticsConsent(granted) {
vital.setEnabled(granted);
if (granted && ["/", "/features", "/pricing"].includes(location.pathname)) {
vital.pageview();
}
}Connect this function to your existing consent controls. Calling it with falsealso clears queued events. With the standalone HTML client, use Vital.createClientinstead of the package import.
The client also honors Global Privacy Control and Do Not Track. Do not work around either signal. Vital uses no cookies, local storage, or session storage, and keeps its small retry queue only in memory.
Verify the connection
Open Live for the website source, visit one allowed page, and look for a$pageview event. The browser batches for about one second. Allow up to one minute for a new key or collection change to reach every service cache.
Check the browser request, exact origin, route allowlist, build variable, and privacy signals in the troubleshooting guide.