Every growth team has the same loop: marketing asks for a cohort, analyst writes Postgres / dbt / Looker SQL, ops re-pulls hashed identifiers, someone uploads to Meta, someone else mirrors into Klaviyo. Four tools, three hand-offs, two days. The audience definition lives in a Slack message; the implementation lives in four places.
Win-back campaigns lag by 2-3 weeks. Audience definitions drift between platforms (Klaviyo's 'lapsed' isn't Meta's 'lapsed'). Identifier hashing gets done wrong on at least one platform. And every cohort change is another SQL ticket — so teams stop iterating.
Most cohort definitions are time-windowed: 'lapsed 60d', 'high-LTV 365d', 'YoY repeat buyers'. If your warm event store has 30-day retention (Lite) or 90-day (Starter), 'lapsed 180d' literally cannot be expressed. Scale's 365-day retention is the floor for a working audience system. Pro's 2-year retention is the floor for YoY churn-prediction baselines.
// workers/api/src/ai/audience-compiler.ts
const AudienceFilter = z.object({
suggested_name: z.string().max(64),
estimated_user_count: z.number().int(),
event_filter: z.object({
all: z.array(EventClause).min(1),
}),
platforms: z.array(
z.enum(["meta","google","tiktok","klaviyo"])
).min(1),
});
await anthropic.messages.create({
model: "claude-opus-4",
tools: [{
name: "compile_audience",
input_schema: zodToJsonSchema(AudienceFilter),
}],
tool_choice: { type: "tool", name: "compile_audience" },
messages: [{ role: "user", content: nlDescription }],
});Sends batches keyed on email_sha256, phone_sha256, fbp, external_id. SHA-256 lowercased per Meta hashing spec. CUSTOM source, 30-day retention attribute.
OfflineUserDataJob with hashedEmail, hashedPhoneNumber, hashedFirstName + hashedLastName + countryCode + postalCode. Crm-based user list, upload + close in one job.
EMAIL_SHA256, PHONE_SHA256, IDFA_SHA256, GAID_SHA256. file_paths upload via TT MMP, then create custom audience referencing the file id. EU residency respected.
Profile attributes only (Klaviyo dedupes on raw email). External_id mirrored into custom property. Adds the audience as a Klaviyo segment via segment-create on first sync.
Define: purchased ≥1 in last 365d AND no purchase in last 180d. Sync to Meta + Klaviyo. Needs 365-day retention to look back far enough — Scale tier covers it. On Lite (30d) or Starter (90d) the cohort definition can't even compile because the lookback exceeds your retention window.
Define: ltv_usd ≥ 1000 AND purchases ≥ 5 within 365d. Sync as exclusion to Meta and Google ads to stop wasting acquisition budget on existing repeat buyers. Estimated count surfaces in dashboard before sync — no platform call until you confirm.
Define: add_to_cart in last 7d AND no purchase since AND cart_value_usd ≥ 200 AND viewed_product_count ≥ 4. Sync to Meta CAPI as audience and Klaviyo as flow trigger. Refreshes every 6h via the cron worker.
We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.
We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.