Documentation
Type-safe events
Typos in event names silently split your data — signup_completed and signup_complete become
two different events. Declare your events once and TypeScript autocompletes names and checks
property shapes everywhere you track.
NPM package
Either pass an event map as a generic, or augment the global DtcEventMap interface once — the
augmentation types every tracker in your project, including window.__dtc.
Typed events
import { createTracker } from '@didtheyclick/sdk';
type MyEvents = {
signup_completed: { plan: string };
purchase_promo: { code: string };
};
const tracker = createTracker<MyEvents>({
websiteId: 'YOUR_API_KEY',
endpoint: 'https://www.didthey.click/api/collect'
});
tracker.track('signup_completed', { plan: 'pro' }); // ✅ autocompleted
tracker.track('signup_compleded', {}); // ❌ compile error// dtc.d.ts — anywhere in your project's include path
declare global {
interface DtcEventMap {
signup_completed: { plan: string };
purchase_promo: { code: string };
}
}
export {};
// Every tracker is now typed — no generic needed:
// createTracker(), createServerTracker() (from
// '@didtheyclick/sdk/server') and window.__dtc
// all autocomplete your event names.The same DtcEventMap augmentation also types createServerTracker from @didtheyclick/sdk/server, so client and server events share one definition.
Declare your events
The tracker lives on window.__dtc. Declare its types once in a .d.ts file anywhere in your
project:
Script tag typings
// dtc.d.ts — anywhere in your project's include path
export {};
declare global {
interface DtcEventMap {
signup_completed: { plan: string };
purchase_promo: { code: string };
}
interface Window {
__dtc?: {
track<K extends keyof DtcEventMap & string>(
name: K,
properties?: DtcEventMap[K]
): void;
identify(userId: string, traits?: Record<string, string>): void;
page(): void;
};
}
}window.__dtc?.track('purchase_promo', { code: 'LAUNCH20' }); // ✅
window.__dtc?.track('purchase_prom0'); // ❌ compile errorCompile-time only
These types exist purely in your editor and build. The tracker accepts any event name at runtime — nothing breaks for untyped callers, and events won't be rejected if the types drift.Keep values as strings
Event properties are string key/value pairs on the wire. Stick tostring values in
your event map so the types match what's actually sent.