/** * Public TypeScript types for the tgram-analytics SDK. * * Import these in your application to get full type safety: * @example * import type { TGAOptions, EventProperties } from "tgram-analytics"; */ /** * A single JSON-safe scalar — the building block of {@link EventProperties}. */ type EventPropertyScalar = string | number | boolean | null; /** * The value side of an entry in {@link EventProperties}. * * Either a scalar primitive or an array of scalars. Nested arrays and * object-valued properties are intentionally not supported so the JSONB * column stays cheap to query (a per-element pie chart is one * `jsonb_array_elements_text` call away). */ type EventPropertyValue = EventPropertyScalar | EventPropertyScalar[]; /** * Arbitrary key-value properties attached to events. * * Values must be JSON-serialisable primitives — or arrays of such * primitives — so they can be stored in the server's JSONB `properties` * column without transformation. * * @example Scalar properties * const props: EventProperties = { amount: 49, plan: "pro", trial: false }; * * @example Array-valued property (e.g. multi-select onboarding answer) * const props: EventProperties = { * role: "creator", * interest_set: ["vertical_to_horizontal", "unsure"], // <-- array of strings * }; * * @remarks * Keys ending in `_set` are sorted alphabetically at write time by the * server, which makes `GROUP BY properties->'interest_set'`-style "most * common combos" queries trivial. Other array properties are stored in * the order you sent them. */ type EventProperties = Record; /** * Fine-grained options for the event batching queue. * Passed as the `batch` option to {@link TGAOptions}. * * @example * TGA.init("proj_xxx", { * serverUrl: "https://analytics.example.com", * batch: { maxSize: 20, maxWait: 3000 }, * }); */ interface BatchOptions { /** * Maximum number of events to buffer before the queue is force-flushed. * @default 10 */ maxSize?: number; /** * Maximum milliseconds to wait before the queue is automatically flushed, * even if `maxSize` has not been reached. * @default 5000 */ maxWait?: number; } /** * Configuration passed to {@link TGAClient.init}. * * Only `serverUrl` is required. All other options have sensible defaults * that work for most websites without any extra configuration. * * @example Minimal setup * TGA.init("proj_abc123", { serverUrl: "https://analytics.example.com" }); * * @example Full setup * TGA.init("proj_abc123", { * serverUrl: "https://analytics.example.com", * autoPageview: true, * respectDNT: true, * batch: { maxSize: 10, maxWait: 5000 }, * }); */ interface TGAOptions { /** * Base URL of your tgram-analytics server — no trailing slash. * * This is the URL where you deployed the server Docker image. * @example "https://analytics.example.com" */ serverUrl: string; /** * When `true` (the default), the SDK automatically sends a pageview event: * - On initial page load. * - On every SPA route change (works with React Router, Vue Router, etc.). * * Set to `false` if you want to call `TGA.pageview()` manually. * @default true */ autoPageview?: boolean; /** * When `true` (the default), the SDK checks the browser's * [Do Not Track](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DNT) * setting. If DNT is enabled, **all** tracking is silently skipped — no * requests are sent. * * Set to `false` only if you have obtained explicit user consent through * other means (e.g. a cookie consent banner). * @default true */ respectDNT?: boolean; /** * Enables event batching to reduce the number of network requests. * * - Pass `true` to use the default batch settings (maxSize: 10, maxWait: 5 s). * - Pass a {@link BatchOptions} object to customise the thresholds. * - Leave unset (or `false`) to send every event immediately. * * Batching is useful for high-frequency events (e.g. scroll depth, clicks). * For low-volume events like purchases, immediate sending is preferred. * @default false */ batch?: boolean | BatchOptions; /** * Override the auto-generated session ID with your own value. * * The session ID is a UUID that groups events from the same browser tab. * Leave this unset unless you are managing sessions server-side. */ sessionId?: string; /** * When `true` (the default), the SDK automatically collects visitor * context (OS, browser, language, screen, timezone, device type) and * includes it as `$`-prefixed properties on every event. * * Set to `false` to disable automatic context collection. * @default true */ collectContext?: boolean; } /** * Core SDK client. * * `TGAClient` implements all public SDK methods. It is instantiated once as a * module-level singleton in `index.ts` and exported as `TGA`. You almost never * need to import this class directly — use the singleton instead: * * @example * import TGA from "tgram-analytics"; * * TGA.init("proj_xxx", { serverUrl: "https://analytics.example.com" }); * TGA.track("purchase", { amount: 49 }); */ declare class TGAClient { private apiKey; private serverUrl; private sessionId; private initialized; private optedOut; private globalProperties; private queue; private teardownSpa; /** * Initialises the SDK. **Must be called once** before using any other method. * * What `init()` does: * 1. Validates the API key and `serverUrl`. * 2. Generates (or restores) a session ID from `sessionStorage`. * 3. Checks Do Not Track — silently disables all tracking if enabled. * 4. Reads UTM parameters from the current URL and stores them as global * properties so they appear on every event in this session. * 5. Sends an initial pageview and installs SPA route-change listeners * (when `autoPageview` is `true`, which is the default). * 6. Installs `visibilitychange` / `pagehide` listeners to flush any * pending queue when the user leaves the page. * * Calling `init()` a second time logs a warning and does nothing — it is * not an error. Call {@link reset} first if you need a clean slate. * * @param apiKey - Your project API key. Must start with `"proj_"`. * Get it from the Telegram bot with `/projects`. * @param options - Configuration options. See {@link TGAOptions}. * * @throws {Error} If `apiKey` is missing, does not start with `"proj_"`, or * if `options.serverUrl` is not provided. * * @example * TGA.init("proj_abc123", { * serverUrl: "https://analytics.example.com", * }); */ init(apiKey: string, options: TGAOptions): void; /** * Tracks a custom named event. * * The event is sent to `POST /api/v1/track` on the server. * Properties from {@link identify} are automatically merged in. * * @param eventName - A string identifier for the event, e.g. `"purchase"`, * `"signup"`, `"button_click"`. Use snake_case for * consistency with the server's query patterns. * @param properties - Optional key-value metadata for this specific event. * Values must be strings, numbers, booleans, `null`, or * arrays of those scalars. Nested arrays and object * values are rejected synchronously. * * @throws {Error} When `properties` contains an unsupported value shape * (e.g. nested object, nested array, `undefined`, `NaN`). * The error names the bad key and is intended to surface * developer mistakes in dev — production callers should * never see this if types are honoured. * * @example Track a purchase * TGA.track("purchase", { amount: 49, currency: "USD", plan: "pro" }); * * @example Track a multi-select answer (array property) * TGA.track("onboarding_completed", { * role: "creator", * interest_set: ["vertical_to_horizontal", "unsure"], * }); * * @example Track a signup with no extra properties * TGA.track("signup"); */ track(eventName: string, properties?: EventProperties): void; /** * Tracks a pageview event. * * You rarely need to call this manually — when `autoPageview` is `true` * (the default), pageviews are sent automatically on init and on every * SPA route change. * * The event is sent to `POST /api/v1/pageview` on the server. * * @param url - The page URL or path to record. Defaults to * `window.location.pathname + window.location.search`. * @param referrer - The referring URL. Defaults to `document.referrer`. * * @example Manual pageview for a custom URL * TGA.pageview("/virtual/checkout-step-2"); * * @example With explicit referrer * TGA.pageview("/pricing", "https://twitter.com"); */ pageview(url?: string, referrer?: string): void; /** * Attaches persistent properties to every subsequent {@link track} call. * * Properties set via `identify()` are merged into the `properties` field of * each event. Per-event properties (passed directly to `track()`) take * precedence over identified properties when keys conflict. * * Use `identify()` for attributes that apply to the whole session, such as * the user's subscription plan, locale, or A/B test variant. * * @param properties - Key-value pairs to merge into global session * properties. Values follow the same rules as * {@link track}: scalars (string / number / boolean / * null) or arrays of those scalars. * * @throws {Error} When `properties` contains an unsupported value shape. * The error names the bad key. * * @example Single A/B variant * TGA.identify({ plan: "pro", locale: "en-US", ab_variant: "B" }); * TGA.track("purchase"); // => properties includes plan, locale, ab_variant * * @example Multi-bucket experiment membership (array property) * TGA.identify({ ab_variants: ["A", "B"] }); */ identify(properties: EventProperties): void; /** * Opts the current user in or out of analytics. * * - Opting **out** immediately flushes any pending queue and silently * suppresses all future `track()` and `pageview()` calls. * - Opting **in** re-enables tracking for the rest of the page session. * * **The opt-out state is not persisted.** If you want persistence across * page loads, store the preference yourself (e.g. in `localStorage`) and * call `TGA.opt("out")` on every page load when the preference is set. * * @param status - `"in"` to enable tracking, `"out"` to disable it. * * @example Honour a consent flag stored in localStorage * if (localStorage.getItem("analytics_consent") === "false") { * TGA.opt("out"); * } */ opt(status: "in" | "out"): void; /** * Immediately sends all buffered events. * * This is a no-op when batching is disabled (the default). When batching is * enabled, call `flush()` before programmatic navigations or logout to ensure * no events are lost. * * @returns A Promise that resolves once the flush is complete. * * @example Flush before navigating away * await TGA.flush(); * window.location.href = "/thank-you"; */ flush(): Promise; /** * Starts a new session. * * Clears the current session ID from `sessionStorage` and generates a fresh * one. Also clears all properties set via {@link identify}. * * Call this after a user logs out to ensure subsequent events are not * attributed to the previous user's session. * * @example * function onLogout() { * TGA.reset(); * // Now tracking continues under a new anonymous session. * } */ reset(): void; /** * Guards all public tracking methods. * * Returns `false` (and logs a warning) when called before `init()`, so that * misconfiguration fails visibly in development. Returns `false` silently * when the user has opted out. * * @param method - Name of the calling method, used in the warning message. * @returns `true` when it is safe to proceed with the send. */ private guardReady; /** * Routes a payload to either the batching queue or the transport layer, * depending on whether batching is enabled. * * @param endpoint - API path relative to `serverUrl` (e.g. `"/api/v1/track"`). * @param payload - JSON-serialisable request body. */ private dispatch; } /** * tgram-analytics JS SDK * * Lightweight, privacy-first analytics for websites and SPAs. * Zero dependencies. < 2 KB gzipped. * * --- * * ## Install via npm * ```bash * npm install tgram-analytics * ``` * * ## Install via ` * * ``` * * ## Quick start (ESM / TypeScript) * ```ts * import TGA from "tgram-analytics"; * * TGA.init("proj_xxx", { serverUrl: "https://analytics.example.com" }); * * // Pageviews are tracked automatically on load and SPA route changes. * // Track custom events manually: * TGA.track("purchase", { amount: 49, plan: "pro" }); * ``` * * ## Quick start (` * * ``` * * @module tgram-analytics */ /** * The global singleton SDK instance. * * Import this object and call `.init()` once at the top of your application. * Do **not** create a `new TGAClient()` — use this singleton instead. * * @example * import TGA from "tgram-analytics"; * TGA.init("proj_xxx", { serverUrl: "https://analytics.example.com" }); */ declare const TGA: TGAClient; export { type BatchOptions, type EventProperties, TGAClient, type TGAOptions, TGA as default };