Paste the prompt below into Claude Code, Codex, Cursor, or any other modern coding agent. It will analyze your codebase, present a setup plan for your approval, and then handle the full Milana integration — SDK installation, user identification, privacy controls, and analytics event mirroring.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.
Set up Milana — installs the SDK, configures recording, wires up user identification, applies privacy controls, and integrates with your existing analytics.
View full prompt
View full prompt
Set up Milana in this codebase. Milana is an AI-powered session recording and product analytics SDK — it records user sessions via a lightweight browser SDK and uses AI to analyze the recordings so product teams can understand user behavior.The goal is to produce an easy-to-review pull request that is under 200 lines of code. Keep changes minimal and focused.
Reference
Fetch https://docs.getmilana.ai/llms.txt and use it as your SDK reference throughout this task. It contains the full API surface, initialization options, and framework-specific integration patterns.Step 1: Explore the codebase
Find the frontend application code. In a monorepo, identify the package that serves the user-facing UI — look for a React DOM render call, a framework entry point (e.g. Next.jsapp/layout.tsx, Remix root.tsx, Vite main.tsx), or an HTML template that loads the app.Determine:- Framework and rendering model: React (client-side), Next.js (SSR/RSC), Remix (SSR), vanilla JavaScript, or static HTML. This determines the integration method — React provider (
MilanaProvider), programmatic init (init()), or CDN script tag — and whether you need a"use client"boundary. - User object: Find where my primary user object is loaded. This might be from an auth provider (Clerk, Auth0, NextAuth/Auth.js, Supabase Auth, Firebase Auth, better-auth, or a custom system), or from a user context, store, or API call elsewhere in the app. You need access to the user’s ID, email, and name.
- Existing analytics: PostHog, Segment, Amplitude, Mixpanel, or others. Note whether there is a shared analytics wrapper function, and find calls that track activation events, conversion/purchase events, cancellation/churn events, and AI agent usage events.
- Environment variable pattern: Are other client-side API keys stored in environment variables (e.g.
NEXT_PUBLIC_*,VITE_*,REACT_APP_*)? Note the naming convention used. - Content Security Policy: Search for any
Content-Security-Policyheader set in middleware, server config, framework config (e.g.next.config.js), or<meta http-equiv>. If one exists, note thatconnect-src(for all installs) andscript-src(for script-tag installs) will need to allow Milana origins — surface this in the plan in Step 2. - Environment and version: How does the app detect its current environment (e.g.
process.env.NODE_ENV,import.meta.env.MODE)? Is there an existing version constant or build-time injection frompackage.json? - Session context: Does the app read UTM parameters from the URL, track referrer, store A/B test or experiment variants, or maintain feature flag state? Are there specific fields that track where users are coming from (e.g. entry point, traffic source, invite origin)? Note where this context is already available on the client.
- Sensitive UI elements: Scan for forms that collect credit card numbers, payment information, government IDs, social security numbers, or other PII beyond standard email, password, and phone fields (those input types are masked automatically by the SDK). Note: third-party payment UIs that render in iframes or popups (Stripe Elements, Stripe Link, Braintree hosted fields, etc.) are already invisible to the recorder — only flag payment forms built with native HTML inputs.
- Feature flag system: Is there a feature flag provider (LaunchDarkly, PostHog, Statsig, etc.)? Note this for the rollout recommendation.
Step 2: Present your plan
Before making any changes, present a plan that covers the following. For each item, name the specific file path and show surrounding code context so I can verify placement.SDK integration- Which integration method you’ll use (React provider, JS init, or script tag) and why.
- The exact file where you’ll add the initialization code, and where in the component tree or module it will go.
- For SSR frameworks: any
"use client"directives or layout file considerations.
- Which auth provider or user object loader you found and where you’ll call
identify(). - The
identify()call must go inside auseEffect(React) or equivalent lifecycle hook that fires when the authenticated user changes — not on every render. For vanilla JS, call it after auth resolves. identify()takesuserId,email, optionalname, and optionalmetadata. Populatemetadatawith fields already available on the client (createdAt,plan,orgId,role, or equivalents). Do not fetch additional data from the server.- For later partial refreshes of user fields during the same session (e.g. plan upgrade, role switch), use
updateUser()— it accepts the same fields withemailoptional.
- How you’ll set
environment(dynamically from the app’s existing env detection). - How you’ll set
version(from an existing version constant or build-time injection; if none exists, use"0.0.0"). - Any session-level context already available on the client (UTM parameters, referrer, experiment variants, feature flag state, entry point or traffic source fields) that you’ll include via
sessionInfo.metadataat init, or a subsequentupdateSession({ metadata: {...} })call as context becomes available.
- List each sensitive element you found, its file path, and whether you recommend
milana-block(contents never recorded) ormilana-mask(text replaced with asterisks). - Ask me which ones I want you to apply. Do not add privacy classes without my explicit approval.
- Whether you’ll store the product ID and client key in environment variables (matching the existing pattern) or hardcode them. The client key is safe to include in client-side code.
- If you found an existing CSP, list the directive changes needed: add
https://in.getmilana.aitoconnect-src. For script-tag installs, also addhttps://cdn.getmilana.aitoscript-src, plus'unsafe-inline'(or a nonce) so the inline queue shim can run.
- If a shared analytics wrapper function exists, you’ll add
trackEvent()to it. - Otherwise, list up to 5 specific events you found — prioritizing activation, conversion/purchase, cancellation/churn, and AI agent usage events — that you’ll mirror with
trackEvent().
- If you found a feature flag system, mention that Milana supports deferred initialization gated behind a feature flag. Link to the Feature-flagged Rollout guide from the SDK reference for details.
Step 3: Implement
Once I approve the plan, implement it:-
Install the SDK: Add
milana-jsusing the project’s package manager (npm,yarn, orpnpm). For non-bundled apps, add the CDN script tag instead. -
Initialize recording: Add the initialization code in the location specified in the plan.
- React / Next.js / Remix: Wrap the app with
MilanaProviderfrommilana-js/react. Place it below the auth provider so user data is available. For SSR frameworks, add a"use client"directive to the component that rendersMilanaProvider. - Vanilla JS: Call
init()frommilana-jsin the application entry point. - Script tag: Add the queue snippet and async script tag to the HTML template.
- React / Next.js / Remix: Wrap the app with
-
Set session info: Set
environmentdynamically from the app’s existing environment detection. Setversionfrom an existing version constant or"0.0.0". Include any session-level context already available on the client (UTM params, referrer, experiment variants, entry point) insessionInfo.metadata. -
Identify users: Add an
identify()call inside auseEffect(React) or lifecycle hook that fires when the authenticated user changes. IncludeuserId,email, optionalname, and populatemetadatawith fields already available on the client likecreatedAt,plan,orgId, androle. If you need to refresh user fields later in the session, reach forupdateUser()instead of callingidentify()again. -
Apply privacy controls: For each element I approved, add the
milana-blockormilana-maskCSS class directly to the element in the HTML or JSX. -
Store credentials: Ask me for my Milana product ID (starts with
prd_) and client key (starts withkey_). These are found on the Settings page. Store them using the existing env var pattern if one exists, otherwise hardcode them directly. -
Mirror analytics events: If a shared analytics wrapper exists, add a
trackEvent()call inside it. Otherwise, addtrackEvent()calls for each approved event — importtrackEventfrommilana-jsor use theuseMilana()hook in React components.
Step 4: Next steps
After implementation, tell me to:- Run the dev server and open the application in a browser
- Open the browser developer console (you may need to change the log level from Default levels to Verbose) and look for “Milana: Ready” — this confirms the SDK initialized successfully
- Navigate through a few pages and interact with the app to generate a test session. Check the Integration page to see the recorded session
- Milana waits for 30 minutes of inactivity before finalizing a session, and processing takes up to 10 minutes after that