Types
The TypeScript types exported from the package root, which are shared by the server, tracker, client and dashboard.
The root export, analytik, contains types only. There is no runtime code in it, so importing from it adds nothing to a bundle.
import type { Overview, PaymentInput, PrivacyMode } from 'analytik'
Which import do I need
The root holds types only. Everything with code in it has its own subpath, so a bundle only gets what it imports.
| Import | What it gives you | Use it when |
|---|---|---|
analytik |
Types only (this page). | You type your own code against the API. |
analytik/server |
createAnalytik() and the server types. |
You run the server. See Server API. |
analytik/client |
createClient() for the browser without React. |
You track from your own front end code. See Tracker. |
analytik/react |
AnalytikProvider, useAnalytik, useTrackPageviews, TrackClick. |
You use React. See React. |
analytik/dashboard, analytik/dashboard/styles.css |
The Dashboard component, its parts and its stylesheet. |
You embed the dashboard. See Dashboard embedding. |
analytik/standalone |
withDashboard(), which wraps a fetch handler so it also serves the dashboard page. |
The server should serve the dashboard from the same deployment. |
analytik/email |
Email senders for email.send. |
You turn on owner emails. See Email notifications. |
analytik/migrate |
openStorage() and seedDemo(), the helpers the CLI uses. |
You script a migration or fill a test database. |
analytik/storage/d1, analytik/storage/postgres, analytik/storage/sqlite, analytik/storage/memory |
One storage driver each. | You choose where the data lives. See Storage. |
analytik/adapters/stripe, /dodo, /lemonsqueezy, /paddle, /polar, /razorpay, /creem, /gumroad |
verify() and toPayment() for one provider’s webhook. |
You handle a webhook in your own code. The server’s built-in webhook route already uses them, so for the normal setup you import nothing. |
analytik/analytik.js, analytik/analytik-vitals.js |
The built tracker script and the Core Web Vitals file. | You serve the tracker from your own files. See Tracker. |
analytik/package.json |
The package manifest. | A tool needs to read the version. |
Unions
type PrivacyMode = 'strict' | 'enriched' | 'persistent'
type Interval = 'hour' | 'day' | 'week' | 'month'
type EventType = 'pageview' | 'goal' | 'outbound' | 'ping' | 'identify' | 'revenue'
type PaymentKind = 'payment' | 'refund'
type PaymentMatch = 'metadata' | 'return_page' | 'customer' | 'email' | 'timing'
type PaymentProvider = 'stripe' | 'dodo' | 'lemonsqueezy' | 'paddle' | 'polar' | 'razorpay' | 'creem' | 'gumroad'
type Dimension =
| 'channel'
| 'source'
| 'referrer'
| 'campaign'
| 'medium'
| 'term'
| 'content'
| 'ref'
| 'page'
| 'entry'
| 'exit'
| 'country'
| 'region'
| 'city'
| 'browser'
| 'os'
| 'device'
| 'event'
| 'outbound'
| 'goal'
type Props = Record<string, string | number | boolean | null>
Site
interface Site {
id: string
name: string
domain: string
timezone: string
currency: string
privacyMode: PrivacyMode
retentionDays: number | null
allowLocalhost: boolean
/** Tracking is paused: tracker events and server goals are dropped, payments are still recorded. */
paused: boolean
/** Addresses and CIDR ranges (at least /8 for IPv4, /32 for IPv6) whose events are dropped. */
ignoredIps: string[]
/** Events from browsers holding an admin session are dropped; needs dashboard and tracker on one origin. */
ignoreAdmins: boolean
/** Targets for goals, at most 20. */
targets: GoalTarget[]
/** Percent of page views, 0 to 100, that measure Core Web Vitals; 0 turns it off. */
vitalsSample: number
createdAt: number // Unix milliseconds
/** Which providers have a webhook secret configured. Secrets are never returned. */
webhooks?: Record<PaymentProvider, boolean>
/** Token for the read-only share link, or null when sharing is off. */
shareToken?: string | null
}
type TargetPeriod = 'week' | 'month' | 'quarter'
interface GoalTarget {
goal: string
target: number // a whole number
period: TargetPeriod
}
interface TargetProgress extends GoalTarget {
count: number // goals since the period began
start: number // Unix milliseconds, [start, end) in the site's time zone
end: number
projection: number | null // null until a tenth of the period has passed
}
interface TargetsResult {
now: number
targets: TargetProgress[]
}
interface VitalValues {
samples: number // reports that carry any metric
lcp: number | null // 75th percentile, milliseconds
inp: number | null // milliseconds
cls: number | null // a score
}
interface VitalsResult {
enabled: boolean // whether the site measures them
total: VitalValues
pages: (VitalValues & { path: string })[] // up to 50, most reports first
}
Events and payments
/** What the tracker posts to `POST {basePath}/event`. */
interface TrackerPayload {
w: string // site id
t: EventType
u: string // url
r?: string // referrer
vid?: string
sid?: string
sw?: number // screen width
n?: string // name
p?: Props
d?: number // engaged milliseconds
a?: number // amount
c?: string // currency
o?: string // order id
m?: PrivacyMode
}
interface PaymentInput {
id: string
/** Minor units (cents). */
amount: number
currency: string
kind?: PaymentKind
email?: string
name?: string
customerId?: string
subscriptionId?: string
orderId?: string
visitorId?: string
sessionId?: string
renewal?: boolean
/** Unix milliseconds. Defaults to now. */
ts?: number
/**
* Refunds without their own id: the total refunded for the order so far.
* Only the part not recorded yet is stored.
*/
refundedTotal?: number
}
interface Payment {
id: string
amount: number
currency: string
siteId: string
provider: string
kind: PaymentKind
ts: number
visitorId: string | null
sessionId: string | null
customerId: string | null
email: string | null
name: string | null
renewal: boolean
matchedBy: PaymentMatch | null
subscriptionId: string | null
orderId: string | null
}
interface AttributionIds {
analytik_visitor_id: string
analytik_session_id: string
}
Queries and results
Overview.revenue, orders and the other revenue figures count only payments in the site’s own currency. Payments in any other currency are listed in otherCurrencies, not converted.
interface Filters {
[dimension: string]: string | undefined
}
interface Query {
from: number // Unix ms, inclusive
to: number // Unix ms, exclusive
interval?: Interval
tz?: string
filters?: Filters
}
interface Delta {
value: number
previous: number
/** Relative change, `null` when `previous` is 0. */
change: number | null
}
interface Overview {
visitors: Delta
sessions: Delta
pageviews: Delta
bounceRate: Delta
avgDurationMs: Delta
revenue: Delta
orders: Delta
conversionRate: Delta
revenuePerVisitor: Delta
currency: string
online: number
/** Payments in other currencies than the site's, left out of the revenue numbers above. */
otherCurrencies: { currency: string; amount: number; orders: number }[]
}
interface SiteSummary {
siteId: string
visitors: number
revenue: number // in the site's currency, minor units
orders: number
currency: string
online: number
traffic?: number[] // visitors per bucket, with `series`
sales?: number[] // revenue per bucket (minor units), with `series`
previous?: { visitors: number; revenue: number; orders: number } // with `compare=1`
}
interface TimeseriesPoint {
ts: number // bucket start, Unix ms
visitors: number
sessions: number
pageviews: number
revenue: number
orders: number
bounceRate: number // 0 to 1
avgDurationMs: number
conversionRate: number // 0 to 1
revenuePerVisitor: number
}
interface BreakdownRow {
key: string
visitors: number
sessions: number
pageviews: number
revenue: number
orders: number
conversionRate: number
}
interface Realtime {
online: number
recent: { ts: number; type: EventType; name: string | null; path: string | null; country: string | null }[]
locations: RealtimeVisit[]
}
// A visit active in the last five minutes that has a location.
interface RealtimeVisit {
lat: number
lon: number
country: string | null
city: string | null
sessionId: string
visitorId: string
page: string | null // the page the visitor is on now
source: string
browser: string | null
device: string | null
startedAt: number
lastSeen: number
}
interface SessionSummary {
id: string
visitorId: string
startedAt: number
durationMs: number
pageviews: number
goals: number
entryPage: string | null
exitPage: string | null
source: string
channel: string
country: string | null
city: string | null
browser: string | null
os: string | null
device: string | null
revenue: number
}
interface EventRow {
id: string
ts: number
type: EventType
name: string | null
path: string | null
props: Props | null
sessionId: string
visitorId: string
}
interface Page<T> {
items: T[]
/** `null` on the last page, and whenever `sort` or `offset` is used. */
nextCursor: string | null
/** Every match, not only this page. */
total: number
}
Funnels
interface Funnel {
id: string
name: string
steps: FunnelStep[]
}
interface FunnelStep {
type: 'page' | 'goal'
/** Page path (supports a trailing `*`) or goal name. */
match: string
}
interface FunnelResult {
funnel: Funnel
steps: { match: string; visitors: number; dropOff: number | null }[]
}
Test data
Body and answer of POST /debug/generate, for servers created with debug: true.
interface TestDataInput {
/** Write into this site instead of making new test sites. */
siteId?: string
/** New test sites to make, 1 to 20. Default 1. */
sites?: number
/** Days of history ending now, 0 to 730; 0 makes empty sites. Default 30. */
days?: number
/** Average visits per day and site, 0 to 100,000; 0 makes empty sites. Default 500. */
visitorsPerDay?: number
/** Multiplies every price (900, 2,900 and 9,900 minor units). Default 1. */
priceScale?: number
/** Currency of new test sites. Default `USD`. */
currency?: string
/** New sites differ like real ones (empty, quiet, busy, just launched, paused…); visitorsPerDay and priceScale don't apply. */
mix?: boolean
}
interface TestDataResult {
sites: { id: string; name: string }[]
counts: { visitors: number; sessions: number; events: number; payments: number }
/** How long writing took, in ms. */
durationMs: number
}