DocsAPI reference
Reference

API reference

Every endpoint the analytics script talks to, and how to call them yourself from a server or a custom integration.

Authentication

There are two keys per project:

  • Public key: a UUID. Safe to embed in client HTML. Used for /track and /experiments/active.
  • Secret key: generate and rotate from Settings. Required for /server-events. Never ship to the browser.
Rotating a secret key
Old keys keep working for 24 hours after rotation, so you have a window to redeploy.

Endpoints

MethodPathAuthPurpose
GET/api/analytics/script.js?projectId=…PublicServe tracking script.
POST/api/analytics/trackPublicSubmit batched client events.
POST/api/analytics/server-eventsSecretSubmit a single server event with idempotency.
GET/api/analytics/experiments/activePublicFetch experiments for the script.

Track event payload

POST /api/analytics/track accepts a batch of events. Events are deduped server-side on (visitorId, timestamp, eventType, pathname).

interface TrackRequest { projectId: string; // your public key events: TrackEvent[]; } interface TrackEvent { eventType: "pageview" | "scroll" | "engagement" | "conversion" | "experiment_impression" | string; eventName?: string; // e.g. "signup", "purchase" eventData?: Record<string, unknown>; pathname: string; fullUrl: string; referrer?: string; sessionId: string; visitorId: string; timestamp: number; // epoch ms utm?: { source?: string; medium?: string; campaign?: string; term?: string; content?: string; }; }

Server event payload

POST /api/analytics/server-events accepts one event at a time. Authenticate with your project's secret key in the Authorization header. Pass experimentId + variantId when you want the conversion attributed to an A/B experiment variant.

interface ServerEventRequest { eventType: string; // e.g. "conversion" eventName: string; // e.g. "signup", "purchase" timestamp?: string; // ISO 8601 — defaults to ingestion time idempotencyKey?: string; // stable key for retry dedup (Stripe event ID, etc.) visitor?: { id?: string; // any stable anonymous ID (user ID, gmp_vid, hashed email) ip?: string; userAgent?: string; }; page?: string; // pathname to attribute the event to properties?: Record<string, unknown>; // Optional: attribute this conversion to an A/B experiment variant. // Grab both from window.grademypage.getExperimentAssignments() on the // browser and forward them through your backend to this endpoint. experimentId?: string; variantId?: string; }

Active experiments response

GET /api/analytics/experiments/active?projectId=… returns every running experiment. Responses are cached at the edge for 60s with a 30s stale-while-revalidate window.

interface ActiveExperimentsResponse { experiments: Experiment[]; } interface Experiment { id: string; name: string; type: "copy" | "css" | "layout"; targetUrl: string; urlMatchType: "all" | "exact" | "contains" | "starts_with"; trafficPercentage: number; // 0-100 variants: Variant[]; } interface Variant { id: string; name: string; isControl: boolean; weight: number; changes: VariantChange[]; } interface VariantChange { selector: string; changeType: "text" | "html" | "style" | "class" | "css"; property?: string; value: string; }