An audience is a saved query against contacts (or any CRM record) that materialises a list of recipients at the time a campaign launches. Audiences let you write the filter once — "VIP customers who opened an email in the last 30 days" — and reuse it across campaigns, ads, automations, and reports.
Audience CRUD
/crm/audiences/segmentsJWT/crm/audiences/segmentsJWT/crm/audiences/segments/:idJWT/crm/audiences/segments/:idJWT/crm/audiences/segments/:idJWTA segment body:
{
"name": "VIP recent openers",
"description": "VIP-tagged contacts who opened a marketing email in the last 30 days",
"filter": {
"datatype": "contact",
"where": {
"$and": [
{ "tags": "vip" },
{ "lastEmailOpenedAt": { "$gte": "2026-03-25T00:00:00Z" } }
]
}
},
"type": "dynamic"
}
The filter object uses the DynamicQuery syntax — the same MongoDB-style operators the rest of AppEngine accepts. type is dynamic (re-evaluated at use) or static (a frozen list of contact IDs).
Custom audiences
/crm/audiences/customJWT/crm/audiences/customJWT/crm/audiences/custom-typesJWTCustom audiences are uploaded lists — CSV imports, lookalike seeds, ad-platform-synced audiences. custom-types returns the categories the platform supports (file upload, customer match, lookalike, retargeting pixel).
Insights and reach estimation
/crm/audiences/segments/:id/insightsJWT/crm/audiences/estimate-reachJWT/crm/audiences/segments/:id1/overlap/:id2JWTinsights returns demographic and engagement breakdowns of the current segment population. estimate-reach accepts a filter and returns a count without saving, which is what the audience builder uses for "this matches 1,247 contacts" feedback as the user edits.
const reach = await fetch('/api/crm/audiences/estimate-reach', {
method: 'POST',
headers: { orgid: ORG_ID, Authorization: `Bearer ${jwt}` },
body: JSON.stringify({
filter: {
datatype: 'contact',
where: { country: 'US', tags: { $in: ['lead', 'mql'] } },
},
}),
}).then(r => r.json());
// { count: 1247, sampleProfile: { ... } }
overlap between two segments returns how many contacts appear in both — useful for knowing whether two campaigns will hit the same people.
Targeting helpers
/crm/audiences/interestsJWT/crm/audiences/locationsJWT/crm/audiences/targeting-optionsJWTThese return platform-specific taxonomies (Facebook interests, geo regions, ad platform targeting trees). The audience builder UI consumes them so users pick from real ad-platform values rather than free-typing strings that won't sync.
Using audiences
Audiences plug into:
- Marketing campaigns — set
audienceId(see Marketing campaigns). - Automations — trigger a flow when a contact enters or leaves an audience.
- Ads — sync to Facebook, Google, TikTok, LinkedIn ad platforms via the ads module.
- Reports — slice analytics by audience membership.
Dynamic audiences are evaluated lazily. A campaign launched at noon sees the audience as it exists at noon. If you add a contact at 12:01, they won't be in that send — but they will be in the next launch.
Performance
Audience evaluation hits the same indexes as the data layer. If a filter scans tens of thousands of contacts and runs slowly, add an index on the filtered fields via POST /collection/index. The platform doesn't pre-materialise dynamic audiences — every read goes through MongoDB.