Skip to main content

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.

SDK & Installation

Work through the following checks in order:
1

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

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

Account for sampling

Enable debug mode to see whether the current session was sampled. Run this in your browser console, then refresh the page:
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:
localStorage.removeItem("milana_debug_mode");
If you need to adjust sampling rates for your product, contact help@getmilana.ai.
4

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

Check for ad blockers

Some browser ad blockers may block requests to in.getmilana.ai. Try disabling ad blockers, or contact help@getmilana.ai for help configuring a reverse proxy.
6

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.
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 page to avoid typos. Do not trim, truncate, or modify it.
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 page. If the key is correct but the error persists, the key may have been rotated — contact help@getmilana.ai to generate a new one.
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):
<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:
<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 for the full set of block, mask, and ignore options.
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:
<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.
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.
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:
<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 guide.

FAQ

Have a question not answered here? Reach out at help@getmilana.ai.
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)
  • Page navigation — URL path changes, query parameter changes (with a denylist 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 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
Milana’s recording engine is built on rrweb, 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.
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.