-
Notifications
You must be signed in to change notification settings - Fork 0
Home
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. |
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). |
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. |
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) 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" /><TaktBadge> props
| Prop | Type | Default | Description |
|---|---|---|---|
domain |
string |
— | Site identifier whose badge to render. |
variant |
'a' | 'b' | 'd' |
core | Badge variant. |
glyph |
'unplug' | 'dash' | 'off' | 'eyeoff' |
core | Badge glyph. |
lang |
'fr' | 'en' |
core | Badge language. |
host |
string |
— | Override the public host serving the SVG. |
The badge alt defaults to "takt" but can be overridden via passthrough. It also sets loading="lazy" and decoding="async".
<TaktEmbed> props
| Prop | Type | Default | Description |
|---|---|---|---|
domain |
string |
— | Site identifier whose embed to render. |
theme |
'light' | 'dark' | 'auto' |
core | Embed theme. |
lang |
'fr' | 'en' |
core | Embed language. |
host |
string |
— | Override the public host serving the page. |
width |
number |
404 |
Iframe width. |
height |
number |
264 |
Iframe height. |
title |
string |
takt |
Iframe title. |
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 by a consumer. It also sets loading="lazy".
For both widgets, the optional host prop must be an absolute http(s) URL (validated by core, which reduces it to its origin — path and query are dropped); an empty host means same-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' })- Repository: github.com/vskstudio/takt-solid
-
npm:
@vskstudio/takt-solid - Core: takt-core · its wiki
Core
Framework wrappers