--- url: 'https://docs.kitbase.dev/index.md' description: >- Developer platform for product analytics, event tracking, bot & crawler detection, and AI visibility. SDKs for TypeScript, React, and Angular. --- # Kitbase Kitbase is a developer platform for product analytics and feature management: web analytics, custom events, bot & crawler detection, and AI visibility — with SDKs for TypeScript, React, and Angular. ## Set up tracking Install once, and pageviews, sessions, clicks, and users are tracked automatically. Pick your stack: New to Kitbase? Start with the [Web Analytics overview](/web-analytics) or the [Quick Start](/getting-started). ## Go deeper ## Watch the bots Two different features — one keeps bots **out** of your analytics, the other makes them **visible**: Bot *filtering* — excluding bots from your human visitor counts — is built into the SDK and needs no setup. See [bot filtering vs. bot detection](/crawler-detection#detection-vs-filtering). ## Use the dashboard ## Tools & reference ## Open source All Kitbase SDKs are MIT-licensed — [source on GitHub](https://github.com/scr2em/kitbase-sdk). --- --- url: 'https://docs.kitbase.dev/getting-started.md' description: Install the Kitbase SDK and send your first event in under five minutes. --- # Getting Started Get up and running with Kitbase in minutes. ## Installation ::: code-group ```bash [pnpm] pnpm add @kitbase/analytics ``` ```bash [npm] npm install @kitbase/analytics ``` ```bash [yarn] yarn add @kitbase/analytics ``` ::: ## Analytics & Events Track pageviews, sessions, and custom events. ```typescript import { init } from '@kitbase/analytics'; const kitbase = init({ sdkKey: '', }); // Track custom events await kitbase.track({ channel: 'payments', event: 'New Subscription', user_id: 'user-123', icon: '💰', notify: true, tags: { plan: 'premium', amount: 9.99, }, }); ``` [Learn more about Events →](/track-events) ## Next steps * [Web Analytics overview](/web-analytics) — how capture, filtering, and enrichment fit together. * [Track Events](/track-events) — channels, tags, notifications, and revenue tracking. * [SDKs & Tools](/sdks/) — React, Angular, the CLI, and the MCP server. * [Dashboard guide](/guide/) — analytics, events, sessions, and users views. --- --- url: 'https://docs.kitbase.dev/web-analytics.md' description: >- Privacy-friendly web analytics with one script tag or an npm SDK. Autocaptured pageviews, sessions, clicks, and users — enriched server-side, no cookies. --- # Web Analytics Kitbase tracks pageviews, sessions, clicks, scroll depth, outbound links, and users automatically — no cookies, no banners required. Install it once and the [autocapture system](/autocapture) does the rest; add [custom events](/track-events) and [user identification](/identify-users) when you're ready. Pick your installation path: ::: tip Script or SDK? Both run the same engine. The [tracking script](/tracking-script) is the npm SDK, pre-bundled and served from `https://kitbase.dev/lite.js` — use it when you don't have (or don't want) a build step. Use the [npm SDK](/sdks/javascript) when you want typed APIs, tree-shaking, and framework integration. ::: ## How it works 1. **Capture** — the script or SDK autocaptures pageviews, sessions, clicks, scroll depth, and outbound links in the browser. See the [autocapture reference](/autocapture) for every event and its payload. 2. **Filter** — obvious non-human traffic (headless browsers, testing tools, HTTP clients, known crawlers) is discarded before it's ever sent, and the server-side attribution pipeline excludes anything flagged as a bot from human counts. No configuration needed. 3. **Enrich** — the backend parses the User-Agent (device, browser, OS), derives geolocation from the IP (then drops the IP unless IP logging is enabled), and extracts UTM parameters. All enriched fields are first-class filter dimensions. 4. **Explore** — metrics, breakdowns, and filters live in the [Analytics dashboard](/guide/analytics); raw events in the [Events view](/guide/events). ## Reporting timezone Every date boundary in your reports — where "today" starts, which day a visit at 00:30 belongs to, which hour a heatmap cell covers — is resolved in the project's **reporting timezone**. Set it per project under **Settings → General → Reporting**; it defaults to UTC. It is deliberately a project setting rather than something each request decides. Because the server holds it, the dashboard, the API, the CLI, exports, and the Slack assistant all cut the same period the same way — so two people in different countries reading the same project see the same numbers, and a scheduled export matches the dashboard it came from. Two things worth knowing before you change it: * **Past numbers are restated, not lost.** Traffic is stored as exact instants; the timezone only decides where the day boundaries fall. Moving from UTC to `Africa/Cairo` re-cuts yesterday at a different moment, so a daily figure can move. Moving it back restores the previous figures exactly. * **Explicit dates follow it too.** `from=2026-08-01&to=2026-08-01` means that calendar day in the project's zone, not in the caller's. Set it from the CLI with: ```bash kitbase settings update --reportingTimezone Africa/Cairo ``` ## Compare to an earlier period {#compare-periods} Every analytics report that takes a date range answers for two periods in one call: the one you asked for, and an earlier one to measure it against. **You get a comparison whether or not you ask for one.** Send none of the parameters below and a report compares against the **previous period** — the window of the same length immediately before your selection. Send one to compare against something else. | Parameter | Value | Notes | |---|---|---| | `comparePreset` | `previous_period` · `previous_week` · `previous_month` · `previous_quarter` · `previous_year` | Defaults to `previous_period`. Wins over `compareFrom`/`compareTo` when both are sent | | `compareFrom` | `YYYY-MM-DD` | Start of a custom window, inclusive. Must be sent with `compareTo` | | `compareTo` | `YYYY-MM-DD` | End of a custom window, inclusive. Must be sent with `compareFrom` | Both windows are resolved in the project's **reporting timezone** (above), so a comparison is always cut the same way the period it compares against is. A custom pair may cover a different length than your selection; the presets are described next. ### What each preset means **`previous_period`** keeps the *length* of your selection and ends exactly where it starts, so the two windows never overlap — 7 days compares against the 7 days immediately before them. **The calendar presets** answer a different question: how does this compare with how things have been going. Each one is the week, month, quarter or year **running up to** your selection, ending the day it begins — `previous_month` on 5–12 August is 5 July to 5 August. Month lengths clamp, so a selection starting May 31 reaches back to April 30. Those windows are usually **longer** than your selection, and the figures are reported as they are — a month's traffic really is more than a week's. The delta answers "this week against the month behind it", not "this week against a like-sized week"; use `previous_period` when you want equal lengths. ::: tip These windows never overlap your selection Every preset ends where your selection starts, so no row is ever counted on both sides of a comparison — whatever length each side happens to be. ::: A comparison window may not start **more than a year** before your selection. A comparison you asked for that reaches further is refused with `VAL_001`, as are a lone `compareFrom` or `compareTo` and a pair given back to front — half-honouring any of them would answer a question you did not ask. The default is treated differently on purpose: select more than a year of traffic and you get the report with **no comparison beside it**, rather than an error. You asked for a report; the comparison was ours to add, so it is ours to drop. ### What comes back Comparison figures are added to the shape a report already had, and only when you asked for them: | Field | Where | Meaning | |---|---|---| | `comparisonWindow` | Top level of the response | `{ from, to }` in UTC, echoing what was actually read. **`from` is inclusive, `to` is exclusive** | | `previous…` | On each row | The same figure over the comparison window — `previousCount`, `previousRequestCount`, `previousAvgDurationMs`, and so on, named after the metric it mirrors | | `absoluteChange` | On each row | Current minus previous, for the metric the report is ranked on. On rows ranked by a **rate** it is a **percentage-point** difference: 0.4286 against 0.2857 reads as `14.3` | | `percentageChange` | On each row | Relative change. **Null when the previous figure is 0** — no percentage describes going from nothing to something | Two conventions are worth reading before you chart any of it: * **Zero and null mean different things.** A count reads `0` when the thing existed but wasn't seen in the comparison window — a crawler that arrived this week reads `previousRequestCount: 0`. An average, a position, or a share reads `null` when it was never measured at all: a page nobody opened has no average duration, and 0 ms would claim it was read instantly. * **Ranking is always the selected period's.** Which rows appear, and in which order, is decided by the window you selected alone. A page, bot, domain or brand that showed up *only* in the comparison window is not listed, and each listed row's earlier figures are looked up by its own name or URL — never read off whatever occupied that position back then. Reports that are a **series** rather than a list return the earlier window as its own set of points, carrying that window's own dates. Chart them against each other by position, not by date — the two windows rarely hold the same number of buckets. ### Which reports accept it | Report | Parameter effect | |---|---| | `GET /web-analytics` | Each metric's existing `previous` and `change` read from your chosen window instead of the implicit one | | `GET /web-analytics/timeline` | The existing `previousPeriod` series reads from your chosen window, bucketed at the same interval | | `GET /web-analytics/breakdown` | Adds `previousCount` (plus `previousVisitors` / `previousViews` on the `top_page` dimension) and the change fields per row | | `GET /web-analytics/pages/duration` | Adds `previousAvgDurationMs` and the change fields per page | | `GET /web-analytics/dimension/timeline` | Adds `comparisonData`, the same daily series over the comparison window | The summary and the timeline have always reported *some* previous period — the implicit one immediately before your selection. These parameters decide which window that is; they don't add the field. The same three parameters work on the [crawler reports](/crawler-detection#compare-periods) and on [AI visibility](/ai-visibility#comparison), and on the matching [MCP tools](/sdks/mcp#period-comparison), so a comparison chosen in one place means the same thing everywhere. ## Going deeper ::: info Bots are filtered here — detected elsewhere Web analytics silently **excludes** bots so your numbers reflect humans. If you want to **see** the bots — which AI crawlers and search engines visit your site, verified against spoofing — that's the separate [Bot & Crawler Detection](/crawler-detection) feature. The difference is explained in [detection vs. filtering](/crawler-detection#detection-vs-filtering). ::: ## Next steps * [Quick Start](/getting-started) — install the SDK and send your first event. * [Analytics dashboard guide](/guide/analytics) — metrics, breakdowns, and filtering. * [API reference](/api-reference) — query events and analytics over REST. --- --- url: 'https://docs.kitbase.dev/tracking-script.md' description: >- Add Kitbase analytics to any website with a lightweight tracking script. Privacy-friendly, no cookies, works on static sites, SPAs, and SSR. --- # Tracking Script Kitbase provides a lightweight tracking script for web analytics and event tracking. It is privacy-friendly, requires no cookies by default, and works on any website -- static HTML, single-page applications (SPAs), and server-side rendered (SSR) frameworks alike. ## Installation ### Script Tag (Simplest) Add these two snippets to your HTML `` section: ```html ``` The `KITBASE_CONFIG` object **must** be set before the tracking script loads. The `defer` attribute ensures the script is fetched in parallel and executed after the HTML is parsed, so it never blocks page rendering. ### NPM Package For JavaScript/TypeScript projects with a build step, install the SDK as a dependency: ::: code-group ```bash [pnpm] pnpm add @kitbase/analytics ``` ```bash [npm] npm install @kitbase/analytics ``` ```bash [yarn] yarn add @kitbase/analytics ``` ::: Then initialize the SDK in your application entry point: ```typescript import { init } from '@kitbase/analytics'; const kitbase = init({ sdkKey: 'YOUR_SDK_KEY', analytics: { autoTrackPageViews: true, trackBfcacheRestore: true, autoTrackOutboundLinks: true, autoTrackClicks: true, autoTrackScrollDepth: true, autoTrackVisibility: true, }, }); ``` ::: tip Lite Build For a smaller bundle size (~12KB vs ~50KB), use the lite build which excludes offline queue support: ```typescript import { init } from '@kitbase/analytics/lite'; ``` The lite build has the same API surface for analytics and event tracking. Only the offline queue module (`offline` config) is removed. ::: ## Configuration Reference Below is the full configuration object with every available option and its default value. ```typescript const kitbase = init({ // ── Core ─────────────────────────────────────────────── sdkKey: 'YOUR_SDK_KEY', // Required. SDK API key from the dashboard. debug: false, // Enable console logging for troubleshooting. baseUrl: 'https://ingest.kitbase.dev', // Ingestion endpoint. Override for self-hosted. storage: localStorage, // Storage backend for the anonymous ID. // Set to `null` to disable persistence. storageKey: 'kitbase_anonymous_id', // Key used in the storage backend. // ── Analytics ────────────────────────────────────────── analytics: { autoTrackPageViews: true, // Fire `screen_view` on every navigation. trackBfcacheRestore: true, // Fire `screen_view` on bfcache restore (back/forward in MPAs). autoTrackOutboundLinks: true, // Fire `outbound_link` for external link clicks. autoTrackClicks: true, // Fire `click` for interactive element clicks. autoTrackScrollDepth: true, // Fire `scroll_depth` when the user leaves a page. autoTrackVisibility: true, // Observe `data-kb-track-visibility` elements. }, // ── Offline Queue ────────────────────────────────────── offline: { enabled: false, // Queue events when offline, sync when back. maxQueueSize: 1000, // Maximum events held in the queue. flushInterval: 30000, // Flush interval in milliseconds (30 s). flushBatchSize: 50, // Events sent per batch. maxRetries: 3, // Retry attempts before an event is dropped. retryBaseDelay: 1000, // Base delay for exponential backoff (1 s). }, }); ``` ### Configuration Options Summary | Option | Type | Default | Description | |--------|------|---------|-------------| | `sdkKey` | `string` | -- | **Required.** SDK API key from your dashboard. | | `debug` | `boolean` | `false` | Enable verbose console logging. | | `baseUrl` | `string` | `'https://ingest.kitbase.dev'` | Ingestion endpoint. Override for self-hosted deployments. | | `storage` | `Storage \| null` | `localStorage` | Storage backend for anonymous ID persistence. Set to `null` to disable. | | `storageKey` | `string` | `'kitbase_anonymous_id'` | Key name used in the storage backend. | #### `analytics` | Option | Type | Default | Description | |--------|------|---------|-------------| | `autoTrackPageViews` | `boolean` | `true` | Automatically track page views on navigation. | | `trackBfcacheRestore` | `boolean` | `true` | Track a pageview when the browser restores a page from the back-forward cache (bfcache). Important for MPA sites where back/forward navigation does not re-execute scripts. | | `autoTrackOutboundLinks` | `boolean` | `true` | Track clicks on links to external domains. | | `autoTrackClicks` | `boolean` | `true` | Track clicks on interactive elements. | | `autoTrackScrollDepth` | `boolean` | `true` | Report maximum scroll depth when the user leaves. | | `autoTrackVisibility` | `boolean` | `true` | Observe elements with `data-kb-track-visibility`. | #### `offline` | Option | Type | Default | Description | |--------|------|---------|-------------| | `enabled` | `boolean` | `false` | Enable the offline event queue. | | `maxQueueSize` | `number` | `1000` | Maximum events to hold in the queue. | | `flushInterval` | `number` | `30000` | Interval between automatic flushes (ms). | | `flushBatchSize` | `number` | `50` | Events sent per flush batch. | | `maxRetries` | `number` | `3` | Retry attempts before an event is dropped. | | `retryBaseDelay` | `number` | `1000` | Base delay for exponential backoff (ms). | ## What the Script Does (Behind the Scenes) When the tracking script loads, it performs the following sequence of actions automatically. Understanding this lifecycle helps you debug issues and reason about the data you see in the dashboard. ### 1. Generates an Anonymous ID A UUID v4 is generated and stored in `localStorage` under the key `kitbase_anonymous_id`. This ID persists across page loads so the same browser is recognized as the same visitor without cookies. If `storage` is set to `null`, the ID is regenerated on every page load. ### 2. Starts a Session A `session_start` event is fired with a new session ID (UUID v4). The session remains active as long as events arrive within 30 minutes of inactivity. After 30 minutes of inactivity, the next interaction starts a fresh session. ### 3. Listens for Page Navigations The SDK patches `history.pushState` and listens for the `popstate` event. This means route changes in single-page applications are detected automatically -- no framework-specific code is needed. ### 4. Tracks Page Views A `screen_view` event is fired on the initial page load and on every subsequent navigation (pushState or popstate). Each event includes the page path, document title, referrer, and any UTM parameters present in the URL. ### 5. Monitors Clicks on Interactive Elements A global click listener watches for clicks on interactive elements: ``, `