Winback Audience With Stale Event Data and Overlapping Suppression
A meal-kit subscription service wants to send a winback campaign to users who canceled at least 60 days ago, have not placed an order in the last 45 days, and have opened at least one email in the last 90 days. The audience is built in Iterable as a dynamic audience with criteria: subscription_status = canceled, last_order_date < now - 45 days, and email_open event occurred in last 90 days. The list size is 84,000, but the CRM team says only 61,000 users meet the criteria. The discrepancy appears because last_order_date is updated by a nightly batch at 2 a.m., and the email_open event is streamed but some opens are attributed to a generic email_open event without campaign ID. The company also has a 60-day suppression list for users who complained, and a policy that winback messages cannot be sent to users with an active subscription. The campaign is scheduled for Monday 9 a.m.
1. Why might the dynamic audience size differ from the CRM count, and what would you check first?
Read the worked answer
The 84,000 vs. 61,000 gap is large enough that I would treat it as an over-inclusion problem, not a rounding issue. The most likely causes are:
- Stale
last_order_date: the nightly batch at 2 a.m. means orders placed after 2 a.m. are not reflected. A user who ordered yesterday afternoon may still look like they have not ordered in 45 days, so they are incorrectly included. - Generic
email_openevent: if the audience counts anyemail_open, including transactional or non-marketing opens, it will include users who never opened a marketing email. That inflates the audience. - Dynamic audience refresh timing: the audience may not have recomputed after the last batch, so it reflects an older data state.
- Suppression and active-subscription exclusions not applied in the count: if the preview count does not apply the 60-day complaint suppression or the active-subscription policy, the number will be higher than the CRM count.
I would first compare a sample of 100 users in the dynamic audience against CRM records, checking last_order_date, subscription_status, and the specific open event. Then I would check the audience refresh timestamp.
2. How would you redesign the audience and the send to avoid messaging active subscribers and recent complainers?
Read the worked answer
I would separate inclusion from exclusion and enforce both at send time.
Inclusion criteria: canceled at least 60 days ago; no order in 45 days based on the freshest order data available; at least one marketing email open in 90 days, using a campaign-specific open event or a marketing-only event filter.
Exclusions:
subscription_status = active- exclude explicitly, not just by relying oncanceled.- 60-day complaint suppression list - exclude by list membership.
- Global unsubscribe, hard bounce, and any account-level suppression.
- Current winback journey members or recent winback recipients within a frequency window.
I would not rely on a static snapshot. I would either build a dynamic audience that includes these exclusions and confirm it refreshes after the 2 a.m. batch, or use a journey with send-time filters that re-check active subscription and suppression immediately before send. The Monday 9 a.m. send should be scheduled after the batch and after a final audience refresh. I would also keep a small holdout to measure winback lift.
3. What metrics would you monitor to catch over-inclusion before the campaign goes out?
Read the worked answer
Before send, I would monitor audience composition, not just total size:
- Active-subscriber overlap: count audience members whose current
subscription_statusis active. The target is zero; any nonzero value is a blocker. - Suppression overlap: count members on the 60-day complaint list and global suppression. Again, the target is zero.
- Order recency distribution: bucket the audience by days since last order. A spike in the 0–45 day bucket suggests stale
last_order_datedata. - Open-event source mix: show how many members qualify because of a generic
email_openvs. a campaign-specific open. A high generic share means the open criterion is too broad. - Audience count trend: compare the dynamic audience count before and after the nightly batch. A large drop after refresh indicates the earlier count was stale.
I would also run a seeded test send to internal addresses and inspect the first 1,000 records manually. If active subscribers or suppression overlaps exceed 0.5%, I would pause the campaign and fix the audience logic.