# Tracking recipes

> Copyable recipes for tracking custom events and user interactions


import { CodeBlock } from "@/components/docs";
import { Callout } from "@/components/docs";
import { Card, Cards } from "@/components/docs";

<Callout type="info">
  <strong>TL;DR:</strong> **Tracking recipes** you can copy and customize for custom events in your application. **Track only what you need** and **avoid duplicate events**.
</Callout>

These recipes show common ways to track user interactions and application events. Copy and customize them for your needs.

## Recipes

<Cards>
  <Card title="Toast tracking" href="/docs/hooks/toast-tracking">
    Track toast notifications automatically to understand user feedback patterns and error rates
  </Card>
  <Card title="Form tracking" href="/docs/hooks/form-tracking">
    Track form submissions with validation state and error patterns
  </Card>
  <Card title="Modal tracking" href="/docs/hooks/modal-tracking">
    Track when modals and dialogs are opened and closed
  </Card>
  <Card title="Feature usage" href="/docs/hooks/feature-usage">
    Track when users interact with specific features
  </Card>
  <Card title="Feedback tracking" href="/docs/hooks/feedback-tracking">
    Track user feedback with server actions and client hooks
  </Card>
</Cards>

## Best practices

### 1. Prevent duplicate events

Use refs or Sets to track what's already been tracked:

<CodeBlock 
  language="tsx"
  code={`const tracked = useRef(new Set<string>());

if (!tracked.current.has(eventId)) {
  tracked.current.add(eventId);
  track("event_name", { id: eventId });
}`}
/>

### 2. Track only essential data

Avoid tracking sensitive information or excessive data:

<CodeBlock 
  language="tsx"
  code={`// ✅ Good: only essential properties
track("purchase_completed", {
  order_id: "ORD-123",
  revenue: 99.99,
  currency: "USD",
});

// ❌ Avoid: too much data, includes PII
track("purchase_completed", {
  order_id: "ORD-123",
  revenue: 99.99,
  currency: "USD",
  email: "user@example.com", // PII
  full_address: "...", // Sensitive
  credit_card_last_4: "1234", // Sensitive
});`}
/>

### 3. Use consistent event names

Follow a naming convention (e.g. `snake_case`):

<CodeBlock 
  language="tsx"
  code={`// ✅ Good: consistent naming
track("button_clicked");
track("form_submitted");
track("modal_opened");

// ❌ Avoid: inconsistent naming
track("buttonClick");
track("form-submitted");
track("ModalOpened");`}
/>

### 4. Handle errors gracefully

Don't let tracking errors break your app:

<CodeBlock 
  language="tsx"
  code={`const trackSafely = useCallback((eventName: string, properties?: Record<string, unknown>) => {
  try {
    track(eventName, properties);
  } catch (error) {
    console.error("Tracking error:", error);
    // Don't throw: tracking failures shouldn't break the app
  }
}, []);`}
/>

The SDK also exports `trackError` for reporting handled errors and `flush` for sending queued events immediately.

### 5. Conditional tracking

Only track in production or when explicitly enabled. The `<Databuddy />` component's `disabled` prop already covers dev-environment gating; use a check like this only for tracking calls outside the component:

<CodeBlock 
  language="tsx"
  code={`export function useToastTracking() {
  const { toasts } = useSonner();
  const tracked = useRef(new Set<string | number>());
  const isEnabled = process.env.NODE_ENV === "production";

  useEffect(() => {
    if (!isEnabled) return;

    for (const toast of toasts) {
      if (!tracked.current.has(toast.id)) {
        tracked.current.add(toast.id);
        track("toast_shown", {
          type: toast.type,
          message: toast.title,
        });
      }
    }
  }, [toasts, isEnabled]);
}`}
/>

## Related

<Cards>
  <Card title="SDK reference" href="/docs/sdk">
    Complete SDK API reference and configuration options
  </Card>
  <Card title="React SDK" href="/docs/sdk/react">
    React-specific integration guide and examples
  </Card>
  <Card title="Tracker helpers" href="/docs/sdk/tracker">
    Helper functions for tracking custom events
  </Card>
</Cards>
