TraceDart integration guide
Install the browser script, collect traffic, resolve returning anonymous visitors, and keep collection scoped to your domains.
Install the browser script
Paste the snippet into the head of every page you want to track. Use the production key generated for the site in the dashboard.
<script
src="https://api.tracedart.com/analytics.js"
data-api-key="td_sk_..."
defer
></script>- Loads asynchronously
- Starts a first-party visitor token
- Captures pageviews, sessions, active time, scroll depth, and referrer context
Known user identity
TraceDart resolves returning visitors using the first-party visitor token, full and component fingerprint hashes, browser context, and network observations, including ASN, ISP, VPN/proxy, datacenter, and provider signals.
The collect API also accepts an optional userId field, which takes precedence over every other signal once it is present on a request. This is meant for server-side integrations that already authenticate the visitor and forward that ID when they call the collect endpoint directly.
tracedart.identify(userId) browser helper is planned. Until it ships, the browser script has no way to attach a user ID on its own — only a server-side integration calling the collect API can set one.Fingerprint signals
TraceDart creates one full td-v2 browser fingerprint hash and a set of smaller component hashes. Raw component values are not stored: the browser hashes each signal group first, then the backend HMACs those hashes before saving them.
Identity matching uses a userId attached through the collect API when one is present, then the first-party visitor token, then the full fingerprint hash, then a conservative component match across stable signal groups.
Component hashes
| Component | What it checks | How it is measured |
|---|---|---|
stable | Browser/device basics | Reads user agent, vendor, platform, hardware hints, cookies, DNT, PDF viewer, touch points, Client Hints, and Brave detection. |
graphics | GPU and rendering | Queries WebGL/WebGL2/WebGPU, renders canvas text/shapes, then hashes rendering output. |
audio | Audio stack | Renders a fixed OfflineAudioContext oscillator/compressor graph and hashes the sample result. |
fonts | Installed fonts | Measures hidden text against base font families to detect available fonts. |
locale | Language and region | Reads browser languages, timezone, offset, Intl options, and speech voices. |
capabilities | Browser feature set | Checks API presence, CSS support, media preferences, storage, touch, plugins, and permissions. |
display | Screen and layout | Reads screen/window dimensions, color depth, DPR, viewport, orientation, and measured UI sizes. |
network | Browser network hints | Reads Network Information API type, effective type, save-data, downlink bucket, and RTT bucket. |
math | Runtime math behavior | Runs fixed floating-point Math operations and hashes the results. |
timing | Timer precision | Samples performance.now() deltas and buckets the timer resolution. |
storage | Storage environment | Checks cookies, local/session storage, IndexedDB, openDatabase, quota, persistence, and OPFS. |
media | Codecs and devices | Checks media codec support, MediaCapabilities, WebCodecs, and media device counts. |
permissions | Permission states | Queries browser permissions such as camera, microphone, geolocation, clipboard, notifications, sensors, and push. |
automation | Bot/headless hints | Checks webdriver, headless user agent, plugin/MIME counts, chrome runtime, window gaps, visibility, and permissions API presence. |
Separate risk and context signals
TraceDart also records browser timezone context, private-mode detection, parsed browser/device fields, IP geolocation, ASN, ISP, VPN/proxy/Tor/datacenter, and provider signals. Those help explain traffic quality and risk, but they are separate from the browser fingerprint component hashes.
Track custom events
Use custom events for actions that matter more than a pageview: referral clicks, coupon copies, lead submissions, checkout clicks, demo requests, tool usage, or account creation.
After the install script has loaded, call window.tracedart.track with a stable event name and a small properties object.
window.tracedart?.track("demo_request", {
plan: "portfolio",
source: "pricing"
});- Use lowercase snake_case event names, such as referral_click or email_signup_success
- Send useful metadata, not sensitive data
- Keep property values short and stable so tables stay readable
TraceDart stores events with the current visitor, session, pageview, page URL, timestamp, referrer, UTM context, device, browser, location, and any custom properties you send. Events appear in the dashboard under Events & Goals, visitor timelines, and page-level event tables.
Event properties
Properties sent with tracedart.track(name, props) are explorable in the dashboard: open Events & Goals and click an event name to see its property keys ranked by frequency, then click a key for a per-value breakdown — count and unique visitors — over the selected date range. Keep values low-cardinality so that breakdown stays readable: plan names, categories, and step labels work well; raw IDs, emails, and other high-cardinality or sensitive values do not.
Track clicks
For outbound links, referral links, affiliate buttons, or CTA clicks, attach a listener and send the destination plus campaign context.
document.querySelectorAll("[data-track-referral]").forEach((link) => {
link.addEventListener("click", () => {
window.tracedart?.track("referral_click", {
label: link.textContent.trim(),
destination_host: new URL(link.href).hostname,
campaign: link.dataset.campaign,
placement: link.dataset.placement
});
});
});Track forms
Track the form action, result, source, and page. Do not send email addresses, passwords, payment data, health data, full prompts, or other sensitive values in event properties.
const form = document.querySelector("[data-lead-form]");
form?.addEventListener("submit", async (event) => {
event.preventDefault();
window.tracedart?.track("lead_submit", {
source: "footer",
page: window.location.pathname
});
try {
await submitLeadForm(form);
window.tracedart?.track("lead_success", {
source: "footer",
page: window.location.pathname
});
} catch {
window.tracedart?.track("lead_error", {
source: "footer",
page: window.location.pathname
});
}
});Track product or content tools
For calculators, search, filters, AI tools, or recommendation flows, track the action and numeric context rather than raw user text.
window.tracedart?.track("tool_used", {
tool_name: "unit_converter",
input_count: 4
});
window.tracedart?.track("site_search", {
search_area: "docs",
query_length: searchInput.value.trim().length
});Goals & funnels
Goals are user-defined in Events & Goals in the dashboard. A goal matches either a custom event name exactly, or a page path — an exact path, or a prefix ending in * (for example /thanks* matches /thanks and /thanks/confirmed). The goals overview reports completions, unique converting visitors, and a conversion rate (converting visitors divided by unique visitors for the selected range).
If a site has no goals configured yet, TraceDart falls back to treating conversion-style event names as goals automatically — purchase, signup, lead, and names ending in _success or _conversion among them. This fallback only applies until you define your own goals.
window.tracedart?.track("email_signup_success", {
source: "blog_footer"
});
window.tracedart?.track("purchase_conversion", {
plan: "starter",
billing_cycle: "annual"
});Funnels build on the same event and path building blocks. Define 2-8 ordered steps in Events & Goals, each an event name or a path (wildcards allowed). A visitor only advances to a step after completing the previous step within the selected date range, and the dashboard reports per-step visitor counts and conversion, both from the previous step and from the funnel's start.
Guard events before the script loads
If your app may fire events before the deferred script has loaded, wrap tracking in a tiny helper. This keeps your UI code from throwing if analytics is unavailable.
function trackEvent(name, properties = {}) {
if (window.tracedart?.track) {
window.tracedart.track(name, properties);
}
}
trackEvent("cta_click", {
placement: "hero",
label: "Start trial"
});The tracker also exposes window.analyticsTrack as an alias for the same function.
Webhooks
Create webhooks per site in Settings → Webhooks. They fire on goal completions (goal.completed), and the signing secret (td_whs_...) is shown once, at creation time — store it somewhere safe.
Every delivery is a POST with a JSON body and three relevant headers: content-type: application/json, x-tracedart-event: goal.completed, and x-tracedart-signature: sha256=<hex>, where the hex digest is an HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret.
Payload
| Field | Type | Notes |
|---|---|---|
type | string | Always "goal.completed" today. |
siteId | string | Site the goal belongs to. |
goal.id / goal.name | object | The configured goal that completed. |
visitorId | string | The converting visitor. |
sessionId | string | The session the completion happened in. |
event.name / event.pageUrl | object | Present for event goals — the event name and the page URL it fired on. |
pageview.path / pageview.url | object | Present for path goals — the page path and full URL that matched. |
occurredAt | string | ISO 8601 timestamp of the completion. |
Verify deliveries
Recompute the signature over the raw, unparsed request body — re-serializing a parsed JSON object will not reproduce the same bytes and the signature will not match.
const crypto = require("node:crypto");
function isValidSignature(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const provided = String(signatureHeader || "").replace("sha256=", "");
const expectedBuffer = Buffer.from(expected, "hex");
const providedBuffer = Buffer.from(provided, "hex");
return (
expectedBuffer.length === providedBuffer.length &&
crypto.timingSafeEqual(expectedBuffer, providedBuffer)
);
}Retries and delivery
Failed deliveries retry up to 8 attempts total, with exponential backoff starting around 60 seconds and capped at 6 hours between attempts. A non-2xx response or a timeout counts as a failed attempt, and redirects are not followed — a 3xx response is recorded as a failure rather than chased. Respond with a 2xx status as soon as you have accepted the delivery, and do slower processing afterward.
Webhook URLs must be public http or https addresses; localhost, loopback, private (RFC1918), and link-local addresses are rejected, in both IPv4 and IPv6 form.
- Verify the signature against the raw request body, not a re-parsed or re-serialized copy
- Return a 2xx status quickly, then do slower work asynchronously
- Treat deliveries as at-least-once and dedupe on the payload if your handler is not naturally idempotent
Data requests & export
Visitor-level requests
Open any visitor's profile in the dashboard to Export data — a JSON download of that visitor's sessions, pageviews, events, and identity records (tokens, fingerprints, fingerprint components, and network observations) — or Delete visitor, which permanently erases the same visitor across every raw table. Aggregate rollups behind historical charts are left untouched, since they store anonymous daily counts rather than records tied to an individual visitor. Both actions require the admin role, and both have API equivalents:
| Method | Endpoint | Notes |
|---|---|---|
GET | /api/dashboard/sites/:id/visitors/:visitorId/export | JSON export of the visitor's full record. |
DELETE | /api/dashboard/sites/:id/visitors/:visitorId | Permanent, transactional erasure across all raw tables. |
Raw CSV export
Settings → Data export produces CSV downloads of sessions, pageviews, or events for the selected date range. Each download returns up to 10,000 rows; for larger date ranges, page through the dataset using the cursor returned in the API's x-next-cursor response header until it comes back empty.
Sharing & teams
Public dashboards
Settings → Public dashboard generates a read-only link (analytics.tracedart.com/public/?token=...) showing the same aggregate stats as your dashboard overview — traffic, sources, devices, locations — with no visitor-level data. Configured goal names and their completion counts are included, so avoid enabling sharing on a site where those are sensitive. Disable sharing at any time to revoke the link immediately.
Teams
Every account has a workspace. Invite teammates from the Team section using single-use invite links that expire after 14 days, each granting one role: viewer (read-only across every dashboard view), admin (manage goals, funnels, segments, webhooks, API keys, and exports), or owner (everything admin can do, plus managing members and invites). Revoke outstanding invites when someone offboards, so an unused link cannot be redeemed later.
Saved segments let you save the active filter combination from the filter bar and reapply it later without rebuilding it.
Realtime shows active visitors live, over roughly the last 5 minutes.
Protect allowed origins
Each site key should only collect from domains configured for that site. Requests from unknown origins are rejected by the backend.