Home Blog Contact
Home/Blog/Why Your Klaviyo Segment Count Keeps Changing
How toKlaviyoKlaviyoSegmentationDiagnostics

Why Your Klaviyo Segment Count Keeps Changing

10 min readBy Miloš Mitrović

If a Klaviyo segment count changed overnight and nobody touched the definition, the most likely answer is that nothing is broken. A segment is a live definition evaluated against profile and event data at the moment you ask for it, so any condition anchored to "in the last 30 days" or "zero times since" moves on its own as the clock advances and events land. The useful question is not why the number moved, but whether it moved inside the band your definition should produce. Below is the drift you should expect, the drift that signals a problem, and an audit that separates them in about twenty minutes.

Key takeaways

  • Segments are evaluated live, so counts with rolling time windows change continuously. A stable number is often more suspicious than a moving one.
  • Drift has a shape. Slope is normal, a cliff is not, and a flat line on a time-based segment usually means the feeding metric stopped arriving.
  • Counts tell you magnitude. Profile IDs tell you cause. Diff the membership two days apart and classify who left.
  • Segment size is not send size. Suppression, consent and sending rules sit between the two, so the two numbers should never be expected to match.
  • Anything reported to a board or a client needs a timestamped snapshot, not a live segment count read on the day of the meeting.

Why the number moves when nobody edited it

The count moves because Klaviyo recomputes membership rather than storing it. Every profile that crosses a threshold enters or leaves without any action from you, and on an account of any size that happens thousands of times a day. Klaviyo's API reflects this design directly: segment size is not a first class attribute you read back, it is an optional extra you request alongside the segment record via additional-fields[segment]=profile_count, documented on the Get Segment endpoint. Treat that number as a computed value with its own refresh cadence, not as a figure you can pin to a timestamp.

Three independent clocks drive the movement. The window clock advances, so the trailing edge of "last 90 days" drops profiles every hour. The event clock delivers new opens, clicks and orders, which pulls profiles in. The consent clock removes people through unsubscribes, bounces and suppression uploads. A count that sits perfectly still across all three is worth a look, because on a sending account it should not.

Which conditions drift by design

You can predict most of the movement from the condition types in the definition. Open the segment and classify each condition before you investigate anything.

Condition typeWhy it movesShape of the movement
Engagement in the last N days (opened, clicked)Both edges of the window move, and sends inject new matchesSmooth slope with steps on send days
Placed Order zero times since a datePurchases push profiles out one at a timeGradual decline, faster during promotions
Predictive fields (churn risk, expected date of next order)Recomputed by Klaviyo on its own schedule, not on event arrivalBatch steps at regular intervals
Profile property written by a flow or API jobMoves only when the writer runsSharp steps that match your job schedule
Consent or suppression statusChanges with every unsubscribe, hard bounce and spam complaintSlow one way decline
Is in list XStatic membership, changes only on import or manual editFlat until someone acts

Mixed definitions inherit the noisiest component. A segment that combines a 30 day engagement window with a nightly property write will show a slope plus a step every night, and operators frequently report the step as a bug when it is the job doing its work. If the window itself is the thing you are unsure about, the window length deserves its own decision rather than a template default, which I covered in sizing an engagement window by repurchase interval.

How much drift is normal for your account

You cannot judge drift without a baseline, and almost nobody has one. Build it in an afternoon: pull profile_count for every segment that drives a send or a report, once a day at the same hour, and store the value with a timestamp. After fourteen days you have a distribution instead of an opinion.

From accounts I have run, the rough bands look like this. A 90 day engaged segment on a store sending two or three campaigns a week typically moves under two percent day over day, with visible bumps the day after a send. A 30 day window on the same account moves three to six percent, because the trailing edge is doing more work. A segment keyed on a nightly property job is flat all day and steps once. Your numbers will differ, which is the point of measuring rather than borrowing mine. Once the band exists, a ten percent swing on a day with no send and no import becomes a signal instead of a shrug.

Set the alert on the percentage, not the absolute. Absolute thresholds break the moment the list grows, and you will end up either muting the alert or ignoring it.

Segment size is not your send size

Expecting the segment count to match campaign recipients is the most common source of false alarms. The two numbers are produced by different systems. Segment size answers "who matches this definition right now". Recipient count answers "who is eligible to receive this message after suppression, consent, deduplication and sending rules are applied". Klaviyo even models the recipient figure as a separate asynchronous estimation job rather than a property of the segment, which you can see in the campaign recipient estimation reference.

Between the two numbers sit suppressed profiles, profiles without valid email consent, profiles that received a message inside a smart sending interval, and deduplication across overlapping audiences. Smart sending in particular removes people from a specific send without touching segment membership, and it is often mistaken for a frequency policy when it is not one. I went through that distinction in why smart sending is not a frequency policy. If your segment shows 84,000 and the campaign estimates 71,000, that gap is the system working, and the gap is worth tracking as its own metric over time.

The twenty minute audit

Run this in order and stop at the first step that explains the movement. Most cases resolve at step two or three.

  1. Confirm nobody edited it. Pull the segment record and read the updated timestamp. If it changed recently, you have your answer, and the next conversation is about change control rather than data.
  2. Check event volume upstream. Chart daily event counts for every metric the definition references. If Placed Order events dropped forty percent on the day the segment moved, the segment is reporting an ingestion problem accurately. Integration gaps of this kind are common enough to deserve their own check, covered in Shopify webhook blind spots.
  3. Check for bulk profile operations. Imports, suppression uploads, profile deletions and merges all move counts in a single step. Duplicate cleanup is a frequent culprit, since merging two profiles removes one from every segment it matched. See merging duplicate Shopify customers safely for the side effects.
  4. Inventory the property writers. For every custom property in the definition, list everything that writes it: flows, the API, integrations, manual imports. More than one writer on the same property means the value depends on execution order, and the count will oscillate accordingly.
  5. Diff the actual membership. This is the step that produces an answer rather than a theory. Pull the profile IDs in the segment today and again in twenty four hours, then compare the two sets.
GET /api/segments/{segment_id}/profiles/?page[size]=100&fields[profile]=email,created
# paginate, store IDs, repeat tomorrow, then diff the two sets

The Get Segment Profiles endpoint paginates, so on a large segment this is thousands of calls. Pace it against the published limits in Klaviyo's rate limits and error handling guide, and if you are running this across several brands under one key, read how one API key throttles multiple accounts first.

Then classify the profiles that left. If they are all people whose last engagement date just passed the window edge, the drift is normal and you are done. If the leavers are spread evenly across every cohort, including people who engaged last week, a property or event stopped writing and you now know which one.

What a broken definition actually looks like

Broken definitions have signatures that normal drift does not produce. A cliff is the clearest: the count falls by a third or more in a single evaluation with no corresponding drop in event volume and no import. That pattern usually means the definition points at something that no longer exists, most often a metric that was recreated when an integration was reinstalled. Metric identifiers do not survive that, which is the same trap that breaks copied flows and is worth understanding in why a metric ID is worthless in another account.

A flat line is the second signature, and it is the one people never report. A 60 day engagement segment that returns exactly the same count for nine days straight is not stable, it is stuck, and the usual cause is that the metric feeding it stopped receiving events entirely. The count freezes at its last valid value and looks healthy on a dashboard. If a segment has stopped matching new profiles altogether, the diagnostic path is narrower and I wrote it up separately in diagnosing a segment that stopped matching.

The third signature is oscillation with a fixed period. A count that rises every night and falls every morning is a job fighting the definition, typically a flow that sets a property and another process that clears it. That one is a data ownership problem, not a segmentation problem, and no amount of adjusting the segment will settle it.

How to get a number you can put in a report

Stop reading live segment counts for anything that gets reported. A live definition is the correct tool for targeting a send and the wrong tool for stating how many engaged customers you had in August, because the answer changes between the time you write the slide and the time someone opens it.

Two options work. Snapshot the count daily into your own store with a timestamp, and report from the snapshot series, which also gives you the baseline from the earlier section for free. Or, where you need the exact population preserved rather than just its size, copy the members into a static list on the day you measure and keep that list as the record. The second is heavier but it lets you go back and ask who was in the number, which is the question that always follows.

For revenue and retention figures, do not derive them from segment membership at all. Report from send and order level data, which is stable once written. The reasons that matters more as volume grows are in retention reporting past a million orders, and the reconciliation habits that keep the numbers defensible are in reconciling Klaviyo revenue with Shopify.

Trade-offs and what I would do

The first trade-off is freshness against auditability. Live segments are always current and never reproducible. Snapshot lists are reproducible and immediately stale. You need both, used for different jobs, and the mistake is picking one and forcing it to serve the other purpose.

The second is window width. A 30 day engagement window responds faster to behaviour change and drifts visibly enough that operators lose confidence in it. A 365 day window looks reassuringly stable and hides deterioration for months. I take the tighter window and the visible drift, because the drift is information, but only if you have built the baseline first. Without a baseline, a tight window generates alarm rather than insight.

The third is monitoring effort. Daily snapshots for every segment in a large account is real work to build and maintain. I would not do it for everything. I would do it for any segment that triggers a send, any segment quoted in a report someone acts on, and any segment feeding a suppression decision. Everything else can drift unobserved, and if a number in that group ever matters, the first move is to start snapshotting it and wait two weeks before drawing a conclusion.

One judgement call worth stating plainly: when a count moves and you cannot explain it, do not edit the definition. Editing resets the only history you have and guarantees the next investigation starts from zero. Diff the membership, find the cause, then change the definition if the cause warrants it.

Sources

M
Miloš Mitrović
Email Marketing for Ecommerce

Have a question or a project?

Whether it is about this post or a system you want built, I'm happy to talk.

Get in touch

404

Post not found. It may have been moved or the link is incorrect.

← Back to the blog
Summarize with AI
ChatGPT, Perplexity, and Grok open with the prompt ready to run. Claude, Gemini, and Copilot open a chat with the prompt copied; press Ctrl+V (Cmd+V on Mac) to paste. The full text is included, so it works even without web access.