Custom events
Configure the client, track meaningful product outcomes, attach useful properties, and verify delivery.
1. Configure the client
Install and initialize Tracwell once in browser-only code. Add delivery callbacks while integrating so failures are visible instead of silent.
import { createTracwell } from "tracwell";
const analytics = createTracwell({
collectionMode: "product",
projectKey: "tw_live_...",
onDelivery(report) {
console.log("Tracwell delivery", report.status, report.eventIds);
},
onError(error) {
console.error("Tracwell error", error.code, error.issues);
},
});Use private mode for privacy-preserving website analytics. Use product mode when you need persistent anonymous identity, sessions, or identify().
2. Name the outcome
Name events after completed outcomes such as signup_completed, checkout_started, or report_exported. Keep the name stable and put changing values in properties.
- Start
- The first character must be a letter.
- Characters
- Letters, numbers, periods, underscores, colons, and hyphens.
- Length
- Between 1 and 100 characters.
- Reserved
identifyandpage_view.
plan_selected with a plan property over dynamic names such as starter_plan_selected and pro_plan_selected.3. Track after success
For actions confirmed by your backend, follow the server events guide to record the result with the same visitor/session identity.
Call track() after the product action succeeds. A button click expresses intent; the confirmed result is the useful outcome.
async function handleSignup() {
const account = await createAccount();
analytics.track("signup_completed", {
account_type: account.type,
plan: account.plan,
});
}track() returns the event ID when the event enters the delivery queue. It returns undefined when collection is blocked or validation fails; onError provides the reason for validation failures.
const eventId = analytics.track("signup_completed", {
plan: "starter",
source: "pricing",
});
if (!eventId) {
// Collection is blocked or the event did not pass validation.
}4. Add useful properties
Properties become filters and breakdowns in reports. Send dimensions you expect to compare later, using JSON-compatible strings, finite numbers, booleans, null, arrays, and nested objects.
analytics.track("report_exported", {
format: "csv",
filters: {
country: "IN",
range: "last_30_days",
},
included_sections: ["overview", "acquisition"],
row_count: 1842,
});- Properties
- Up to 100 keys across the event.
- Nesting
- Up to 4 levels deep.
- Arrays
- Up to 50 items.
- Keys
- Up to 128 characters.
- Strings
- Up to 1,024 characters.
- Event size
- Up to 16 KiB after serialization.
5. Verify the event
- 1
Open the live stream
Go to Events in the Tracwell dashboard and open the live stream.
- 2
Perform the action
Complete the real product outcome in your application.
- 3
Flush while testing
Call await analytics.flush() when you need to send the current batch immediately.
- 4
Inspect the event
Confirm the name, project, page, and properties match what you intended.
A delivery status of accepted means the collector returned a matching acceptance receipt. handed_off means the browser handed the batch to sendBeacon while the page was leaving; it is not a server acceptance confirmation.
Using the script build
If you installed the CDN script instead of the npm package, call the same API through window.tracwell.
window.tracwell?.track("signup_completed", {
plan: "starter",
source: "pricing",
});Common mistakes
- Tracking intent
- Record the successful outcome instead of only the click that started it.
- Dynamic names
- Keep names stable and move variants such as plan or source into properties.
- Duplicates
- Track an outcome from one owning success path, not from both a button and an effect.
- Manual pages
- Let the Browser SDK track standard History API navigation automatically.
- Sensitive data
- Use opaque internal identifiers and collect only what the report needs.