npm package
One install with subpath exports for React, Next, any other framework and your server. The tracker is bundled into your own code, so there is no separate file for anything to block.
npm i trckableThe package is MIT licensed, has no dependencies, and adds 2,264 bytes gzipped to a React app. CI fails above 2,560.
React
Works in Vite, React Router, Remix or anything else that renders React.
import { Analytics } from 'trckable/react'
export default function App() {
return (
<>
<Analytics site="tkb_a1b2c3d4" host="https://stats.example.com" />
{/* your app */}
</>
)
}It starts exactly one tracker, even under React's StrictMode double-render, and counts route changes automatically.
Next.js
The most accurate setup there is: events go through your own domain, so nothing recognises them as analytics and Safari keeps the visitor cookie for 400 days instead of seven.
// app/layout.tsx
import { Analytics } from 'trckable/next'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Analytics site="tkb_a1b2c3d4" />
</body>
</html>
)
}// app/api/e/route.ts — same-origin: past analytics blocklists, 400-day Safari visitors
export { POST } from 'trckable/next'Then set two environment variables (the proxy key is in Settings → General → For developers):
# .env
TRCKABLE_HOST=https://stats.example.com
TRCKABLE_PROXY_KEY=your-proxy-keyThe proxy key is what lets your server tell trckable the visitor's address. See the proxy for why that matters and how it is kept safe.
Any other framework
import { init } from 'trckable'
init({ site: 'tkb_a1b2c3d4', host: 'https://stats.example.com' })Call it once, as early as you can. Vue, Svelte, Astro, Solid, Qwik and plain JavaScript all work the same way.
Any other server
trckable/server gives you the same proxy for any runtime that speaks
(Request) => Response — Hono, SvelteKit, Astro, Remix, Workers, Bun, Deno:
import { proxy } from 'trckable/server'
const trckable = proxy({ host: 'https://stats.example.com', proxyKey: process.env.TRCKABLE_PROXY_KEY })
app.post('/api/e', (c) => trckable(c.req.raw))Robots and AI crawlers
Robots never run JavaScript, so the browser script never sees them. One call in your server middleware forwards them, and only them: a request whose user agent does not look like a robot costs nothing.
// Next.js — middleware.ts
import { reportCrawler } from 'trckable/server'
export function middleware(req) {
reportCrawler({
host: 'https://stats.example.com',
site: 'tkb_a1b2c3d4',
key: process.env.TRCKABLE_PROXY_KEY,
url: req.url,
ua: req.headers.get('user-agent'),
})
}It needs the site's proxy key, never waits for an answer, and never throws, so a robot report cannot slow down or break a page. Turn the AI crawlers & bots module on first (Settings → Modules): until then nothing is recorded.
Goals
import { track } from 'trckable'
track('signup', { plan: 'pro' })Or with no code at all:
<button data-trckable-goal="signup" data-trckable-goal-plan="pro">Start trial</button>
<section data-trckable-scroll="saw_pricing">…</section>More in Goals.
Options
| Option | |
|---|---|
site | Site id (tkb_…). Required |
host | Your trckable server. Leave it out to use the same-origin route /api/e |
api | The full events endpoint, if it is not ${host}/api/e |
cookieless | No cookie, nothing stored. Call consent(true) to switch after consent |
dev | Track on localhost, including automated browsers |
domain | Cookie domain, to share visitors across subdomains |
What the package cannot do
Modules are compiled into your bundle at your build time, not chosen by the server. Turning a module on in the dashboard changes the script-tag install within the hour; an app that bundles the tracker picks the change up on its next deploy. The Modules page says so where it matters.
trckable's own cookie bar is not in the package build yet, for the same reason — it is a script-tag feature today.
The CLI
The same package carries a command line tool:
npx trckable init # detect the framework and wire it up, after showing a diff
npx trckable doctor # check an install from the outside
npx trckable mcp # run the MCP server for your assistantinit never edits your checkout code. It prints the snippet and leaves the
decision to you.