Documentation overview

Connecting your data

Everything The AI CMO knows about your customers flows through the Data page – sources on the left of the journey, your event vocabulary in the middle, and the warehouse it all lands in. This manual covers each door in, and how to confirm your data arrived.

The Data page

Data in the sidebar opens these tabs – the first two are the two directions your data can move:

  • Push – everything you send us: CSV imports, the Website SDK at a glance, the address your own systems post to, the keys they use, and recurring file feeds.
  • Pull – everything we fetch for you on a schedule: Shopify, ad platforms, and tables in your own database, each with a freshness status.
  • Events – the vocabulary of custom events your site and systems can send (see below).
  • Catalog – the products, bonuses and other items your events refer to.
  • Activity – the record of everything that has moved, in either direction (see below).
  • Warehouse – totals, every event type as it streams in, and the meter showing how much of your plan's included volume you've used.

If you want to explore the platform before wiring anything real, Load demo data on the Push tab fills the account with a sample business you can safely play with and remove later.

The fastest start: one CSV

The Add your data (CSV) card accepts one file and works out what it is:

  • Purchase history – a customer, a date, an amount per row. The moment it imports, the Overview tab has your revenue numbers.
  • Ad performance – a date, a platform, a spend per row. Platform names are standardized automatically (GADS, PPC, and Google Ads all become Google Ads), and ROAS and CAC go live on Overview.
  • A contact list – any file with an email column becomes an audience segment in Customer Intelligence → Audiences.
  • A combined file – one file with a record_type column can carry purchases and ad rows together. There's a sample CSV to download on the card.

You map the columns in a quick confirmation step, extra columns are always kept as customer attributes, and files up to 100,000 rows are accepted. Re-importing the same file is safe – the warehouse never double-counts an order it has already seen. Every import appears in the Uploads list, where it can also be deleted.

Connecting your apps

Integrations in the sidebar connects The AI CMO to the tools you already use. The page is organized by job:

  • Publish – Journeys and chat post here for you: LinkedIn, Facebook, X, TikTok, WordPress.
  • Measure – spend and results land in your analytics automatically: Google Analytics, Google Ads, Amazon Ads.
  • Reach & alert – talk to your customers and your team: email sending, HubSpot, Slack.

Connecting is one click: Connect opens a secure sign-in window for that platform, you approve, and you're done. Once an ad platform is connected, its spend syncs into your analytics on its own – no import needed.

Platform feeds

There are two ways data arrives, and they live in different places because only one of them holds passwords to your other accounts.

  • You send it to us – your own systems, or a file. No connector, no setup: see Sending data from your own systems below.
  • We fetch it for you – Shopify, Google Ads, Meta, or a table in your own database. These need access to those accounts, so they are set up by your workspace admins in the admin portal. The Pull tab shows each one and how fresh it is; everyone can see the status.

We pull straight from your database

If the data you want in your warehouse already sits in a PostgreSQL or MySQL database – an orders table, a player roster, a games catalogue – you can skip exports entirely. Give us read-only access to that one table and we collect new rows on a schedule you choose.

Your admins set it up in the admin portal under Data Sources → Add Data Source → We pull from your database:

  1. Create a read-only database user. We only ever read – a user that can do nothing else is the right shape for this.
  2. Enter the connection – host, port, database, username, password. The password is stored encrypted, is never shown again, and never appears in any response. Your database must be reachable from the internet; if it sits behind a firewall, your team allowlists our address.
  3. Say what to pull – the table, and a column that only ever grows (an id, or an updated_at timestamp). Each collection continues from where the last one stopped instead of re-reading everything. Leave the column blank and we re-read the whole table each run.
  4. Say what the rows are – events (orders, transactions), your customer roster, or a catalogue. Same choice as a CSV import, and the same rules apply afterwards.
  5. Press Test connection. It proves the credentials work and the table is readable before anything is saved, and shows you the table's columns.

From then on it runs on the schedule from the Settings tab – hourly, daily or weekly – and Sync now collects on the spot. A row we have seen before replaces itself rather than double-counting, so neither re-runs nor overlapping collections can inflate your numbers. Every run is recorded on Data → Activity, and the source's freshness shows on the Pull tab like every other feed.

Snowflake, BigQuery and other warehouses are connected by our team as part of your plan – add the source and the config page tells you how.

Sending data from your own systems

If your data lives in systems of your own – a player database, an order system, a nightly export – Data → Push is where you wire them in. Nothing about them needs to be modern: anything that can make an HTTPS request, or produce a file, can feed The AI CMO.

Where it lands. One endpoint, whichever warehouse you are on. If you move to a dedicated cluster later, the same address follows you – there is nothing to re-point and no second URL to learn. The Push tab tells you which warehouse it is landing in right now.

The address. One endpoint takes everything. Send a single event or up to 1,000 in one request. Sending the same event_id twice replaces the first rather than adding a second, so retries, restarts and re-sending yesterday's file never inflate your revenue.

The keys. Issue one key per system, named after that system. Two things are worth knowing:

  • A key is shown once, when you create it. We store only a fingerprint, so nobody – including us – can read it back to you. If it goes missing, revoke it and issue another.
  • A key can only send data in. It cannot read your customers, change anything, or delete a single row. Even if one leaked, that is the whole of what it could do.

You can pin a key to the fixed IP addresses your systems send from, and give it an expiry date. Revoking one takes effect immediately and affects nothing else.

Daily files. The same key works for file uploads, so a scheduled job can post your nightly export directly instead of someone opening a browser to drag it in.

What you can load

The warehouse takes more than orders. Anything you can export as a file has a home:

  • Events – anything that happened. Purchases, deposits, withdrawals, bets, wins, bonus grants, sign-ups. Include an event_type column and we keep your words: a withdrawal stays a withdrawal, and is never counted as revenue.
  • Customers or players – who they are. A roster with status, tier, KYC state, self-exclusion flag, lifetime value, and any other column you send. Re-sending the whole file updates people rather than duplicating them, so a nightly full export is exactly the right shape.
  • Catalogues – what they play or buy. Games, bonuses, products. Each catalogue is named, and its items carry whatever attributes you have.
  • Ad performance. A date, a platform, a spend per row.

Extra columns are never dropped. Whatever you send that we don't recognise is kept as an attribute, appears in the Data Manager, and can be used for segmentation.

Telling us what counts as revenue

We do not assume it. A deposit, a premium, a commission and a subscription are all somebody's revenue, and a payout carries an amount without being any of them – so guessing would mean quietly counting money you paid out as money you took in.

In Data → Events, each event type you send has a Money setting:

  • Counts as revenue – amounts on this event roll up into your revenue figures and ROAS.
  • Paid out – money going the other way. Never counted as revenue.
  • Not money – the event has an amount that is not a payment at all.

Anything left undeclared contributes nothing to revenue. That is deliberate: a missing number you can see beats a wrong number you cannot.

Sending the same file every day

Yes, and it does the right thing in each case – but the safest shape is worth knowing.

Best: include an id column. A transaction_id, bet_id or order_id makes each row permanently identifiable. Send a new day's transactions and they add; re-send a corrected version of yesterday's and each row replaces itself. Nothing double-counts, and correcting a single wrong amount is just re-sending the file with it fixed.

Without an id column, we identify a row by its contents. That still behaves correctly: a genuinely new day's rows are new, an accidental second send of the same file changes nothing, and re-sending a rolling window (say the last seven days, every night) updates those days rather than duplicating them – even if the rows come back in a different order. The one thing it cannot tell apart is two byte-identical rows in the same file; those are kept as two events, which is usually what you want for a repeated stake or a repeated purchase.

Customer and catalogue files are a snapshot, and that is fine. A full nightly roster updates the people in it and holds their current state. Segment movement does not depend on it: lifecycle stages are computed from your event history, so how customers move between segments is fully reconstructible from the events you send – no snapshots required, and re-sending a roster never disturbs it. What a roster does not give you is a history of your OWN attributes: if you want "player moved from silver to gold" to be visible as an event, send it as one.

Ad performance is keyed by day, platform and campaign. Re-sending a day replaces that day.

If the wrong data arrives

Nothing is frozen. Three ways to correct it, and each correction is recorded alongside the original load:

  • Re-send the file. A repeat delivery replaces that load rather than adding to it, so fixing a bad export is a matter of sending the good one. For customer and catalogue files this updates the records in place – a full nightly export is exactly the right shape.
  • Delete a single load. Every upload is listed in Sources with its row count and time; removing one takes its rows with it.
  • Clear a profile. Removes everything loaded for that business profile.

The activity log itself can never be edited or removed, including by an owner – it is the record of what happened, not the data.

Files that arrive on a schedule

A one-off CSV drops straight on the Push tab. An export that repeats – your nightly player file, a weekly finance extract – should be a feed, further down the same tab.

Give it a name and say how often it should arrive. From then on:

  • It remembers your columns. You map them once, on the first file. Every delivery after that is loaded the same way, so nobody re-maps the same export every night.
  • It tells you when a file doesn't turn up. This is the real reason to use a feed. A nightly export that quietly dies is wrong numbers for a week before anyone notices; a feed raises it the morning it happens.
  • It works by hand or by machine. Drop a file on the feed here, or have a scheduled job send it with an ingestion key – same feed either way, and the history shows which was which.

If you'd rather not commit to a schedule, leave it on Detect the rhythm. We watch the first few deliveries, work out the pattern, and offer it back to you to confirm – we never invent a schedule you didn't agree to. Pausing a feed stops the overdue alerts without deleting anything.

Activity. Underneath is the record: every file loaded, every batch received, every mapping changed, every deletion – who or what did it, from which address, how many rows moved, and whether it worked. Failures are recorded too, so "the nightly load stopped three days ago" is a question you can answer. Nothing can edit or remove an entry, including an account owner.

Giving your data team their own access

If the people who wire up your systems are not the people who run your marketing, invite them as a Data engineer.

That seat sees the Data page – sources, connection, keys, activity, the event catalog and the warehouse – and nothing else. No campaigns, no journeys, no audiences, no billing. They can load data, map it, correct a bad file, and issue their own keys, without ever seeing the marketing side of the account.

To be precise about one thing, because it matters for regulated businesses: they can see the data they load, and that includes customer identifiers, because inspecting it is the job. What they cannot do is act on it – no campaign, no journey, no export to an ad platform, no message to anyone.

Two things they deliberately cannot do: erase all data for a business profile, and see anything outside the Data page. Purging a profile stays with owners and admins.

Invite them from admin.theaicmo.com → Team, choosing Data engineer as the role. It takes a seat like any other member.

Your website

The Website SDK is one script tag that brings visits, conversions, and revenue from your site into the warehouse – and it's how website messages from Journeys reach your pages. It has its own manual: Website SDK. The Push tab shows its status at a glance, and the SDK page itself flips to "Receiving data" the first time an event arrives.

Your event vocabulary

The Events tab is where you define the business moments that matter – a deposit, a booking, a quote request. Register an event name and you get three ready-to-paste ways to capture it: a JavaScript call, an HTML attribute, or a server webhook. You can also set up no-code capture – point the event at a button, form, or URL on your site and the SDK fires it without any code change, even reading the value straight off the page.

Two details worth knowing:

  • Events your site sends that aren't registered yet show up as seen from your site, not registered – one click registers them.
  • An event can be marked as a suppression event: anyone who fires it is blacklisted from all contact. Built for self-exclusion and do-not-contact flows.

Registered events appear in the Warehouse tab as they stream in, can trigger journeys ("someone fires this event" enrolls them within about a minute), and can define audience segments.

Included events and what happens at the ceiling

Every plan includes a set volume of warehouse events – one event is one order, one deposit, one conversion, one webhook push. On current plans that is 100,000 events on Intern, 1,000,000 on Assistant, and 5,000,000 on Manager – years of order history for most businesses. The meter on Data → Warehouse shows where you stand ("Included events – X of Y on your plan") and turns amber as you approach the ceiling.

The rules at the limit are deliberately one-sided:

  • CSV imports pause – an import that would pass your included volume is declined with the exact numbers, and your file is untouched. Upgrade, or trim the file, and import again.
  • Live streams never stop. Website events, webhooks, and store syncs keep flowing – rejecting live data would destroy it, so we don't.

You get a bell notification at 80% and at 100%. The CMO plan runs on a dedicated warehouse with no event ceiling.

How to know it worked

  • A CSV import confirms immediately and tells you where to look – purchases light up the Overview numbers on the spot.
  • A contact import names the segment it created in Customer Intelligence → Audiences.
  • The Website SDK page shows "Receiving data – last event" with a timestamp after your site's first event.
  • The Warehouse tab lists every event type the moment it streams in – including your registered custom events.