Littledata MonitorAI guide

Monthly value, trial and prospect emails (Intercom)

Littledata can update company fields on each store’s Intercom company, tag the company with the audit checks that are failing, and fire an event so your team can send the trial “days to value” email. All customer-facing copy is built once in MonitorAI (the same strings as Intercom company attributes). The Littledata admin “Preview email” and “Preview Slack” show that server copy only—they do not regenerate wording in the browser. Trial (days-to-value) preview in the admin may still differ slightly until that copy is also served from the API.

The monthly value email is no longer an Intercom message. MonitorAI renders it itself and sends it via POST /messages, because it is a stack of per-destination hero cards — the same layout the store reads in the app — and a template built from flat attributes cannot lay that out. The monthly-roi-ready event is no longer fired and its outbound message is switched off; leave it that way, or stores get two emails. See The monthly value email below. The roi_* company attributes are still written on every value refresh, for segmentation and for the days-to-value template.

Who sets this up: Marketing owns message design in Intercom; operations needs the company attributes and event names exactly as below. The Monitor: company tags need no setup in Intercom — they are created on first use and are there for audience filtering, not for copy.


Prerequisites


Company fields (custom attributes)

Monthly value / ROI (updated when value is recalculated)

These are still written on every value refresh, but no email reads them any more — the monthly value email renders from the hero cards instead. Keep them for audience filtering and segmentation, and because slack_invite_url and monthly_cost_with_overage are read by other templates.

API name What merchants see (examples)
roi_headline Short hero line, e.g. “Littledata generated a 12× return from Google Ads”, or a fallback headline if ROI cannot be quantified that way. When value spans several destinations (Klaviyo + Google Ads + Meta), the headline and its ROI multiple cover the single strongest destination only
roi_explanation Primary value paragraph about the single strongest destination’s metric (e.g. Klaviyo incremental revenue or Google Ads efficiency improvements — never a sum across destinations); includes the Klaviyo flows-live reminder only when the story is a prediction contingent on triggers going live (measured revenue was already earned, so it never carries the reminder) (Google Ads coverage-gap wording is not here—it goes in roi_additional_paragraph)
roi_additional_paragraph When the Google Ads story leads: monthly coverage-gap line — “Littledata reveals $X/month of Google Ads revenue your next best conversion goal doesn’t track. The efficiency improvement is the conservative slice of that gap we credit to Smart Bidding” (second paragraph—use its own block in the template)
roi_additional_bullet_1, roi_additional_bullet_2, roi_additional_bullet_3 Up to three extra value lines (plain text—add your own bullets / list markup in Intercom per field); omit empty keys. Secondary destinations’ metrics (the ones the headline doesn’t cover) appear here as their own per-destination lines, never summed with the headline metric. Also carries the missing abandonment-flow to-do (“Activate Added to Cart flow to add ~$878/month…”, the same line as additional_flow_revenue quantifies) — the email is where a brand acts on it
roi_additional_value Legacy packed field: compact newline-separated copy for older templates; prefer roi_additional_paragraph + roi_additional_bullet_* so each block stays under Intercom limits
roi_multiple Number like 12 or 8.2 when the headline is backed by a positive USD ROI story. Matches the headline: for multi-destination stores this is the leading destination’s own ROI, not the cross-destination total
monthly_cost_with_overage Monthly Littledata cost in USD, including order overage when applicable
slack_invite_url Text: full URL for Add to Slack (MonitorAI alerts). Empty when Slack is already connected, FRONTEND_URL is not configured, or the store cannot mint an invite. Refreshed with ROI sync and with the days-to-value fields
additional_flow_revenue Number: estimated extra USD/month if the store activated Klaviyo abandonment flows for stages that currently have neither a live native nor a live Littledata flow. Uses per-trigger peer medians from the predicted-incremental cohort. Omitted when there are no missing stages or peer data is insufficient.

Trial days-to-value (set right before the one-time days-to-value-reached event)

API name What merchants see
dtv_headline Classic DTV: e.g. “Littledata paid for itself in 8 days” (or softer wording if setup is still incomplete). Or day-14 trial (no headline ROI yet): “2 weeks into your trial, what Littledata improved”.
dtv_explanation Value story only — incremental revenue, payback timing, full-month predictions, etc.; or Meta / GA / tracking-accuracy story for the day-14 case (each field is capped at 255 characters). Does not include trial-days-remaining (those go in dtv_closing).
dtv_closing Trial-days-remaining line (when applicable), or “Your trial period has ended…”. Does not include the Add to Slack CTA — use slack_invite_url in the template for that.
dtv_next_step Text, optional: the one action that unlocks the figure the email just quoted — “Set your Littledata flow triggers live in Klaviyo (Viewed Product - Littledata, …) to start earning this.”, or “Activate Added to Cart flow to add ~$831/month.” once the triggers are live. Omitted entirely when the setup is healthy and no abandonment stage is missing, so hide the block when blank. Set on the payback and day-14 emails alike
customer_view_url Text: the store’s own results page, {FRONTEND_URL}/customers/{shopName}?share={token} — the “View the results” CTA. The page is admin-gated, so the URL carries a ?share= token (minted/reused at send time, 3-day TTL, same as the audit-alert Slack links — re-minted on the monthly-ROI send too, so the link is alive whichever email carries it). Same destination as the trial-at-risk Slack link, so both CTAs land in one place. Empty when FRONTEND_URL is unconfigured or no token could be minted; hide the CTA block when blank

monthly_cost_with_overage and slack_invite_url are also refreshed when the trial event sends so cost and Slack CTA stay consistent in the template.

customer_view_url is the one trial field the monthly email also uses, so it is refreshed immediately before monthly-roi-ready as well. It has to be: the ROI value sync never emits it, so a store that never hit a days-to-value or day-14 milestone would carry a blank URL forever — and the ?share= token minted at that milestone would be three weeks expired by the next monthly send anyway.


Trigger events (per contact)

Create transactional / behavioural emails in Intercom that start when a user triggers an event:

Event name When it typically fires
monthly-roi-ready On the store’s billing calendar day (UTC), once per day maximum—aligned with the same rule used for monthly ROI Slack
days-to-value-reached Once per company when the trial hits the days-to-value milestone or (if headline ROI is not yet available) the day-14 trial milestone — same dtv_* fields in both cases. Only while the trial is still running (now < trialEndDate): the email’s audience guards with phase is trialing (converted customers get the monthly ROI email instead), and firing past that guard would burn the once-per-company event on a send Intercom drops

Note: ROI-related company fields refresh whenever value is recomputed (for example after audits). The trial fields are written immediately before the days-to-value-reached event so the template sees final copy.

The payback milestone needs a 3× return. A store whose best return is below — the same bar a destination clears to headline its own hero card — gets no payback email; it falls through to the day-14 copy, which tells a tracking-accuracy story instead, and only if something has actually been measured (Meta conversion lift or GA4 assisted revenue). With neither, the store gets nothing at all — the only copy left would be an email saying metrics will appear later, which is not worth a send. Without the floor the email argued against us: a 36-day payback quoted inside a 30-day trial, or $20 of predicted revenue against a $25 plan. Sub-floor stores also no longer carry dtv_headline / dtv_explanation on the company at all, so an audience built on “dtv_headline is set” now excludes them rather than picking up a losing number.


Company tags (audit checks)

Alongside the fields above, MonitorAI keeps a company tag on the Intercom company for every audit check that is currently failing. Marketing and CS use these to filter and target in Intercom — audience rules, lists, and follow-up campaigns — without needing the audit data itself.

Tag name: Monitor: + the destination + the check’s label as it appears in the Littledata admin:

Monitor: Google Ads Goal configuration
Monitor: Microsoft Ads Goal configuration
Monitor: Klaviyo Flow exclusion rules
Monitor: GA4 Unassigned traffic

The destination marker is one of GA4, Google Ads, Microsoft Ads, Meta, Klaviyo, Shopify. It is there because Google Ads and Microsoft Ads run several same-named checks — goal configuration, tracking setup, client-side conversion quality, attribution window — and the check label alone would make one tag stand for both platforms. It also means you can filter on the prefix: typing Monitor: Google Ads in Intercom’s tag search brings back every Google Ads check.

When a tag is applied and removed:

Tags gained their destination marker in August 2026. Before that a tag was Monitor: + the label alone (Monitor: Goal configuration). Any audience still built on a label-only name needs repointing at the marked name — mechanically, insert the destination in front of the label. The reconcile process adds the new tags and clears the old ones from companies, but it cannot see or fix audience definitions.

The tags, by destination

Destination Tags (Monitor: <destination> + name)
GA4 Unassigned traffic, Orders attribution (internal), Under free hit limit, Order tracking change, Session tracking change, Order throughput, Google Ads linked, BigQuery linked, Littledata custom dimensions, Alternative property
Google Ads Tracking Setup, Goal configuration, Enhanced Conversions enabled, Alternative server-side conversions, Client-side conversion quality, Market-level ad accounts, Conversion attribution window
Meta Purchase EMQ, Checkout EMQ, Add to Cart EMQ, Events Manager Warnings, Events Manager active errors, Additional conversions reported, Alternative CAPI detected
Klaviyo Littledata abandonment flows, Native abandonment flows, Active alternative flows, Active SMS Flows, Flow exclusion rules, Pseudo market identifiers, Alternative audience uplift, Attribution window, Storefront capture rate, Mailing address enrichment, Marketing consent sync, Spam profiles created
Microsoft Ads Microsoft Ads traffic, Other Ad Accounts, Tracking setup, Goal configuration, Conversion attribution window, Client-side conversion quality
Shopify Shopify Markets active, Traffic from Amazon, Bot checkouts

The GA4 row holds the checks that run against the GA4 property, including the ones that report on a link to another platform (Google Ads linked, BigQuery linked) — the Google Ads row is the checks run against the ad account itself.

Monitor: Conversions value matching (deprecated) may still exist on older companies; the check no longer runs, so treat any leftover tag as stale.

Other company tags (not audit checks): the health-score tags — RAG - Red / RAG - Amber / RAG - Green, At Risk - ..., Open Support Ticket, Multiple Shopify Markets — are set by the nightly customer-health run and documented in Customer health score.


Mapping templates to the admin “Preview email”

The admin preview pulls the same text the API stores on the Intercom company (see attributes above). There is no separate client-side version of the story.

Block in Preview / Slack Intercom variable
Hero line roi_headline
Primary value paragraph (efficiency / incremental value; flows reminder when flows not live) roi_explanation
Google Ads attributed-revenue runway (optional) roi_additional_paragraph (hide block when empty)
Extra tier/detail lines roi_additional_bullet_1_3 (hide each paragraph when blank)
Packed legacy rollup (optional; older templates only) roi_additional_value (hide block if blank)
“Get these MonitorAI alerts in Slack…” / Add to Slack Link slack_invite_url (hide block if blank)

Suggested templates

Email 1 — Monthly ROI

Email 2 — Days to value


Prospect follow-up series (Klaviyo prospects, no Littledata account yet)

A Klaviyo prospect — someone who connected a Klaviyo account to the audit tool but has not installed Littledata — has no Intercom company, so their copy lands on the Intercom contact instead. Contacts Intercom has never seen are created as leads.

The series runs only when the audit shows a return of 3× or better (the same bar a destination clears to headline its own hero card) and there is a monthly dollar upside to quote. It stops for good if the prospect starts a trial or a re-audit drops the return under the bar.

Two lanes — only the nudges need building in Intercom

Email Who sends it What marketing has to do
1. Audit summary (immediately) MonitorAI, via POST /messages with its own HTML Nothing. The email is a rendering of the prospect’s hero card — destination mark, headline, typed metric rows, the card’s own “Return on Littledata monthly cost” line, and a button to the full audit. Built in src/services/value/prospectEmailHtml.ts
2. Day 4 and 3. Day 8 (trial nudges) Intercom, from an outbound message on a data event Build the two messages as below

The split is deliberate. The audit summary is the result of something the prospect just did — they connected Klaviyo and asked for an audit — and its whole value is the hero card, which a template built from flat attributes cannot lay out. The two nudges are promotional, so they stay on Intercom’s outbound messages, where unsubscribe links and subscription types are handled. The API lane does neither, and must not be used for marketing sends.

Setup for lane 1: none. The sender is set in code (PROSPECT_EMAIL_SENDER_ADMIN_IDS in src/services/klaviyo/prospectFollowUpEmails.ts): edward@littledata.io first, falling back to support@littledata.io if that teammate is ever deactivated, so the series never goes down with one account. These are Intercom admin (teammate) ids, not contact or user ids. There is no prospect-audit-ready event — MonitorAI sends that email itself, so building an Intercom message on one would double-send.

Verified against the live workspace: an email to a user contact (to: {type: "user", id}) sends and renders. Intercom’s docs never enumerate the other to.type values, so a lead recipient is sent as type: "lead" with a one-shot retry as type: "contact"; the first real send to a newly created lead is the case to watch in the logs.

The prospect_* attributes below are written on every step, both lanes, so the contact record always shows the current audit.

Contact fields (custom attributes)

Create these under Settings → Data → People → Contact data. Six fields, because the audit email renders itself from the hero card and reads none of them — the only consumers are the two nudge templates and segmentation. Use number type for prospect_roi_multiple; text for the rest.

API name Type Example
prospect_upside_short Text For Mother Root we predict $12,400/month in incremental Klaviyo revenue, and they can test for 30 days for free.
prospect_explanation Text Mother Root's Klaviyo audit predicts $12,400/month in incremental Klaviyo revenue once Littledata is live — a 14× return on the $890/month they would pay Littledata after the free trial. — the longer form; use instead of prospect_upside_short, not as well
prospect_org_name Text Mother Root
prospect_destination Text Klaviyo — the destination the headline figure belongs to (Klaviyo, Google Ads, Meta, Microsoft Ads, GA4), for branching imagery or segmenting. Always Klaviyo until a second destination earns a prospect hero card
prospect_audit_url Text https://monitor.littledata.io/audit/XyZ123 — the prospect’s own audit page, {FRONTEND_URL}/audit/{klaviyoAccountId}. Omitted entirely when FRONTEND_URL is unset, so hide the CTA block when it is blank
prospect_roi_multiple Number 14 — the best return a single destination earned. For segmentation (“prospects above 10×”); no email prints it on its own

Both name the value with the same phrase the audit page and the hero card use (“incremental Klaviyo revenue”, “Google Ads efficiency improvements”, …), so one figure never appears under two names across the series — that wording comes from tierFramingForTierName and is changed there, never per-email.

Copy names the brand rather than addressing the reader as “you”: an agency gets one of these per client, and a second-person line would leave them guessing which. Second person appears only where the Klaviyo account has no organisation name to use. The plan cost is framed as what they would pay after the free trial — a return quoted against a plan they have not started reads as a bill.

The attributes are rewritten immediately before every event, so a day-8 nudge quotes the latest audit rather than day-0 numbers.

Trigger events (per contact)

Event name When it fires
prospect-trial-nudge-4day 4 days after the audit summary went out
prospect-trial-nudge-8day 8 days after the audit summary went out

Suggested templates

Emails 2 and 3 — is now a good time? Plain text; no hero card. Marketing owns the “start your free trial” ask and the CTA destination. Insert prospect_upside_short as the one-line reminder of what is on the table, or prospect_explanation for a longer email — pick one, they say the same thing at different lengths — and link prospect_audit_url for the full audit. prospect_org_name suits a subject line. (Email 1 needs no template — see the two lanes above.)

Who gets the series — and who doesn’t


Abandoned-setup series (agency login, no account ever connected)

An agency who signed in with Google on the audit tool but never connected a Klaviyo account has seen the empty dashboard and left. Nothing else contacts them — the prospect series above only starts once an account is connected and audited — so this series is their only follow-up.

All three emails are promotional, so the whole series is Intercom outbound messages on data events (the same lane as the trial nudges above — unsubscribe links and subscription types are handled). MonitorAI sends nothing itself here.

Trigger events (per contact)

Event name When it fires
abandoned-setup-nudge-1day 1 day after the login was created, still no account connected
abandoned-setup-nudge-4day 3 days after the first nudge (day 4 from signup when on time)
abandoned-setup-nudge-8day 7 days after the first nudge (day 8 from signup when on time)

Contact fields (custom attributes)

API name What it holds
monitor_ai_agency_name Text: what MonitorAI calls the agency — an admin-set name, else derived from their login domain (“paperrun.tech” → “Paperrun”), else their Google name. Prefixed because a bare “agency name” on a lead is ambiguous

Rewritten immediately before every event, so a rename lands before the next nudge.

Suggested templates

Plain text. The ask is a single action — connect a client’s Klaviyo account — so link the CTA straight to the portal (https://monitor.littledata.io), where the connect button is the first thing an accountless agency sees. Greet with monitor_ai_agency_name. Good angles: what the audit shows once an account is connected (flow revenue found, predicted uplift), that it is read-only OAuth, and that it takes about a minute.

Who gets the series — and who doesn’t


The monthly value email

MonitorAI renders and sends this one itself, on the day each store’s subscription renews. Nothing to build in Intercom. Two things there support it, both already in place — this section is what they are and what breaks if they change.

1. The old outbound message — set to not live

The Intercom email triggered by monthly-roi-ready is switched off. MonitorAI no longer fires that event, so it would have stopped sending anyway; off is belt and braces, because anyone re-firing the event by hand would otherwise mail the store twice. Don’t set it live again.

2. The subscription type — don’t delete it

“Monitor AI monthly summary” (id 2754512, opt-out, live). Nothing to create.

This is what the unsubscribe link in the email footer toggles, and MonitorAI checks it for every recipient before every send — the POST /messages lane honours no subscription type by itself, so this check is the only thing standing between an opt-out and another email.

The id is hardcoded in src/services/intercom/monthlyValueEmailConsent.ts, not configured, because an unset env var would not fail loudly — it would fall through to a name match, and this type’s name matches none of the patterns, which reads as “no type configured” and skips the check. INTERCOM_MONTHLY_VALUE_SUBSCRIPTION_TYPE_ID overrides it for a workspace that is not ours.

If you ever delete and recreate it, the id changes. The code then falls back to matching by name — so name the replacement “Monitor AI monthly summary” — and the warning subscription type 2754512 is not in this workspace appears in the cron logs. Update the constant when that happens.

What the reader gets

The store’s hero cards — one per destination, each with its tint, headline, metric rows and its own “Return on Littledata monthly cost” line — a See your results button, and an unsubscribe link. Built in src/services/value/customerValueEmailHtml.ts; sent by src/services/intercom/sendMonthlyValueEmail.ts from support@littledata.io.

Deduplicated per store per day, same as before, and skipped entirely when no destination shows positive value.

Creating the days-to-value message in Intercom

  1. Messages → Email → New email
  2. Send when: User / contact triggers eventdays-to-value-reached
  3. Audience: Contacts on the company (events are only created for relevant people)
  4. Frequency: “Every time” is acceptable—Littledata sends trial mail once per store
  5. Insert fields with `` (or your builder’s equivalent)
  6. Use defaults where helpful, e.g. a fallback headline if a field is empty

Checking that it works

  1. In Littledata admin, open the customer → use Preview email (ROI) and Preview trial email when trial fields apply.
  2. In Intercom, open the company and confirm the company attributes fill in after the next value refresh.
  3. Send an Intercom test message to verify formatting.

Troubleshooting (no database access required)

Problem What to check
No email Message is live; event names match exactly; company exists in Intercom; API credential valid
No monthly value email This one is not an Intercom message — check the store’s subscription renewal day has passed, that some destination shows positive value, and that the recipient has not unsubscribed from Monthly value emails. The cron logs one line per store: monthly value email for … - sent N, opted out N, failed N
Two monthly emails The old monthly-roi-ready outbound message is still live in Intercom. Set it to not live
Unsubscribe link shows “We couldn’t save that” The Monitor AI monthly summary subscription type is missing or was recreated under a new id, so there is nothing to record the choice against. Check the cron logs for subscription type 2754512 is not in this workspace and update the constant in monthlyValueEmailConsent.ts
No Monitor: tag for a check I can see failing in the admin Tags follow status changes, so a check that was already failing before tagging existed may have none; the store’s Intercom company must be linked, and the check must be Error / Warning / Info (not Success). Ask your technical owner to run the internal tag reconcile process to re-sync.
Monitor: tag still on a fixed check The tag clears on the audit run that flips the check to Success — wait for the next cycle for that destination, then re-check; persistent drift is fixed by the same tag reconcile process.
An audience stopped matching anyone It is probably built on a label-only tag name from before August 2026 (Monitor: Goal configuration). Repoint it at the marked name — Monitor: Google Ads Goal configuration or Monitor: Microsoft Ads Goal configuration.
Empty company fields Store’s Intercom company is linked; value has been recomputed recently (audits completed); attribute types in Intercom match (number vs text)
Headline present but roi_multiple empty Headline may be a fallback story; multiple is only set when the quantified USD ROI headline applies
Stale ROI Wait for the next Klaviyo / Meta / GA style audit cycle that refreshes value, or ask an admin to re-run value for that store
Last bullet runs into the next sentence (e.g. “customersIf”) The attribute ends without a following space in the HTML; use line breaks for roi_additional_value and place the Slack / footer sentence in its own paragraph or after an explicit <br>. MonitorAI ends roi_additional_value with a newline when non-empty to separate from adjacent inline placeholders.
Preview email shows “Value not yet computed” Monthly ROI preview needs server-side valueMessages—run a value refresh for that store first (same data Intercom uses).
Trial copy looks wrong Trial end date, whether Klaviyo/GA checks show complete setup, and incremental value tier all feed the story—ask support to verify those inputs

For bulk refresh of message fields across many stores, your technical owner can run the approved internal backfill process—they should not paste customer data into public tickets.