Documentation

Everything here works the same way regardless of what you're building — a static site, a React app, or a backend service. Pick a project's API key from the Projects tab and follow the steps below.

Quickstart

Add the SDK to your page, once, near the top of your HTML:

<script src="https://obsvoid.xyz/obsvoid.js"></script>

Then initialize it and send your first pageview:

<script>
  const obsvoid = new Obsvoid({
    endpoint: "https://api.obsvoid.xyz/e",
    apiKey: "YOUR_API_KEY",
  });
  obsvoid.pageview();
  window.obsvoid = obsvoid; // so other scripts on the page can reach it
</script>

Events are batched and sent every few seconds (or immediately if 20+ pile up, or when the page is closed) — a short delay before something shows up in Analytics is normal, not a bug.

Custom events

Call capture with an event name and any properties you want attached:

obsvoid.capture("signed_up", { plan: "free" });
obsvoid.capture("checkout_completed", { amount: 49.99, currency: "USD" });

Single-page apps

Client-side navigation (React Router, Next.js, Vue Router, etc.) never triggers a full page load, so pageview() firing once on the initial load only counts your very first view. Call it again on every route change. Next.js Pages Router example:

import { useEffect } from "react";
import { useRouter } from "next/router";

function MyApp({ Component, pageProps }) {
  const router = useRouter();

  useEffect(() => {
    const trackPageview = () => window.obsvoid?.pageview();
    router.events.on("routeChangeComplete", trackPageview);
    return () => router.events.off("routeChangeComplete", trackPageview);
  }, [router.events]);

  return <Component {...pageProps} />;
}

For the App Router, React Router, or anything else, hook into whichever navigation/effect fires after a route change completes and call window.obsvoid?.pageview() there — the principle is the same everywhere.

Server-side events

No SDK needed on a backend — just POST directly, in whatever language you're already using:

curl -X POST https://api.obsvoid.xyz/e \
  -H "X-Obsvoid-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event": "order_completed", "distinct_id": "user_123", "properties": {"amount": 49.99}}'

SDK options

OptionRequiredDescription
endpointYesAlways https://api.obsvoid.xyz/e
apiKeyYesYour project's API key from the Projects tab
distinctIdNoOverride the visitor ID. By default the SDK generates a random one and persists it in localStorage for you
flushIntervalNoHow often queued events are sent, in milliseconds (default 5000)

A session ID is also generated automatically and stored in sessionStorage, so events from the same browser tab get grouped into one session for bounce rate/duration stats.

API reference

POST https://api.obsvoid.xyz/e

Headers:

  • X-Obsvoid-Key — required, your project's API key
  • Content-Type: application/json

Body — a single event:

{
  "event": "signed_up",
  "distinct_id": "user_123",
  "properties": { "plan": "free" }
}

Or a batch — this is what the SDK sends under the hood, useful if you're integrating from a backend that wants to send several at once:

{
  "events": [
    { "event": "signed_up", "distinct_id": "user_123" },
    { "event": "clicked_upgrade", "distinct_id": "user_123" }
  ]
}

Fields:

FieldDescription
eventEvent name. Required unless message is set instead.
distinct_idStable identifier for the visitor/user sending this event.
session_idOptional — groups events into a session.
urlOptional — the page URL this event happened on.
typeDefaults to "event". Use "log" for backend log lines.
level / messageFor log-style entries — e.g. level: "error".
propertiesAny custom data as a JSON object.
timestampOptional ISO 8601 string. Defaults to when the server receives it.

Response on success:

{ "accepted": 1 }
Docs · Obsvoid