Website SDK
One script tag connects your website to The AI CMO: visits, conversions, and revenue flow into your warehouse, journeys can react to what people do on your site, and website messages from Journeys render on your pages.
Install
In the app, open your account menu and choose Website SDK. Add your
site by domain and you get a snippet to paste before </head>:
<!-- The AI CMO -->
<script async src="https://theaicmo.com/sdk/v1/tracker.js"></script>
<script>
window.AICMO = window.AICMO || [];
AICMO.push(['init', { siteId: 'lpo_your_site_id' }]);
</script>
That's the whole install. The script loads asynchronously and cannot block or break your page – even if analytics is unreachable, your site is unaffected.
To confirm it works, visit your site once, then refresh the Website SDK page. Each site shows "Receiving data – last event" with a timestamp once the first event lands, and the page banner switches to "SDK installed and receiving data".
What is tracked automatically
With no further code, the SDK captures pageviews (including single-page app navigation), visitors and sessions, and campaign attribution from tracked links and UTM parameters. Everything else – your business moments, conversions, revenue, identity – you declare explicitly with the calls below, so your analytics contains what you decided matters, not noise.
Session recording, heatmaps, and automatic click capture are switched off by design: they multiply event volume without adding decisions, and they are the first thing a privacy review flags.
Everything the SDK sends lands in your warehouse with an sdk_ prefix
on the event type, attributed to the visitor and – once they identify –
to the person.
Included analytics volume
Visitor analytics is included with your plan: up to 1M events a month on Assistant, 5M on Manager, 20M on CMO. Conversions, identity, custom events, journeys, and revenue tracking are never counted against this – it meters only the behavioral layer (pageviews and sessions).
If a site outgrows its plan's volume, nothing breaks and nothing is lost silently: visitor analytics switches to sampling (1 in 10 visitors), you get an alert, and full detail returns when volume drops or the plan grows. First-party data – conversions, revenue, journey events – is never sampled.
The API
Call methods through the queue, which is safe to use before the script has loaded:
AICMO.push(['method', ...arguments]);
| Method | What it does |
|---|---|
init({ siteId, consent? }) | Starts the SDK. Pass consent: 'pending' to wait for a consent banner. |
track(eventName, properties) | Sends a custom business event – see below. |
identify(idOrEmail) | Tells the SDK who the visitor is – an email or your own customer ID. |
trackConversion(type, { value, currency, email }) | Records a conversion with revenue. |
trackPageView() | Manual pageview, for cases the automatic tracking can't see. |
optIn() / optOut() | Grant or withdraw consent at runtime. |
consentStatus() | Returns granted, denied, or pending. |
Custom events
Custom events are how your site's own business moments – a deposit, a booking, a quote request – reach the platform:
AICMO.push(['track', 'deposit', { value: 250, currency: 'USD' }]);
Or with zero JavaScript, declaratively on any element:
<button data-aicmo-event="deposit_click" data-aicmo-value="50">Deposit</button>
Two rules to know:
- Event keys must be registered first in Data → Events, and use lowercase letters, numbers, and underscores. Events with unregistered keys are not stored – but the Events tab shows keys it has seen so you can register them with one click.
- In the warehouse the event lands as
sdk_<key>(a registereddepositbecomessdk_deposit), and a journey with the matching custom-event trigger enrolls the person the next time the engine polls – within about a minute.
You can also define no-code capture rules in Data → Events: a CSS selector or URL match that fires an event without touching your site's code, reading the value from the page or a cookie.
Identifying people
Anonymous visitors get a random visitor ID. The moment you know who they are, tell the SDK:
AICMO.push(['identify', 'jane@acme.com']); // email
AICMO.push(['identify', 'player-48213']); // or your customer ID
Identification is what connects website behavior to a real customer: their events join their profile, journeys can enroll them, and person-targeted website messages can reach them. If your site already sets a login cookie, configure it as the identity cookie in Data → Events and the SDK identifies people automatically – no code change.
Revenue
Send revenue either through a conversion or on a custom event:
AICMO.push(['trackConversion', 'signup', { value: 49, email: 'jane@acme.com' }]);
AICMO.push(['track', 'deposit', { value: 250, currency: 'USD' }]);
The value becomes the event's amount in your warehouse, and feeds
journey goals, revenue reporting, and What's Working.
Website messages
When a journey publishes a website message, the SDK renders it on your site – as a banner, card, or modal – styled to the message, isolated from your page's CSS, and shown at most once per day per message. Person-targeted messages appear only to the identified person they were written for. Impressions, clicks, and dismissals are tracked automatically and feed the journey's performance numbers.
The inbox
Messages can persist in an on-site inbox instead of – or alongside – the one-shot popup. When a visitor has inbox messages, the SDK shows a small launcher in the corner with an unread badge; opening it lists their messages, newest first, and marks them read. Visitors with no messages never see the launcher at all.
Three things put messages there: the journey Website step (choose "Popup + inbox" or "Inbox only" on the step), promos – when a promo with a customer message is credited to someone, that message lands in their inbox automatically, with its terms attached – and the Inbox page (sidebar), where you manage the whole channel: see each message's reads, who it targets, where it came from, end it early, or compose a new one – with an image and a button if you like – for every visitor or one person. The Inbox page also documents the two public endpoints for rendering the same inbox natively inside your own logged-in UI instead of the SDK widget.
Personalization
The SDK can change what your site says per visitor. Mark an element with
data-aicmo-slot="hero-title" (or give a CSS selector on the rule), then
create rules under Audience → Audiences → Personalization: what to show,
and who sees it – everyone, or one of your saved audiences.
Higher-priority rules win; identified visitors on your exclusion lists
are never personalized. Variants are plain text by default; HTML variants
exist behind a per-site switch you have to turn on deliberately.
Rules can target devices – all, mobile (phones and tablets), or desktop – so the shorter headline shows only where screens are small.
Rules apply on page load and on navigation in single-page apps. Applied
elements carry a data-aicmo-personalized attribute so your team can see
what changed and why.
Each rule reports how often it applied and, for identified visitors, the revenue those people generated after first seeing it – the rule's row under Personalization reads both, so a rule is never a guess.
A/B testing a rule
When creating a rule you can switch on A/B test this change: write a second version, choose the split (say 50/50), and set a holdout – a slice of visitors who keep seeing your original page but still count as exposed. Every visitor lands in the same arm on every visit, and the rule's row then reads revenue per arm – A vs B vs holdout – with the leader highlighted. The holdout answers the question that matters: does the change beat doing nothing?
Customers who are inside a journey with a control group are left out of rule A/B tests automatically – they see your original content and are not counted. One person is never part of two experiments at once, so journey uplift numbers and rule test numbers both stay honest.
Web push notifications
Turn browsers into a push channel – no third-party push provider needed. Browser subscriptions are off by default: nothing is offered or collected from visitors until you switch them on for the site (Website SDK page → Web push notifications). Once on, two steps:
-
Host a one-line service worker at your site root, saved as
/aicmo-sw.js(browsers require this file to live on your own domain):importScripts('https://theaicmo.com/sdk/v1/push-sw.js'); -
Call
AICMO.registerPush()from your own button – for example an "enable notifications" toggle in your account area. Browsers punish permission prompts the visitor didn't ask for, so the SDK never prompts on its own.
That's it. Subscribed browsers become reachable by the Push step in
Journeys. Subscriptions are matched to the person once you identify
them – someone who subscribes anonymously and logs in later becomes
addressable automatically. AICMO.unregisterPush() removes this
browser's subscription.
This is mobile push without an app: on Android phones, notifications arrive like any app's – even with the browser closed. On iPhone they arrive once the visitor has added your site to their home screen (Apple requires your site to ship a web app manifest for that). Desktop Chrome, Edge, and Firefox work everywhere. Blacklists and self-exclusion are enforced before every send.
Mobile apps (React Native)
Your React Native app gets the same three things through
@aicmo/react-native – no dependencies, and no third-party push
provider:
- Events and identity –
identify,track, andtrackConversionland in your warehouse exactly like the website SDK's. - Push, delivered directly – upload your Firebase service account
on the Website SDK page (verified live, stored encrypted) and The AI
CMO sends notifications straight through your own Firebase project:
Android natively, iOS via Firebase's APNs integration. Your app
passes its FCM token with
registerPushToken, and the Push step in Journeys reaches the device – matched to the person afteridentify.
The package README walks through setup for bare React Native and Expo. Blacklists and self-exclusion are enforced before every send, on this route like every other.
Survey pages
Your hosted survey pages can carry your site's SDK too: in a survey's
Fill page & branding → Tracking section, pick the site and survey
visits land in your analytics, with a survey_completed event fired on
submit. GA4 and Meta Pixel IDs are supported there as well – IDs only,
never scripts. Owner previews are never tracked.
Consent and privacy
- Consent gating: start with
consent: 'pending'and calloptIn()when the visitor accepts. Until then, nothing runs. AnoptOut()is remembered and the SDK stays silent on future visits. - Do Not Track is respected by default.
- The SDK sets no cookies. Visitor state lives in localStorage on your own domain. It only reads cookies you explicitly configure for identity or value capture.
- Session recordings mask every input field by default.