Output Templates
Output templates define how AudienceGPT generates platform-specific segment names and descriptions for each topic. Rather than hardcoding naming logic per DSP, the system uses configurable templates stored in the output_templates table with {{field}} placeholder syntax. This means you can customize naming conventions for Trade Desk, LiveRamp, or any custom platform without touching code.
This guide covers the template engine architecture, the full list of available context fields, how to create and edit templates, and the built-in platform formats.
Architecture Overview
The template engine is implemented as pure functions in src/lib/naming/template-engine.ts -- no database calls, no side effects, usable on both client and server.
The flow for generating platform outputs:
Classification data → buildTemplateContext() → per-platform context
→ generatePlatformName(config, ctx) → segment name
→ generatePlatformDescription(config, ctx) → segment description
Each platform config defines:
- Path fields: Ordered segments that form the segment name (joined by a separator)
- Slug fields: Fields used to generate a URL-friendly slug appended to the name
- Description template: A template string for the segment description
- Character limits: Optional truncation for platform-specific constraints
Template Syntax
Placeholders
Templates use double-curly-brace syntax: {{field_name}}. Unknown field names resolve to an empty string.
{{topic}} {{intent}} > {{category}} > {{subcategory}}
Path Fields
Each path field in a platform config is an object with:
| Property | Type | Description |
|---|---|---|
key | string | Identifier for the field (used for reference) |
label | string | Optional display label in the admin UI |
format | string | Optional format string with {{variable}} placeholders. If omitted, ctx[key] is used directly |
Example path field definitions:
[
{"key": "topic_intent", "label": "Topic + Intent", "format": "{{topic}} {{intent}}"},
{"key": "category", "label": "Category"},
{"key": "subcategory", "label": "Subcategory"},
{"key": "segment_audience", "label": "Seg Audience", "format": "{{audience_tag}} {{audience_type}}"},
{"key": "intensity_awareness", "label": "Intensity + Awareness", "format": "{{intensity}} {{awareness}}"},
{"key": "recency", "label": "Recency", "format": "15-Day"}
]
When a field has a format string, the template engine resolves all {{placeholders}} in it. When it does not have a format, the engine looks up ctx[key] directly from the template context. Empty segments are skipped.
Path Separator
Segments are joined with the pathSeparator (default: " > "):
Salesforce CRM Product Intent > Business-Technology > B2B SaaS > Business In-Market Buyers > Engaged Consideration > Mid-Funnel Active-Eval > 15-Day
Slug
If includeSlug is true, a URL-friendly slug is appended after -:
Salesforce CRM Product Intent > ... > 15-Day - salesforce-crm-product-intent-business-technology-b2b-saas-business-in-market-buyers-active-eval-15-day
The slug is built from the slugFields list, slugified (lowercase, collapse non-alphanumeric to the slugSeparator).
Description Template
The descTemplate is a single template string that generates the segment description. It has access to a {{prefix}} variable that is automatically set based on the topic's segment type:
| Segment Type | Prefix |
|---|---|
| B2B, B2E, B2G | descPrefixB2b (default: "Professionals who") |
| B2C | descPrefixB2c (default: "Consumers who") |
| B2B2C | descPrefixB2b2c (default: "Consumers and professionals who") |
Example description template:
{{prefix}} are actively researching and engaging with {{topic}}-related content across the {{taxonomy_label}} ecosystem. This audience demonstrates {{audience_type_lower}} behavior through sustained interaction with {{taxonomy_description_lower}} content.
If descCharLimit is set, the rendered description is truncated to that many characters.
Available Context Fields
The buildTemplateContext() function produces the following flat key-value map from classification data:
Core Classification Fields
| Field | Description | Example |
|---|---|---|
topic | Topic name | "Salesforce CRM" |
intent | Primary intent signal label | "Product Intent" |
secondary_intent | Secondary intent signal label (or empty) | "Brand Interest" |
secondary_intent_suffix | + Secondary Label or empty | " + Brand Interest" |
group | Taxonomy type (13-group), short form | "Technology-Telecom" |
category | Parent category (41-type), short form | "Business-Technology" |
subcategory | First subcategory (before comma) | "B2B SaaS" |
segment_type | Raw segment type | "B2B" |
audience_tag | Segment audience label | "Business", "Consumer", "Biz+Consumer" |
audience_type | Audience type classification | "In-Market Buyers" |
Tree-Level Fields
| Field | Description | Example |
|---|---|---|
subcategory_l1 | L1 node from taxonomy path | "Enterprise Software" |
subcategory_l2 | L2 node from taxonomy path | "CRM" |
subcategory_l3 | L3 node from taxonomy path | "" |
subcategory_l4 | L4 node from taxonomy path | "" |
These are extracted by splitting the taxonomy_path on > and indexing into the resulting array (L0 is the standard subcategory).
Classification Layer Fields
| Field | Description | Example |
|---|---|---|
intensity | Layer 2 intensity label | "Engaged" |
awareness | Layer 3 awareness label | "Consideration" |
funnel | Buyer journey funnel position | "Mid" |
journey | Buyer journey label | "Active-Eval" |
sensitivity | Sensitivity classification | "Standard" |
composite_score | Composite intent score (0--100) | "65" |
Platform-Specific Fields
| Field | Description | Example |
|---|---|---|
recency | Per-template recency value | "15-Day", "Daily" |
org_alias | Organization alias for intermediary providers | "Think Data Group" |
partner_alias | Partner alias for downstream data company | "" |
Data Alliance Fields
| Field | Description | Example |
|---|---|---|
user_behavior | User behavior classification | "Intent", "Interest", "Ownership" |
user_behavior_lower | Lowercase version | "intent" |
model_process | Modeling process | "Page Level", "Site Domain" |
user_market | Target market/region | "United States" |
Description-Specific Fields
| Field | Description | Example |
|---|---|---|
taxonomy_label | Full parent category label | "Business Technology" |
taxonomy_label_lower | Lowercase version | "business technology" |
taxonomy_description | Parent category description | "B2B SaaS, Enterprise Software..." |
taxonomy_description_lower | Lowercase version | "b2b saas, enterprise software..." |
audience_type_lower | Lowercase audience type | "in-market buyers" |
audience_type_people | People-form of segment type | "professionals", "consumers" |
domain_signals_top3 | Top 3 domain signals | "salesforce.com, hubspot.com, zoho.com" |
domain_signals_top3_lower | Lowercase version | "salesforce.com, hubspot.com, zoho.com" |
group_lower | Lowercase taxonomy type group | "technology & telecom" |
User Behavior Auto-Derivation
When userBehaviorOverride is not set on a template, the user_behavior field is automatically derived:
| Condition | Derived Value |
|---|---|
| Audience type contains "owner" | "Ownership" |
| Audience type contains "past purchaser" or "previous buyer" | "Past Purchaser" |
| Audience type contains "decision maker" | "Decision Maker" |
| Primary intent is product, service, or solution | "Intent" |
| Primary intent is brand or event | "Interest" |
| All other cases | "Interest" |
Built-in Platform Formats
AudienceGPT ships with four pre-seeded output templates (created by migration 0015_output_templates.sql):
Trade Desk (Koa)
- Platform key:
tradedesk - Path: Topic+Intent > Category > Subcategory > Segment Audience > Intensity+Awareness > Funnel Journey > Recency
- Description char limit: 500
- DB columns:
segment_name_tradedesk,segment_desc_tradedesk
LiveRamp
- Platform key:
liveramp - Path: Topic+Intent > Group > Category > Subcategory > Segment Audience > Journey > Recency
- Description char limit: 245
- DB columns:
segment_name_liveramp,segment_desc_liveramp
Internal
- Platform key:
internal - Path: Topic > Intent (with secondary) > Group > Category > Subcategory > Segment > Intensity > Awareness > Funnel Journey > Recency
- Description char limit: None (unlimited)
- DB columns:
segment_name_internal,internal_description
Index Exchange
- Platform key:
indexexchange - Path: Topic+Intent > Category > Subcategory > Segment Audience > Journey > Recency
- Description char limit: 300
- DB columns: None (stored in
platform_outputsJSONB) - Status: Inactive by default
DB Column Mapping
Templates can write their outputs to either dedicated DB columns or the generic platform_outputs JSONB column:
| Approach | Config Fields | Usage |
|---|---|---|
| Dedicated columns | dbColumnName, dbColumnDesc | Built-in platforms (Trade Desk, LiveRamp, Internal) with existing column infrastructure |
| JSONB storage | Both are null | Custom platforms, stored in platform_outputs keyed by platformKey |
The mapOutputsToTopicFields() function handles this routing automatically.
Creating a New Template
Via the Admin UI
- Navigate to Admin > Output Templates
- Click Create Template
- Fill in the configuration:
| Field | Required | Description |
|---|---|---|
| Platform Key | Yes | Unique identifier (lowercase, no spaces). E.g., "custom_dsp" |
| Display Name | Yes | Human-readable name. E.g., "Custom DSP" |
| Active | No | Whether to generate outputs for this template (default: true) |
| Sort Order | No | Display ordering (default: 0) |
| Path Fields | Yes | Array of path field objects (see syntax above) |
| Path Separator | No | Separator between path segments (default: " > ") |
| Slug Fields | No | Fields to include in the slug |
| Slug Separator | No | Character between slug parts (default: "-") |
| Include Slug | No | Whether to append a slug (default: true) |
| Desc Template | No | Description template string |
| Desc Char Limit | No | Maximum description length |
| Desc Prefix B2B | No | Prefix for B2B topics (default: "Professionals who") |
| Desc Prefix B2C | No | Prefix for B2C topics (default: "Consumers who") |
| Desc Prefix B2B2C | No | Prefix for B2B2C topics (default: "Consumers and professionals who") |
| Recency | No | Default recency value for this platform (e.g., "15-Day") |
- Use the live preview to verify the output
- Save the template
API: POST /api/admin/output-templates
Via the API
{
"platformKey": "custom_dsp",
"displayName": "Custom DSP",
"isActive": true,
"sortOrder": 5,
"pathFields": [
{"key": "topic", "label": "Topic"},
{"key": "category", "label": "Category"},
{"key": "audience_tag", "label": "Audience"}
],
"pathSeparator": " | ",
"slugFields": ["topic", "category"],
"slugSeparator": "-",
"includeSlug": false,
"descTemplate": "{{prefix}} show interest in {{topic}} within {{taxonomy_label}}.",
"descCharLimit": 200,
"recency": "30-Day"
}
After creating or updating a template, the platform config cache is automatically invalidated. However, existing topics are not automatically regenerated. To apply the new template to all topics, run a bulk reclassify job (which regenerates all platform outputs).
Editing an Existing Template
- Navigate to Admin > Output Templates
- Click the template you want to edit
- Modify fields as needed
- Use the live preview to verify changes
- Save
API: PATCH /api/admin/output-templates/[templateId]
Live Preview
The preview endpoint lets you test a template configuration without saving it:
API: POST /api/admin/output-templates/preview
The preview uses a sample topic ("Salesforce CRM" in "Business Technology" / B2B) and returns:
{
"name": "Salesforce CRM Product Intent | Business-Technology | Business",
"description": "Professionals who show interest in Salesforce CRM within Business Technology.",
"descLength": 78,
"context": {
"topic": "Salesforce CRM",
"intent": "Product Intent",
"category": "Business-Technology",
...
}
}
The context object shows all resolved template variables, which is helpful for understanding what values are available and how they render.

Activation Integration
When a connection is configured for segment activation (push to DSPs), the template key is stored on the connection record. During activation:
- The system loads the platform config matching the connection's template key
- Generates the segment name and description using that template
- Pushes the generated name/description to the platform API
This means the same topic can have different names on different platforms, all driven by their respective templates.
Data Alliance Template
The Data Alliance format is a specialized template that includes additional fields for intermediary data providers:
| Field | Purpose |
|---|---|
org_alias | Organization alias (e.g., "Think Data Group") |
partner_alias | Partner alias for the downstream data company |
user_behavior | Behavioral classification (Interest, Intent, Ownership, etc.) |
model_process | Modeling methodology (Page Level, Site Domain, LAL) |
user_market | Geographic market (e.g., "United States") |
These fields are set per-template in the platform config and resolved by buildTemplateContext(). The user_behavior field can be either a fixed override (set on the template) or auto-derived from classification signals.
Best Practices
- Use the preview before saving -- verify the generated name looks correct with a sample topic
- Set character limits for external platforms -- most DSPs have maximum name/description lengths; exceeding them causes silent truncation or errors
- Keep path fields focused -- include only the segments that add value for the target platform. Not every platform needs all classification layers.
- Use the description prefix fields -- they ensure B2B and B2C topics get appropriate language without needing conditional logic in the template
- Test with different topic types -- a template that looks good for B2B SaaS may not work well for B2C retail. Test across categories.
Next Steps
- Global Topics -- See how templates affect topic platform outputs
- Export -- Export topics with platform-specific names
- Background Jobs -- Regenerate outputs after template changes via reclassify