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 public key generated for the site in the dashboard. This key is intended to be visible in your website's code.

HTML
<script
  src="https://api.tracedart.com/analytics.js"
  data-api-key="YOUR_PUBLIC_KEY"
  defer
></script>

Public keys stay visible in the dashboard. Copy your site ID from Sites & Setup when calling the API, and keep it as a string to preserve its full value.

  • Loads asynchronously
  • Starts a first-party visitor token
  • Captures pageviews, sessions, active time, scroll depth, and referrer context

Secret keys and backend API

Use a secret key to read a site's visitor and device data from your backend. In Sites & Setup → Secret Keys, enter a name and select Generate Secret Key. Site admins and owners can create and manage these keys.

Secret keys contain 43 characters and no prefix. Copy the key when it is generated: the full value is shown once. Store it as TRACEDART_SECRET_KEY in your backend's environment or secret manager. Never put it in browser code, a tracking snippet, or a public environment variable.

Send the key in the Authorization: Bearer header. To check your connection, replace SITE_ID with the ID displayed in the dashboard:

Shell
curl -H "Authorization: Bearer $TRACEDART_SECRET_KEY" "https://api.tracedart.com/api/server/sites/SITE_ID"
MethodEndpointReturns
GET/api/server/sites/:siteIdThe site's ID, publicId, name, and domain.
GET/api/server/sites/:siteId/visitors/:visitorIdVisitor details, sessions, pageviews, events, and device information.
GET/api/server/sites/:siteId/devices/:deviceIdThe device's linked visitors and recent activity on this site.

Each secret key is limited to its site, including nested device activity. Use that site's own secret key to read another site's records. The dashboard can still show matching devices across your workspace.

The tracker exposes visitorId and deviceId through window.tracedart.profile after collection, and in the tracedart:collect event. Pass the needed ID to your backend and make the lookup there. Your backend must authorize who can request this data; a visitor or device ID is not authentication.

JavaScript
// Run on your backend. Authorize the caller before returning visitor data.
const response = await fetch(
  "https://api.tracedart.com/api/server/sites/" +
    encodeURIComponent(process.env.TRACEDART_SITE_ID) +
    "/visitors/" + encodeURIComponent(visitorId),
  { headers: { Authorization: "Bearer " + process.env.TRACEDART_SECRET_KEY } }
);
if (!response.ok) throw new Error("TraceDart lookup failed: " + response.status);
const visitor = await response.json();

Invalid or revoked keys return 401. A site or record outside the key's scope returns 404. Rotating or revoking a secret key takes effect immediately; update your backend when you rotate. A key becomes inactive if its creator loses admin access, and moving a site to another workspace revokes its secret keys.

The secret-key API currently supports read-only lookups. Assigning authenticated user IDs and the website-to-app identity handoff are planned separately.

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 accepts an optional userId field for matching within a site. Because collection uses a public key, this value is not verified account identity.

A private API for assigning authenticated users to visitors is planned. Secret keys currently support backend lookups only.

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.

Automatic recognition across your sites

Sites in the same workspace automatically share a deviceId when fingerprint evidence links their visitors. Each site keeps its own visitorId.

The collection response includes deviceId and profile.deviceId. The dashboard visitor profile shows linked sites and their recent activity. Authenticated integrations can fetch the same profile with GET /api/dashboard/sites/:siteId/devices/:deviceId using a dashboard session with access to that site. Public collection keys do not grant access to this history.

Matching stays within one workspace. Ambiguous matches remain separate, bots do not establish links, and sites without a workspace stay isolated. The ID represents a likely browser environment; submitted user IDs do not establish cross-site links or prove a person's identity.

Component hashes

ComponentWhat it checksHow it is measured
stableBrowser/device basicsReads user agent, vendor, platform, hardware hints, cookies, DNT, PDF viewer, touch points, Client Hints, and Brave detection.
graphicsGPU and renderingQueries WebGL/WebGL2/WebGPU, renders canvas text/shapes, then hashes rendering output.
audioAudio stackRenders a fixed OfflineAudioContext oscillator/compressor graph and hashes the sample result.
fontsInstalled fontsMeasures hidden text against base font families to detect available fonts.
localeLanguage and regionReads browser languages, timezone, offset, Intl options, and speech voices.
capabilitiesBrowser feature setChecks API presence, CSS support, media preferences, storage, touch, plugins, and permissions.
displayScreen and layoutReads screen/window dimensions, color depth, DPR, viewport, orientation, and measured UI sizes.
networkBrowser network hintsReads Network Information API type, effective type, save-data, downlink bucket, and RTT bucket.
mathRuntime math behaviorRuns fixed floating-point Math operations and hashes the results.
timingTimer precisionSamples performance.now() deltas and buckets the timer resolution.
storageStorage environmentChecks cookies, local/session storage, IndexedDB, openDatabase, quota, persistence, and OPFS.
mediaCodecs and devicesChecks media codec support, MediaCapabilities, WebCodecs, and media device counts.
permissionsPermission statesQueries browser permissions such as camera, microphone, geolocation, clipboard, notifications, sensors, and push.
automationBot/headless hintsChecks 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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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

FieldTypeNotes
typestringAlways "goal.completed" today.
siteIdstringSite the goal belongs to.
goal.id / goal.nameobjectThe configured goal that completed.
visitorIdstringThe converting visitor.
sessionIdstringThe session the completion happened in.
event.name / event.pageUrlobjectPresent for event goals — the event name and the page URL it fired on.
pageview.path / pageview.urlobjectPresent for path goals — the page path and full URL that matched.
occurredAtstringISO 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.

JavaScript
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:

MethodEndpointNotes
GET/api/dashboard/sites/:id/visitors/:visitorId/exportJSON export of the visitor's full record.
DELETE/api/dashboard/sites/:id/visitors/:visitorIdPermanent, 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, public 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 public key should only collect from domains configured for that site. Requests from unknown origins are rejected by the backend.

Add the domains you own in the dashboard before installing the script on a live site.