> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getmilana.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Track Events

> Emit named events with optional attributes to mark important user actions in a session recording.

Milana watches session recordings directly, so it doesn't need granular event tracking the way traditional analytics tools do. We recommend tracking only a small number of high-signal events:

* **Key business drivers** — activation, conversion, cancellation, downgrades
* **Feature usage** — e.g. `product.aiAgent.firstMessage`, `report.exported`
* **Sampling helpers** — events that help Milana find the right population of sessions to analyze (though user and session metadata can also be used for this)

### Already using an event tracking tool?

If you already instrument events with a tool like Segment, Amplitude, or PostHog, you can add a `trackEvent` call alongside your existing tracking — there's no need to define a separate set of events for Milana. We don't need granular tracking, but we'll happily use it if you already have it.

```typescript theme={null}
// Your existing analytics helper
function trackAnalyticsEvent(name: string, properties: Record<string, unknown>) {
  posthog.capture(name, properties);
  milana.trackEvent(name, properties); // just add this line
}
```

***

## Usage

<Tabs>
  <Tab title="React">
    Use the `useMilana()` hook:

    ```tsx theme={null}
    import { useMilana } from "milana-js/react";

    function UpgradeButton({ plan }: { plan: string }) {
      const { trackEvent } = useMilana();

      const handleClick = useCallback(() => {
        trackEvent("upgrade_clicked", {
          plan,
          source: "pricing_page",
        });
        navigate("/checkout");
      }, [plan, trackEvent]);

      return <button onClick={handleClick}>Upgrade to {plan}</button>;
    }
    ```
  </Tab>

  <Tab title="JavaScript">
    ```typescript theme={null}
    import { trackEvent } from "milana-js";

    trackEvent("checkout_started");
    trackEvent("report_exported", { format: "pdf", pageCount: 12 });
    ```
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    Milana("trackEvent", "checkout_started");

    Milana("trackEvent", "report_exported", {
      format: "pdf",
      pageCount: 12,
      includeCharts: true,
    });
    ```
  </Tab>
</Tabs>

***

## Parameters

<ParamField path="eventName" type="string" required>
  A name that describes the action that occurred. Maximum 255 characters. Must be a non-empty string.
</ParamField>

<ParamField path="attributes" type="object">
  Optional key-value pairs to attach to the event. Keys must be 1–255 characters, string values must be 1–2048 characters. Values can be `string`, `number`, `boolean`, or `null`.

  Attributes with invalid keys, invalid string values, `undefined` values, or non-primitive values (objects, arrays) are silently dropped with a warning in the browser console.
</ParamField>

## Validation rules

The SDK validates each event and attribute before recording it. Invalid values are silently dropped — the event is still recorded with the valid attributes, and a warning is printed to the browser console.

| Rule                                                       | Behavior when violated                     |
| ---------------------------------------------------------- | ------------------------------------------ |
| Event name is empty                                        | Event is dropped entirely                  |
| Event name exceeds 255 characters                          | Event is dropped entirely                  |
| Attribute key is empty or exceeds 255 characters           | Attribute is dropped, event still recorded |
| String attribute value is empty or exceeds 2048 characters | Attribute is dropped, event still recorded |
| Attribute value is `undefined`                             | Attribute is dropped, event still recorded |
| Attribute value is a non-primitive (object, array)         | Attribute is dropped, event still recorded |

## Timing

`trackEvent()` is synchronous and returns immediately. If initialization hasn't completed yet when you call `trackEvent()`, the event is queued and replayed once the session starts. Events tracked before a session is sampled in are silently discarded.
