Skip to contentSkip to navigationSkip to topbar
Page tools
Useful for sharing or LLM
Accelerate development with AI

On this page
Looking for more inspiration?Visit the

Core concepts


Conversation Insights aggregates conversational outcomes into queryable business metrics. Use it to discover the data available across your conversations and to aggregate your conversation metrics.

Conversation Insights helps you answer the question: "what is happening across all my Conversations?" An outcome is a property of a whole conversation, such as whether it was resolved, whether it escalated, or whether it met your compliance criteria. Conversation Insights rolls those outcomes up across your entire conversation volume so that you can measure and compare them.

Producing those aggregate answers has traditionally meant building a pipeline: pulling data out of each product, modeling it, and maintaining the joins as those products change. Conversation Insights performs that assembly for you and exposes the result through a query API.

This page explains the model behind it. Conversation Insights uses a semantic data model based on OLAP (Online Analytical Processing) concepts: the cubes your data is organized into, how those cubes are layered, and the measures and dimensions you use to query them.


Cubes

cubes page anchor

A cube is a collection of related data organized for analysis. Each cube contains measures and dimensions that you can query together. Conversation Insights provides the following cubes:

LayerCubeDescription
GoldConversationSummaryOne row per conversation, with metadata, participant counts, and sentiment rolled up into a single record.
SilverConversationConversation metadata from Conversation Orchestrator, including participant details.
SilverOperatorResultResults from intelligence operators run on conversations.

Gold and silver cubes

gold-and-silver-cubes page anchor

Conversation Insights organizes its cubes into gold and silver layers, following the medallion model common in analytics data modeling.

  • Gold (ConversationSummary): Holds exactly one row per conversation, with every attribute as a single value on that row. Because the row and the conversation are the same thing, you can combine attributes from across the conversation in one query without double-counting, and counting rows counts conversations.

    The gold cube is analytics ready. One row per conversation is the shape that data warehouses, BI systems, and analytics tools expect, so you can load it into your reporting stack and start building against it without first joining data from several sources.

  • Silver (Conversation, OperatorResult): Keeps each underlying record at its own grain, so a single conversation can produce several rows in each of them. A conversation has multiple participants, and an intelligence configuration can run multiple operators. This shape preserves the individual records for detailed analysis, and it means a new custom operator adds rows rather than requiring a schema change. It also means row counts and conversation counts aren't the same number.

(information)

What gold and silver mean here

In Conversation Insights, gold and silver describe the shape of the data rather than how refined it is. Both layers are conformed, query-ready, and reflect final conversation state. Silver isn't staging data, and it isn't less reliable than gold. Neither layer is better than the other: gold answers questions about conversations as units, and silver answers questions about what happened inside them.

Conversation Insights doesn't expose a bronze layer of raw events. To work with raw product events, use Event Streams.

Choosing a cube is less about how complex your query is than about the vantage point you want to analyze from. Each cube anchors analysis on a different resource, and the cube you pick determines what a single row represents.

  • Anchor on the conversation when you want to treat conversations as units: how many closed, what their sentiment was, or how they divide between AI and human agents. Use ConversationSummary.
  • Anchor on the participant when your question is about who took part in a conversation. Use Conversation.
  • Anchor on the operator result when you want to explore Conversation Intelligence output directly: which operators ran, what each one returned, and which knowledge base informed them. Use OperatorResult.

The following table maps common questions to a starting cube.

Your questionCubeWhy
How many conversations closed last week?ConversationSummaryOne row per conversation, so the count is a conversation count.
What is the sentiment breakdown across conversations?ConversationSummarySentiment is a single value per conversation on the summary row.
How do conversations with AI agents compare to conversations with human agents?ConversationSummaryHasAIAgent and HasHumanAgent flag the whole conversation.
Which operators ran, and what did each one return?OperatorResultEach operator result keeps its own row, with the operator name and label.
Which participants took part, and what type was each one?ConversationParticipant attributes are available per row.
Which knowledge base did an operator use?OperatorResultThis cube records knowledge base and memory store identifiers per operator result.
What is the average lead score my custom operator produced, by channel?ConversationSummaryCustom measures are available here at one value per conversation.

If you are unsure where to start, use ConversationSummary. It answers the widest range of questions with the least assembly, and you can move to a silver cube when you need the individual records behind a number.

Each query targets a single cube. You can't combine measures and dimensions from two cubes in one request, so to bring results together, run a query per cube and join them in your own application on ConversationId.


Measures are numeric values that can be aggregated. Use measures to count, sum, or calculate statistics across your data. For example, Conversation.Count returns the count of unique conversations.

Each cube ships with built-in measures, and you can add your own. Registering a numeric field from a Conversation Intelligence custom operator as a custom measure makes it aggregatable in the same way, so a lead score or QA rating your operators produce becomes queryable across your whole conversation volume. See Define and use custom fields.


Dimensions are attributes that describe your data. Use dimensions to filter results or group measures into categories. For example, Conversation.ConversationStatus contains the status of the conversation.


ConversationSummary cube

conversationsummary-cube page anchor

The ConversationSummary cube contains one row per conversation, combining data from across the Conversations layer into a single record. A conversation can span several channels, involve several participants, and have several intelligence operators run against it. The summary cube resolves all of that into one row, with one value per attribute.

Two products contribute data today:

(information)

More data sources are planned

Additional Conversations layer products are planned as sources for this cube, including customer profile traits from Conversation Memory and the knowledge that informed a conversation from Enterprise Knowledge. Conversation Memory is already represented by CustomerProfileId, which you can use to join this cube to your own profile data.

How the summary row is built

how-the-summary-row-is-built page anchor

Three kinds of normalization reduce a conversation to a single row.

Participants become counts and flags. Rather than one row per participant, or numbered participant columns, the cube records how many participants took part, which you can aggregate with the ParticipantsSum, ParticipantsAvg, ParticipantsMin, and ParticipantsMax measures. Two boolean dimensions, HasHumanAgent and HasAIAgent, record whether at least one human agent or AI agent took part. A conversation handed off between an AI agent and a human agent has both set to true. It also records CustomerProfileId, the Conversation Memory profile identifier of the customer participant.

Repeated operator runs collapse to the latest result. If an operator runs several times during a conversation, the summary row holds the most recent value available when the row is written. The cube reflects the final state of the conversation rather than a history of operator executions. The silver OperatorResult cube keeps every run as its own row, so the same measure can return a different aggregate there. See Multiple results in one conversation.

Each operator result becomes its own attribute. Every value is a column on the same row, so you can filter and group across results from different operators in one query. The silver OperatorResult cube keeps each result on its own row, which means combining two operators there takes more than one query.

Conversation Insights populates an operator-derived attribute only for conversations the operator actually ran on. A conversation without a given operator has null for that attribute, so grouping by it can produce a null group representing conversations the operator didn't analyze.

(warning)

The summary row is a snapshot taken at conversation close

Conversation Insights writes the summary row once, when a conversation reaches the CLOSED state, approximately 15 minutes after the conversation ends. The row captures the operator results available at that moment and never changes afterward, so an operator result that arrives after the conversation closes doesn't appear in this cube.

This has two consequences:

  • In-flight conversations don't appear here. To analyze conversations that are still open, query the silver Conversation cube.
  • Post-conversation operator results aren't included here. To analyze results that arrive after close, query the silver OperatorResult cube, which records every result regardless of when it lands.

Updating the summary row with results that arrive after close is planned.

ConversationSummary measures

conversationsummary-measures page anchor

The ConversationSummary cube includes the following measures:

NameTypeDescription
ConversationSummary.CountnumberThe count of unique conversations.
ConversationSummary.ParticipantsSumnumberThe total number of participants across the selected conversations. A participant who appears in several conversations is counted once per conversation, so this isn't a count of distinct participants.
ConversationSummary.ParticipantsAvgnumberThe average number of participants per conversation.
ConversationSummary.ParticipantsMinnumberThe smallest number of participants in a single conversation.
ConversationSummary.ParticipantsMaxnumberThe largest number of participants in a single conversation.
ConversationSummary.<Name><Aggregation>numberEach custom measure you register appears here under the name you chose, followed by an aggregation: Sum, Avg, Min, or Max. The aggregation runs across conversations, using one value per conversation. Conversations where the source operator didn't run return null. You can register up to three custom measures.

For example, a custom measure registered as LeadScore is queryable as ConversationSummary.LeadScoreSum, ConversationSummary.LeadScoreAvg, ConversationSummary.LeadScoreMin, and ConversationSummary.LeadScoreMax. See Define and use custom fields.

ConversationSummary dimensions

conversationsummary-dimensions page anchor

The ConversationSummary cube includes the following dimensions:

NameTypeDescription
ConversationSummary.ConversationIdstringThe unique identifier for the conversation.
ConversationSummary.ConversationNamestringThe name of the conversation.
ConversationSummary.ConversationStatusstringThe current status of the conversation.
ConversationSummary.ChannelsstringThe communication channels used in the conversation, as a comma-separated list. For example, voice,sms.
ConversationSummary.HasHumanAgentbooleanWhether at least one human agent took part in the conversation.
ConversationSummary.HasAIAgentbooleanWhether at least one AI agent took part in the conversation.
ConversationSummary.CustomerProfileIdstringThe profile identifier for the customer participant.
ConversationSummary.SentimentstringThe latest sentiment operator result for the conversation. Populated only when the Twilio-authored Sentiment operator ran on the conversation, and null otherwise.
ConversationSummary.IntelligenceConfigurationIdsstringThe intelligence configurations associated with the conversation.
ConversationSummary.CreatedDatetimeThe date and time when the conversation was created. Use .hour, .day, .week, or .month to group by period.
ConversationSummary.ClosedDatetimeThe date and time when the conversation was closed. Use .hour, .day, .week, or .month to group by period.
(information)

Participant measures don't count distinct participants

Participant IDs aren't available on this cube, so ParticipantsSum counts participant appearances rather than distinct people. To count distinct participants, query the Conversation cube. ParticipantsAvg is an average, so you can't add the averages of two groups together to get the average of both. Query the combined range directly instead.

Filter and group by channel

filter-and-group-by-channel page anchor

ConversationSummary.Channels holds every channel the conversation used. A conversation that started over SMS and moved to voice has the value sms,voice.

Choose a filter operator based on whether you want conversations that included a channel or conversations that used an exact combination:

  • Filter with IN to select conversations that used any of the listed channels, alone or alongside others. A filter for sms matches both a conversation that used SMS alone and one with the value sms,voice.
  • Filter with EQ to select an exact combination, such as voice for conversations that used voice alone, or sms,voice for that exact pairing.

The following filter selects every conversation that included SMS:

1
{
2
"expressions": [
3
{
4
"op": "IN",
5
"field": "ConversationSummary.Channels",
6
"values": ["sms"]
7
}
8
]
9
}

To see the distribution of channel combinations across your conversations, including which combinations are most common, group by ConversationSummary.Channels.


The Conversation cube contains metadata about conversations captured by Conversation Orchestrator, including details about each participant.

Both this cube and ConversationSummary expose a count of unique conversations, so either one answers "how many conversations?" The difference is what else you can ask alongside it. This cube carries participant attributes, so grouping by ParticipantType or ParticipantId returns a row per participant while the count itself stays distinct. Use this cube when participants are part of the question, and use ConversationSummary when they are not.

The Conversation cube includes the following measures:

NameTypeDescription
Conversation.CountnumberThe count of unique conversations.

The Conversation cube includes the following dimensions:

NameTypeDescription
Conversation.ConversationIdstringThe unique identifier for the conversation.
Conversation.ConversationNamestringThe name of the conversation.
Conversation.ConversationStatusstringThe current status of the conversation.
Conversation.IntelligenceConfigurationIdsstringThe intelligence configurations associated with the conversation.
Conversation.ParticipantIdstringThe unique identifier for the participant.
Conversation.ParticipantTypestringThe type of participant (for example, agent or customer).
Conversation.ParticipantProfileIdstringThe profile identifier for the participant.
Conversation.CreatedDate.hourtimeThe date and time when the conversation was created, grouped by hour. Use .day, .week, or .month for other granularities.

The OperatorResult cube contains results from intelligence operators run on conversations. Use this cube to count and group operator results by operator name, label, channel, or configuration.

The following operators produce results in the OperatorResult cube:

The OperatorResult cube includes the following measures:

NameTypeDescription
OperatorResult.CountnumberThe count of unique operator results.
OperatorResult.<Name><Aggregation>numberEach custom measure you register also appears here, at operator result grain rather than conversation grain.

A custom measure is available on both cubes, with the same Sum, Avg, Min, and Max aggregations. Query it on ConversationSummary, such as ConversationSummary.LeadScoreAvg, to analyze one value per conversation, or on OperatorResult, such as OperatorResult.LeadScoreAvg, to work with the individual results behind it. See Define and use custom fields.

OperatorResult dimensions

operatorresult-dimensions page anchor

The OperatorResult cube includes the following dimensions:

NameTypeDescription
OperatorResult.ConversationIdstringThe unique identifier for the conversation.
OperatorResult.IntelligenceConfigurationIdstringThe unique identifier for the intelligence configuration.
OperatorResult.IntelligenceConfigurationNamestringThe display name of the intelligence configuration.
OperatorResult.KnowledgeBaseIdstringThe Knowledge Base ID used during operator rule execution.
OperatorResult.MemoryStoreIdstringThe unique identifier for the memory store.
OperatorResult.OperatorIdstringThe unique identifier for the operator.
OperatorResult.OperatorNamestringThe name of the operator (for example, Sentiment Analysis).
OperatorResult.OperatorLabelstringThe label associated with the operator result (for example, positive, negative).
OperatorResult.ExecutedChannelsstringThe communication channel for the conversation (for example, voice, chat, sms, whatsapp).
OperatorResult.CreatedDate.hourtimeThe date and time when the operator result was created, grouped by hour. Use .day, .week, or .month for other granularities.

Time dimensions group data by time periods. Use dimension names with granularity suffixes.

ConversationSummary cube:

  • ConversationSummary.CreatedDate.hour: group by hour
  • ConversationSummary.CreatedDate.day: group by day
  • ConversationSummary.CreatedDate.week: group by week
  • ConversationSummary.CreatedDate.month: group by month

The same suffixes apply to ConversationSummary.ClosedDate, which is available on this cube only.

Conversation cube:

  • Conversation.CreatedDate.hour: group by hour
  • Conversation.CreatedDate.day: group by day
  • Conversation.CreatedDate.week: group by week
  • Conversation.CreatedDate.month: group by month

OperatorResult cube:

  • OperatorResult.CreatedDate.hour: group by hour
  • OperatorResult.CreatedDate.day: group by day
  • OperatorResult.CreatedDate.week: group by week
  • OperatorResult.CreatedDate.month: group by month

See Query syntax for examples.


Use the Metadata API to retrieve the available cubes, measures, and dimensions:

Retrieve available cubes, measures, and dimensionsLink to code sample: Retrieve available cubes, measures, and dimensions
1
// Download the helper library from https://www.twilio.com/docs/node/install
2
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";
3
4
// Find your Account SID at twilio.com/console
5
// Provision API Keys at twilio.com/console/runtime/api-keys
6
// and set the environment variables. See http://twil.io/secure
7
// For local testing, you can use your Account SID and Auth token
8
const accountSid = process.env.TWILIO_ACCOUNT_SID;
9
const apiKey = process.env.TWILIO_API_KEY;
10
const apiSecret = process.env.TWILIO_API_SECRET;
11
const client = twilio(apiKey, apiSecret, { accountSid: accountSid });
12
13
async function fetchMetadata() {
14
const metadata = await client.insights.v3.metadata.fetch();
15
16
console.log(metadata.domain);
17
}
18
19
fetchMetadata();

The metadata response provides the authoritative list of available data, including descriptions and types.


Explore the following resources to learn more: