Littledata MonitorAI guide

Customer health score — what makes a store Red, Yellow or Green

The customer health score is a single number that tells the Customer Success team how each paying store is doing. It rolls up engagement signals (is there a champion on the account, are they logging in, what data is flowing) and risk signals (a connection was removed, a competitor product is installed, a support issue is open) into one RAG stage — 🔴 Red, 🟡 Yellow, or 🟢 Green — that shows on the store row in cip.littledata.io and on the company sidebar in Intercom.

It is not a forecast and it is not a churn probability. It is a CSM-oriented checklist: every factor that moves the score is something a human can act on.

Who gets scored

Only customers that are all of the following:

Stores outside this set don’t appear in the RAG list and keep their previous score, if any, until they re-qualify. The one exception is the Recent positive call toggle (below) — flipping that for any customer recomputes a score on the spot, even if the customer has no destination connected yet.

History

Every time the nightly run (or a “Recent positive call” toggle) changes a store’s score or its “why” lines, a point is appended to customerHealthScoreHistory — score, stage, lines, lifecycle phase. GET /customers/{shopName}/health-history serves it to the CIP dashboard’s health chart. Unchanged runs write nothing, so the timeline is a list of events. The first time a store churns, syncCustomersCron also freezes its score, MRR and any already-disconnected destinations into customers.churnSnapshot, so a Green churn stays visible as a Green churn.

How to read the result

Stage Score Meaning
🔴 Red ≤ 0 At risk — needs attention now.
🟡 Yellow 1 or 2 Worth watching; one nudge in the wrong direction and they slide to Red.
🟢 Green ≥ 3 Healthy. No intervention needed.

Thresholds were calibrated against the actual score distribution to land roughly 45% Red / 19% Amber / 36% Green — the closest integer-cutoff split to a 1/4 – 1/4 – 1/2 target given that ~33% of stores cluster at score 0.

The exact score is shown alongside the stage so two Greens with different headroom can be told apart (e.g. +8 is far more robust than +1).

Every store also carries a “why this score” list — the same factors below, with their +N / −N contributions — so a CSM can see at a glance which lever moved them.

What pushes the score up

Factor Points What it means
Champion linked +3 The Intercom company has been marked as having an internal champion (someone inside the store who advocates for Littledata). Set via the Champion? attribute on the Intercom company (not on a contact tag — that just identifies which person to use for login timing).
Recent positive call +2 The CSM has flipped the “Recent positive call” toggle in cip.littledata.io to mark that they’ve had a good conversation with the store recently. Entirely manual — no automation guesses this.
First non-GA4 connection +1 The store has at least one of Meta CAPI, Google Ads, Klaviyo or Segment as a connected destination. GA4-only stores do not earn this point.
Second non-GA4 connection +3 The store has two or more of {Meta CAPI, Google Ads, Klaviyo, Segment} connected. Stops at two — adding a third doesn’t earn a further point on this axis.
Klaviyo bonus +1 Klaviyo is one of the connected destinations. Stacks with the two connection bonuses above, so a store with Meta + Google Ads + Klaviyo earns the maximum +5 from connections.

GA4 is not worth any positive points. It is treated as table stakes — a store on GA4 alone reads as “no real destinations connected” for scoring purposes, even though they still qualify to be scored.

Connections come from the live inventory, not the audited destinations. The count reads connectedDestinationTypes (every live ld-shopify Connection), falling back to the audited destinations[] only for a customer the inventory has not reached. destinations[] holds just what MonitorAI audits, so Segment was invisible to it: 132 paying Segment customers had no audited destination at all and went unscored, and the rest scored as if they had connected nothing.

What pulls the score down

Factor Points What it means
No Champion login in 30+ days −1 The most recent login from anyone tagged Champion on the store’s Intercom contacts was 30–89 days ago. (Non-champion logins are intentionally ignored — the question is whether the advocate is still active.)
No Champion login in 90+ days −2 Same signal, 90+ days ago. Replaces the 30-day penalty (not added on top). If the store has no Champion contact at all, this signal doesn’t fire.
Champion left company −4 A contact tagged Champion now shows a different current employer on LinkedIn. The advocate is gone and the +3 “Champion linked” is describing someone who no longer works there, so this is the largest penalty alongside the app embed. Detected by checkContactEmployersCron through marketing-automations’ employer-check API (Bright Data LinkedIn snapshots); the “why this score” line names the person. Clears when CS moves the Champion tag to a new contact (or the next check sees them back at the company).
Champion changed role −1 Same check, same employer, but the champion’s title has changed since we started tracking them (a Head of Ecommerce who is now VP Brand may no longer own the Littledata relationship). Not applied on top of “left company”. Best-effort: since LinkedIn’s Nov 2025 policy change titles mostly come from the headline.
Connection removed −2 A destination integration was connected on the last refresh and is no longer connected now — Meta, GA4, Google Ads, Klaviyo, Microsoft Ads, Segment, TikTok, Pinterest or Attentive. The “why this score” list shows which one. A destination has to disappear from both the audited list and the live connection list before it counts, so a half-finished sync cannot trigger this on its own.
Competitor install detected −3 A competitor product is active on the store. Triggered by any of these audit checks running at Error or Warning for the store: <ul><li>Active alternative flows (klaviyoActiveCompetitorFlows)</li><li>Alternative server-side conversions (googleAdsCompetitorConversions)</li><li>Alternative CAPI detected (metaCompetitorCAPI)</li></ul> The competitor’s name is included in the explanation.
App embed not enabled −4 Every Littledata client-side tracking app embed check that actually ran came back false (appEmbedEnabled, appEmbedEnabledStandardApp, appEmbedEnabledSegmentApp, appEmbedEnabledFreeApp). They are not tracking client-side events. A check that never ran is not evidence: a store with no embed check row is left alone, and so is one whose check threw in ld-shopify (a failed run still writes status: false, which is most of the false embed rows fleet-wide — Customer.shopifyAuditCheckErrors records which).
MonitorAI error −2 The store has at least one MonitorAI audit check at Error. The audits have been refined so an Error is taken as a real problem on its own — there’s no manual gate any more.
MonitorAI warning −1 Same, but the worst audit on the store is a Warning (no Errors). Stops there: Info, Success, and Unknown audit statuses don’t move the score.

The MonitorAI penalty is recalculated from the current audit-check rows on every refresh — fixing the underlying issue (so the audit moves back to Success / Info / Unknown) is what clears it.

How audit checks feed the score

Audit checks feed the score in two ways. Both apply at the same time — they’re independent signals — so a single audit can move the score twice (once via competitor detection, once via the worst-status penalty).

1. Three specific competitor checks → Competitor install detected (−3)

Audit check (system name) Display name in cip
klaviyoActiveCompetitorFlows Active alternative flows
googleAdsCompetitorConversions Alternative server-side conversions
metaCompetitorCAPI Alternative CAPI detected

When any of these is at Error or Warning, the Competitor install detected −3 penalty fires once for the store, regardless of how many competitor checks are red. Competitor names from the checks appear in the explanation.

2. All audit checks → MonitorAI error / warning

Every other audit check the store has — EMQ, conversion-window drift, dataset quality, Klaviyo flow coverage, the same three competitor checks, anything else — feeds the MonitorAI error / warning factor based on the worst single status across the whole catalogue. Error wins over Warning; Info / Success / Unknown don’t count.

This is a single signal per store, not per audit: a store with five Errors and twenty Warnings still scores −2 (one MonitorAI error penalty), not −10. The point of the penalty is “something on this store is at Error / Warning right now,” not “tally the misses.”

Worked example

A Plus store with Meta CAPI + Google Ads + Klaviyo + GA4 connected, a champion linked, no recent positive call, no open issues:

+3 +1 +3 +1 = +8 → 🟢 Green.

Now an Error appears on Active alternative flows (Klaviyo competitor) and nobody from the store has logged in for 45 days. The same audit feeds two factors — the specific competitor pathway and the catch-all worst-audit pathway:

+8 −3 −2 −1 = +2 → slides to 🟡 Yellow (still in the watch band).

The champion then leaves and their Champion? attribute is unset:

A destination is removed:

−1 −2 = −3 → still 🔴 Red, deeper.

Where it shows up

When the score refreshes

The overnight refresh works through the base one store at a time and takes about an hour, so a score you see first thing in the morning is from last night, not from this minute. The “last refreshed” date on the customer detail page is the one to trust: if it is older than yesterday while other stores have moved on, that store’s refresh did not complete and the score on screen is stale — worth flagging rather than acting on.

If a score looks wrong, the most common explanations are:

  1. Champion left but still scoring −4 — the penalty reads the Champion contact tag. Untag the person who left (and tag their successor) in Intercom or from the Contacts tab in cip.littledata.io; the next nightly run clears it. Internal @littledata.io contacts are ignored everywhere.
  2. Champion not detected — the Champion? attribute on the Intercom company isn’t set, or isn’t set to a truthy value (Yes / true / 1). Set it on the company, not on a contact.
  3. Login penalty still on — the login signal reads lastSeenAt only from contacts tagged Champion in Intercom. If nobody on the account carries that tag, you’ll see no login penalty but also no champion benefit; if a contact does carry it but hasn’t logged in, the −1 / −2 will apply until they do.
  4. Old competitor or MonitorAI penalty hanging around — these come from the underlying audit checks. Fix the underlying issue so the audit re-runs at Success / Info / Unknown, and the next overnight refresh removes the penalty automatically.
  5. Store isn’t scored at all — they’re probably missing one of the three prerequisites at the top of this page (a paid plan, Intercom company linked, at least one destination connected). The exception is a “Recent positive call” toggle, which forces a fresh score even without a connected destination.