A thin, SSR-safe Solid layer over @vskstudio/takt-core. It never changes the wire payload or the privacy guarantees — it just makes Takt feel native in a Solid app.
<Takt>component — drop it once near the root; it boots analytics inonMountand provides the instance to the tree.useTakt()— grab the live instance anywhere; returns a never-throwing no-op before mount or during SSR.createTaktEvent()&<TaktEvent>— declarative click tracking.<takt-analytics>custom element — framework-agnostic, Solid-free embed for non-Solid pages.
pnpm add @vskstudio/takt-solid @vskstudio/takt-coresolid-js (^1.8) and @vskstudio/takt-core are peer dependencies.
Mount <Takt> once near your root. It fires an initial pageview, wires SPA navigation, and provides the instance to every descendant:
import { Takt } from '@vskstudio/takt-solid'
export function App() {
return (
<Takt domain="example.com" outbound files={['pdf', 'zip']}>
<Routes />
</Takt>
)
}Then track custom events from any descendant:
import { useTakt } from '@vskstudio/takt-solid'
export function SignupButton() {
const takt = useTakt()
return (
<button
onClick={() =>
takt.track('Signup', {
props: { plan: 'pro' },
revenue: { amount: '29.00', currency: 'EUR' },
})
}
>
Sign up
</button>
)
}useTakt() always returns a usable instance: before <Takt> mounts (or during SSR) it hands back a never-throwing no-op, so your handlers never crash.
| Prop | Type | Default | Description |
|---|---|---|---|
domain |
string |
location.hostname |
Site identifier sent with every event. |
endpoint |
string |
/api/event |
Ingestion endpoint. |
scriptOrigin |
string |
— | First-party origin to derive the endpoint from ({origin}/api/event) — your Takt domain or a custom domain to dodge ad-blockers (endpoint wins over it). |
outbound |
boolean |
false |
Auto-track outbound link clicks. |
files |
boolean | string[] |
false |
Auto-track file downloads; pass extensions to restrict. |
spa |
boolean |
true |
Track SPA navigations (pushState/replaceState + popstate). |
track404 |
boolean |
false |
Report a 404 event when the page is an error page ([data-takt-404] / <meta name="takt:404"> marker, or a 404 HTTP status). |
respectDnt |
boolean |
true |
Suppress events when the browser's Do Not Track is enabled. |
excludeLocalhost |
boolean |
true |
Suppress events on localhost and private IP ranges. |
enabled |
boolean |
true |
Master switch — set to false to fully disable tracking. |
sampleRate |
number |
1 |
Fraction of sessions to track (0–1). |
trackQuery |
boolean |
false |
Include the query string in page URLs. |
queryParams |
string[] |
— | Query parameters to keep when trackQuery is false. |
exclude |
string[] |
— | Path prefixes never tracked, e.g. ['/app', '/account'] (segment-bounded, checked at send time). |
scrubUrl |
(url: string) => string |
— | Transform page URLs before they are sent. Function prop — config only, not available as a custom-element attribute. |
tagged |
boolean |
false |
Auto-track [data-takt-tag] element clicks. |
Config props are read once when
<Takt>mounts. Changing them afterwards has no effect — remount the component to reconfigure.
Two equivalent ways to track a click without writing a handler.
createTaktEvent() returns an { onClick } you spread onto any element:
import { createTaktEvent } from '@vskstudio/takt-solid'
export function BuyButton() {
const onBuy = createTaktEvent({ name: 'Buy', revenue: { amount: '9.00', currency: 'EUR' } })
return <button {...onBuy}>Buy</button>
}<TaktEvent> wraps a single child and composes its existing onClick:
import { TaktEvent } from '@vskstudio/takt-solid'
export function SignupCta(props: { onClick: () => void }) {
return (
<TaktEvent name="Signup" props={{ plan: 'pro' }}>
<button onClick={props.onClick}>Sign up</button>
</TaktEvent>
)
}Both resolve the active instance at click time, so they work inside <Takt> or with an init()-driven core setup, falling back to core's default instance otherwise.
For non-Solid pages, import the side-effecting ./element entry to register <takt-analytics>. It bundles core and pulls in no Solid runtime:
import '@vskstudio/takt-solid/element'<takt-analytics domain="example.com" outbound files></takt-analytics>Privacy attributes (respect-dnt, exclude-localhost, spa) are on by default and only disabled by an explicit "false"/"0". Presence flags (outbound, files, track-404) activate when the attribute is present.
<Takt> boots inside onMount and is guarded by Solid's isServer, so nothing touches window/document on the server. useTakt() returns the no-op during the server pass. Importing @vskstudio/takt-solid/element on the server is a no-op — registration is guarded behind a customElements check.
All privacy behavior lives in @vskstudio/takt-core: Do Not Track support, localhost exclusion, opt-in/opt-out consent, and a frozen wire payload. This wrapper never alters any of it.
Thin wrappers over the server-rendered badge SVG and embed page. <TaktBadge> renders an <img>, <TaktEmbed> an <iframe>; both accept native passthrough props.
import { TaktBadge, TaktEmbed } from '@vskstudio/takt-solid'
;<TaktBadge domain="example.com" variant="d" glyph="dash" />
;<TaktEmbed domain="example.com" theme="dark" />The embed <iframe> is hardened: it ships with sandbox="allow-scripts allow-same-origin" and a fixed referrerpolicy="strict-origin-when-cross-origin", both wrapper-controlled and not overridable. The badge alt defaults to "takt" but can be overridden via passthrough. The optional host prop must be an absolute http(s) URL (validated by core, which reduces it to its origin); src is wrapper-controlled and cannot be overridden.
For programmatic stats, createStats returns a typed public-API client:
import { createStats } from '@vskstudio/takt-solid'
const stats = createStats({ domain: 'example.com' })
const summary = await stats.summary({ period: '7d' })