One script tag. No build step, no package to install. Works with any HTML, React, Next.js or FastAPI project.
YOUR_PROJECT and YOUR_PUBLIC_KEY with the values from the project settings page.</body><!-- Paste before </body> in your base template --> <script src="https://cdn.mailcowai.com/engage.js" data-project="YOUR_PROJECT" data-public-key="YOUR_PUBLIC_KEY" defer></script>
// app/layout.tsx (or pages/_app.tsx) import Script from 'next/script' export default function RootLayout({ children }) { return ( <html lang="en"> <body> {children} <Script src="https://cdn.mailcowai.com/engage.js" data-project={process.env.NEXT_PUBLIC_MCAI_PROJECT} data-public-key={process.env.NEXT_PUBLIC_MCAI_KEY} strategy="afterInteractive" /> </body> </html> ) }
// src/main.tsx (or App.tsx) import { useEffect } from 'react' function EngageScript() { useEffect(() => { if (document.querySelector('[data-engage]')) return const s = document.createElement('script') s.src = 'https://cdn.mailcowai.com/engage.js' s.dataset.project = import.meta.env.VITE_MCAI_PROJECT s.dataset.publicKey = import.meta.env.VITE_MCAI_KEY s.dataset.engage = '1' s.defer = true document.body.appendChild(s) }, []) return null } export default function App() { return ( <> <EngageScript /> {/* rest of your app */} </> ) }
<!DOCTYPE html> <html> <head>…</head> <body> {% block content %}{% endblock %} <script src="https://cdn.mailcowai.com/engage.js" data-project="{{ project_slug }}" data-public-key="{{ public_key }}" defer></script> </body> </html>
After the script loads, call these methods from anywhere in your application.
| Method | Description |
|---|---|
| identify(userId, traits) | Associate the session with a known user. Pass any traits: { email, plan, name }. Sensitive keys are redacted automatically. |
| track(event, properties) | Track a custom event with optional properties. Example: MailcowAI.track("billing.payment.failed", { plan: "pro" }) |
| setContext(obj) | Attach account-level context to all subsequent events. Example: { org_id, subscription_status } |
| openChat(opts) | Open the support widget programmatically. Pass { message } to pre-fill the composer. |
| dismissCampaign(slug) | Suppress a campaign by slug for this session. Useful for testing or user-controlled dismiss. |
| getSession() | Returns { anonymous_id, session_id, user_id, project }. No sensitive data exposed. |