Conversation Metadata
Operational metrics that provide context about conversational interactions, included in every bid request.
Overview
Conversation metadata provides AI/ML-powered analytics for conversational
interactions. This metadata combines operational metrics and AI-powered
insights, included in OpenRTB bid requests via the BidRequest.ext.aura field.
Data Flow
Metadata Categories
| Metric Category | Purpose |
|---|---|
| Conversation tracking | Session management, sequence tracking |
| Message characteristics | Length, timing, input method |
| Intent analysis | Campaign targeting |
| Sentiment analysis | Tone matching |
| Funnel stage | Bid optimization |
| Audience signals | Interest/behavior targeting |
Conversation Metrics
These operational metrics are included in every bid request:
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
messageSequenceNumber | integer | Yes | Position in conversation, 1-indexed | 3 |
messageLength | integer | Yes | Character count of user message | 45 |
isQuickReply | boolean | Yes | Whether message was a quick reply vs typed | false |
userThinkTimeMs | integer | No | Time in ms between last assistant message and user message | 2500 |
sessionDurationMs | integer | Yes | Total elapsed time in ms since session start | 45000 |
messageSequenceNumber
Position of the current message in the conversation sequence.
Type: integer
Required: Yes
Range: 1 to N (1-indexed)
Example:
{
"messageSequenceNumber": 3
}
Use Cases:
- Track conversation depth
- Identify early vs late-stage conversations
- Optimize bid strategies based on engagement level
messageLength
Character count of the user's message.
Type: integer
Required: Yes
Range: 0 to N
Example:
{
"messageLength": 45
}
Use Cases:
- Gauge user engagement level
- Identify detailed inquiries vs quick questions
- Adjust creative length to match user input style
isQuickReply
Indicates whether the message was a quick reply (button/suggestion) or typed by the user.
Type: boolean
Required: Yes
Example:
{
"isQuickReply": false
}
Use Cases:
- Distinguish between guided and organic interactions
- Identify user engagement patterns
- Optimize for different interaction styles
userThinkTimeMs
Time in milliseconds between the last assistant message and the user's response.
Type: integer
Required: No
Range: 0 to N
Example:
{
"userThinkTimeMs": 2500
}
Use Cases:
- Measure user consideration time
- Identify thoughtful vs impulsive responses
- Optimize timing for follow-up messages
Note: May not be available for the first message in a conversation.
sessionDurationMs
Total elapsed time in milliseconds since the conversation session started.
Type: integer
Required: Yes
Range: 0 to N
Example:
{
"sessionDurationMs": 45000
}
Use Cases:
- Track overall session engagement
- Identify long vs short sessions
- Optimize bid strategies for session depth
Request Structure
Conversation metadata is included in BidRequest.ext.aura:
{
"id": "bid-request-123",
"imp": [...],
"site": {...},
"user": {...},
"ext": {
"aura": {
"messageSequenceNumber": 5,
"messageLength": 32,
"isQuickReply": false,
"userThinkTimeMs": 3200,
"sessionDurationMs": 67000
}
}
}
Complete Example
{
"id": "bid-req-20250104-001",
"imp": [
{
"id": "imp-1",
"native": {
"request": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":80}}]}}"
}
}
],
"site": {
"id": "site-123",
"domain": "aiplatform.com"
},
"ext": {
"aura": {
"messageSequenceNumber": 3,
"messageLength": 45,
"isQuickReply": false,
"userThinkTimeMs": 2500,
"sessionDurationMs": 45000,
"intent": {
"value": "purchase_inquiry",
"confidence": 0.85,
"topics": ["family travel", "outdoor activities"],
"signals": ["asked_about_options"]
},
"sentiment": {
"value": "positive",
"score": 0.8
}
}
}
}
Publisher Implementation
Calculating Metrics
class ConversationMetrics {
constructor() {
this.sessionStartTime = Date.now()
this.messageCount = 0
this.lastAssistantMessageTime = null
}
calculateMetrics(userMessage, isQuickReply) {
this.messageCount++
const now = Date.now()
const metrics = {
messageSequenceNumber: this.messageCount,
messageLength: userMessage.length,
isQuickReply: isQuickReply,
sessionDurationMs: now - this.sessionStartTime,
}
// Add think time if we have a previous assistant message
if (this.lastAssistantMessageTime) {
metrics.userThinkTimeMs = now - this.lastAssistantMessageTime
}
return metrics
}
recordAssistantMessage() {
this.lastAssistantMessageTime = Date.now()
}
}
Usage Example
const conversation = new ConversationMetrics()
// User sends first message
const metrics1 = conversation.calculateMetrics('Hello, I need help', false)
// { messageSequenceNumber: 1, messageLength: 20, isQuickReply: false, sessionDurationMs: 100 }
// Assistant responds
conversation.recordAssistantMessage()
// User sends second message after 2.5 seconds
const metrics2 = conversation.calculateMetrics('Tell me more', false)
// { messageSequenceNumber: 2, messageLength: 13, isQuickReply: false, userThinkTimeMs: 2500, sessionDurationMs: 2600 }
Best Practices
1. Track Session Start Time
Always track when the session starts:
const sessionStartTime = Date.now()
2. Handle Quick Replies Correctly
Distinguish between typed and quick reply messages:
function isQuickReply(message) {
return message.source === 'button' || message.source === 'suggestion'
}
3. Calculate Think Time Accurately
Only include think time when there's a previous assistant message:
if (lastAssistantMessageTime) {
metrics.userThinkTimeMs = Date.now() - lastAssistantMessageTime
}
4. Reset on New Session
Reset metrics when starting a new conversation:
function startNewSession() {
conversation = new ConversationMetrics()
}
Use Cases
Early vs Late Stage Targeting
function getBidModifier(metrics) {
if (metrics.messageSequenceNumber <= 2) {
return 1.0 // Early stage - awareness
} else if (metrics.messageSequenceNumber <= 5) {
return 1.2 // Mid stage - consideration
} else {
return 1.5 // Late stage - intent
}
}
Engagement Level Detection
function getEngagementLevel(metrics) {
const avgMessageLength = 30
const avgThinkTime = 3000
if (
metrics.messageLength > avgMessageLength * 1.5 &&
metrics.userThinkTimeMs > avgThinkTime
) {
return 'high' // Detailed, thoughtful responses
} else if (metrics.isQuickReply) {
return 'low' // Quick, guided responses
} else {
return 'medium'
}
}
Session Depth Optimization
function shouldShowAd(metrics) {
// Don't show ads in very short sessions
if (metrics.sessionDurationMs < 10000) {
return false
}
// Show ads after sufficient engagement
if (metrics.messageSequenceNumber >= 3) {
return true
}
return false
}
Next Steps
- Intent Analysis - User intent signals
- Sentiment Analysis - Sentiment detection
- Field Reference - Complete field documentation