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

# Troubleshooting & FAQ

> Solutions to common problems and frequently asked questions about the Milana SDK and session recording.

## SDK & Installation

<AccordionGroup>
  <Accordion title="Sessions are not appearing in the dashboard">
    Work through the following checks in order:

    <Steps>
      <Step title="Verify your credentials">
        Open your browser's developer tools and check the **Console** tab for any errors logged by the SDK (look for messages starting with `Milana:`). A misconfigured `productId` or `clientKey` will throw an error immediately on initialization and prevent any sessions from being recorded.
      </Step>

      <Step title="Check that the SDK initialized successfully">
        In the console, confirm there are no `Milana: Failed to initialize session` messages. If you see one, the SDK could not reach the ingest endpoint — check your network tab for failed requests to `in.getmilana.ai`.
      </Step>

      <Step title="Account for sampling">
        Enable debug mode to see whether the current session was sampled. Run this in your browser console, then refresh the page:

        ```js theme={null}
        localStorage.setItem("milana_debug_mode", "true");
        ```

        You may need to change the console log level from **Default levels** to **Verbose** to see all messages. After refresh, look for `Milana:` messages in the console — they will indicate whether the session was sampled and whether initialization succeeded.

        To disable debug mode later:

        ```js theme={null}
        localStorage.removeItem("milana_debug_mode");
        ```

        If you need to adjust sampling rates for your product, contact [help@getmilana.ai](mailto:help@getmilana.ai).
      </Step>

      <Step title="Allow time for processing">
        Milana waits until **30 minutes** of inactivity have occurred before finalizing a session, and it may take an additional **10 minutes** for it to be fully processed.
      </Step>

      <Step title="Check for ad blockers">
        Some browser ad blockers may block requests to `in.getmilana.ai`. Try disabling ad blockers, or contact [help@getmilana.ai](mailto:help@getmilana.ai) for help configuring a reverse proxy.
      </Step>

      <Step title="Check your Content Security Policy">
        If your site sends a `Content-Security-Policy` header, the SDK's network requests or script may be blocked. Add the following directives:

        * `connect-src https://in.getmilana.ai` — required for all installs, so the SDK can send recorded data.
        * `script-src https://cdn.getmilana.ai` — required for script-tag installs, so the SDK script can load.
        * For script-tag installs, the queue snippet is an inline `<script>`, so `script-src` must also include `'unsafe-inline'` or a nonce.

        Open the browser console and look for messages starting with `Refused to ... because it violates the following Content Security Policy directive:` to confirm whether CSP is the cause.
      </Step>
    </Steps>
  </Accordion>

  <Accordion title="Console error: Invalid product ID">
    The SDK throws this error when `productId` does not meet the required format:

    ```
    Milana: Invalid product ID, product ID must start with 'prd_' and be 30 characters long
    ```

    Your `productId` must:

    * Start with the prefix `prd_`
    * Be exactly **30 characters** in total

    Copy the product ID directly from your [Settings](https://app.getmilana.ai/settings) page to avoid typos. Do not trim, truncate, or modify it.
  </Accordion>

  <Accordion title="Console error: Invalid client key">
    The SDK throws this error when `clientKey` does not meet the required format:

    ```
    Milana: Invalid client key, client key must start with 'key_'
    ```

    Your `clientKey` must start with the prefix `key_`. Copy it directly from your [Settings](https://app.getmilana.ai/settings) page. If the key is correct but the error persists, the key may have been rotated — contact [help@getmilana.ai](mailto:help@getmilana.ai) to generate a new one.
  </Accordion>

  <Accordion title="Console warning: Event type exceeds max size, aborting">
    The SDK aborts the session and logs this warning when a single recorded event would exceed Milana's per-event size limit:

    ```
    Milana: Event type 2 exceeds max size, aborting. Application will continue unaffected
    ```

    This almost always means the DOM contains very large inline content — most commonly `<img>` tags with `data:image/...;base64,...` URIs, but also embedded SVGs or third-party widgets that ship megabytes of inline markup. Milana captures the full DOM (including every element's attributes) when recording starts, and inline data URIs — often hundreds of KB to several MB each — get embedded directly in that snapshot. A single large image is enough to blow past the limit.

    The fix is to mark the offending elements so they are blocked from the recording. Blocked elements are replaced with a same-sized placeholder, and their attributes (including the giant `src`) are dropped — layout and interactions are preserved, but the visual content of that element is not recorded.

    **Option 1 — add the `milana-block` class** to the affected element(s):

    ```html theme={null}
    <img class="milana-block" src="data:image/png;base64,iVBORw0KGgo..." />
    ```

    **Option 2 — use a `blockSelector`** if you can't add a class to every element. For example, to block all inline-data-URI images across your app:

    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{
        privacy: {
          blockSelector: 'img[src^="data:"]',
        },
      }}
    >
      <App />
    </MilanaProvider>
    ```

    The same approach works for any heavy or sensitive element — embedded SVGs, third-party widgets, and so on. See [Privacy Controls](/guides/privacy) for the full set of block, mask, and ignore options.
  </Accordion>

  <Accordion title="Milana is not defined (CDN / script tag)">
    This error occurs when your code references `window.Milana` before the SDK script has finished loading. Use the queue pattern instead so that commands are buffered and replayed automatically once the script loads:

    ```html theme={null}
    <script>
      window._milanaQueue = window._milanaQueue || [];
      function Milana() { window._milanaQueue.push([].slice.call(arguments)); }
    </script>
    <script async src="https://cdn.getmilana.ai/milana.js"></script>

    <script>
      Milana("init", "prd_YOUR_PRODUCT_ID", "key_YOUR_CLIENT_KEY", {
        environment: "production",
        version: "1.0.0",
      });
    </script>
    ```

    With this pattern, any commands pushed before the script loads are processed immediately when the SDK initializes.

    <Note>
      If you are using the `milana-js` npm package with React or a bundler, this error should not occur — the SDK is imported as a module and is always available when your code runs.
    </Note>
  </Accordion>

  <Accordion title="Sessions appear but replay is blank">
    A blank replay is usually caused by one of the following:

    **Canvas elements:** Canvas recording is disabled by default because it is CPU-intensive. If your app renders critical UI in a `<canvas>` element, enable it explicitly:

    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{ shouldRecordCanvas: true }}
    >
      <App />
    </MilanaProvider>
    ```

    **Iframes:** Same-origin iframes are recorded automatically. Cross-origin iframes require additional setup — see the [iframe Recording](/guides/iframe-recording) guide.
  </Accordion>
</AccordionGroup>

***

## FAQ

Have a question not answered here? Reach out at [help@getmilana.ai](mailto:help@getmilana.ai).

<AccordionGroup>
  <Accordion title="What data does Milana record?">
    Milana records browser-side user activity using the SDK embedded in your app.

    **What Milana records:**

    * **DOM snapshots and mutations** — the structure and content of the page as it changes
    * **User interactions** — clicks (including modifier keys), scrolls, and form input value changes (subject to [privacy controls](/guides/privacy))
    * **Page navigation** — URL path changes, query parameter changes (with a [denylist](/guides/privacy) for sensitive values), and navigation type (e.g. back/forward)
    * **Page visibility** — whether the tab is in the foreground or background
    * **Scroll depth** — how far down the page a user scrolled
    * **Download detection** — when a user triggers a file download
    * **Canvas content** — only if [canvas recording](/guides/canvas-recording) is enabled
    * **Session and user metadata** — only what you explicitly pass via `init()` and `update()`
    * **Custom events** — any events you explicitly send with `trackEvent()`

    **What Milana does not record:**

    * Network requests or API calls
    * HTTP headers, request bodies, or response bodies
    * Console logs or JavaScript errors
    * Cookies
    * Local storage or session storage
    * Server-side data or database contents
  </Accordion>

  <Accordion title="Does Milana affect my app's performance?">
    Milana's recording engine is built on [rrweb](https://www.rrweb.io/), the industry-standard open-source session recording library used by PostHog, Sentry, Statsig, and others. It has been tested both in simulated environments and at scale, having recorded sessions from over 50 million browsers.

    Milana is designed to have minimal impact on your app. Key protections include:

    * **Deferred start:** The SDK uses `requestIdleCallback` to wait until the browser is idle before beginning to record — delaying up to 10 seconds after initialization so that page load performance is not affected.
    * **Buffer limits:** If the event buffer grows beyond approximately 10 MB, the SDK flushes immediately. If it reaches approximately 40 MB, recording stops and the session is aborted to protect app memory and performance.
    * **Background flushing:** Events are batched and sent every 10 seconds. Payloads are compressed with gzip on supported browsers to minimize network usage.
    * **Automatic retry:** If the network is temporarily unavailable, the SDK retries up to 5 times with a backoff schedule (5 s, 15 s, 30 s, 60 s, 300 s) before giving up — it never blocks the main thread while retrying.
  </Accordion>

  <Accordion title="How long does it take for sessions to appear?">
    Milana waits until **30 minutes of inactivity** before finalizing a session. After the session ends, it passes through a multi-stage processing pipeline:

    1. **Ingest** — raw events are received and stored
    2. **Aggregation** — events are grouped into a complete session
    3. **Encoding** — the session is rendered and encoded as a video
    4. **AI transcription** — the AI watches the video and produces a searchable description
    5. **Indexing** — the session becomes available in the dashboard and in query results

    This pipeline typically completes within **10 minutes** of a session ending. Sessions will not appear in query results until all stages are complete.
  </Accordion>
</AccordionGroup>
