Aggregate conversation data with Conversation Insights
This guide walks through querying the Conversation Insights Metadata and Query resources to count conversations, add dimensions, and filter results. If you haven't worked with cubes, measures, and dimensions before, start with Core concepts.
Complete the prerequisites:
- Create a Twilio account.
- Store your Twilio credentials in environment variables.
- Set up Conversation Orchestrator with at least one conversation.
Info
Insights data becomes available approximately 15 minutes after conversation events.
Before querying, use the Metadata API to see what measures and dimensions are available.
Send a GET request to the Metadata resource:
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function fetchMetadata() {14const metadata = await client.insights.v3.metadata.fetch();1516console.log(metadata.domain);17}1819fetchMetadata();
The response includes a list of cubes, each with its available measures and dimensions. The following example only shows one measure and one dimension per cube. Make a request to the Metadata resource to retrieve the full list.
1{2"domain": "Conversations",3"cubes": [4{5"name": "ConversationSummary",6"description": "One wide row per conversation with rolled-up metadata, sentiment, and custom measures",7"measures": [8{9"name": "ConversationSummary.Count",10"type": "number",11"aggregation": "countDistinct",12"description": "The count of unique conversations"13}14],15"dimensions": [16{17"name": "ConversationSummary.HasAIAgent",18"type": "boolean",19"description": "Whether the conversation involved at least one AI agent"20}21]22},23{24"name": "Conversation",25"description": "Contains aggregated conversation event data with participant details",26"measures": [27{28"name": "Conversation.Count",29"type": "number",30"aggregation": "countDistinct",31"description": "The count of unique conversations"32}33],34"dimensions": [35{36"name": "Conversation.ConversationId",37"type": "string",38"description": "The unique identifier for the conversation"39}40]41},42{43"name": "OperatorResult",44"description": "Contains results of various intelligence operators run on conversations",45"measures": [46{47"name": "OperatorResult.Count",48"type": "number",49"aggregation": "countDistinct",50"description": "The count of unique operator results"51}52],53"dimensions": [54{55"name": "OperatorResult.OperatorName",56"type": "string",57"description": "Name of the operator. Eg. Sentiment Analysis, Agent Introduction"58}59]60}61]62}
For an explanation of each cube and the full list of measures and dimensions, see Core concepts.
Find out whether your AI agents and your human agents are producing different customer sentiment. This is the kind of question the ConversationSummary cube exists to answer: because it holds one row per conversation, a Conversation Intelligence operator result and orchestration data sit side by side and you can group by both at once.
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createQueryResults() {14const query = await client.insights.v3.query.create({15domain: "Conversations",16query: {17measures: ["ConversationSummary.Count"],18dimensions: [19"ConversationSummary.HasAIAgent",20"ConversationSummary.Sentiment",21],22filters: [23{24expressions: [25{26op: "GT",27field: "ConversationSummary.CreatedDate",28values: ["2026-04-02"],29},30],31},32],33},34});3536console.log(query.domain);37}3839createQueryResults();
The response returns one row per combination, so you can compare sentiment in conversations with and without an AI agent directly:
1{2"domain": "Conversations",3"items": [4{5"ConversationSummary.HasAIAgent": true,6"ConversationSummary.Sentiment": "positive",7"ConversationSummary.Count": "42"8},9{10"ConversationSummary.HasAIAgent": false,11"ConversationSummary.Sentiment": "positive",12"ConversationSummary.Count": "17"13}14],15"meta": {16"key": "items",17"nextToken": null,18"pageSize": 50,19"previousToken": null20}21}
On a silver cube the same question takes two queries and a join in your own application, because participant data and operator results live on separate rows. Conversation Insights writes the summary row when a conversation reaches the CLOSED state, so this cube covers completed conversations only.
To get the total conversation count, make a POST request to the Query endpoint.
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createQueryResults() {14const query = await client.insights.v3.query.create({15domain: "Conversations",16query: {17measures: ["Conversation.Count"],18filters: [19{20expressions: [21{22op: "GT",23field: "Conversation.CreatedDate",24values: ["2026-04-02"],25},26],27},28],29},30});3132console.log(query.domain);33}3435createQueryResults();
The response includes your aggregated data:
1{2"domain": "Conversations",3"items": [4{5"Conversation.Count": "2"6}7],8"meta": {9"key": "items",10"nextToken": null,11"pageSize": 50,12"previousToken": null13}14}
Query conversations grouped by dimensions. This example counts conversations by status:
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createQueryResults() {14const query = await client.insights.v3.query.create({15domain: "Conversations",16query: {17measures: ["Conversation.Count"],18dimensions: ["Conversation.ConversationStatus"],19filters: [20{21expressions: [22{23op: "GT",24field: "Conversation.CreatedDate",25values: ["2026-04-02"],26},27],28},29],30},31});3233console.log(query.domain);34}3536createQueryResults();
The response groups results by status:
1{2"domain": "Conversations",3"items": [4{5"Conversation.ConversationStatus": "ACTIVE",6"Conversation.Count": "15"7}8],9"meta": {10"key": "items",11"nextToken": null,12"pageSize": 50,13"previousToken": null14}15}
If you have registered a custom measure, it behaves like any built-in measure, with a Sum, Avg, Min, and Max aggregation for each. This example uses LeadScoreAvg to average a LeadScore measure by channel, so you can see which channels produce the highest-intent conversations:
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createQueryResults() {14const query = await client.insights.v3.query.create({15domain: "Conversations",16query: {17measures: ["ConversationSummary.LeadScoreAvg"],18dimensions: ["ConversationSummary.Channels"],19filters: [20{21expressions: [22{23op: "GT",24field: "ConversationSummary.CreatedDate",25values: ["2026-04-02"],26},27],28},29],30},31});3233console.log(query.domain);34}3536createQueryResults();
Replace LeadScore with the name you chose when registering the measure. Conversations where the source operator didn't run return null, so they form their own group rather than counting toward another channel's average.
Query operator results to analyze intelligence operators run on your conversations. This example counts operator results grouped by operator name:
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createQueryResults() {14const query = await client.insights.v3.query.create({15domain: "Conversations",16query: {17measures: ["OperatorResult.Count"],18dimensions: ["OperatorResult.OperatorName"],19filters: [20{21expressions: [22{23op: "GT",24field: "OperatorResult.CreatedDate",25values: ["2026-04-02"],26},27],28},29],30},31});3233console.log(query.domain);34}3536createQueryResults();
The response groups results by operator name:
1{2"domain": "Conversations",3"items": [4{5"OperatorResult.Count": "168",6"OperatorResult.OperatorName": "Sentiment"7}8],9"meta": {10"key": "items",11"nextToken": null,12"pageSize": 1,13"previousToken": null14}15}
Query operator results that used a specific Knowledge Base. This example retrieves conversations and operator names filtered by Knowledge Base ID:
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createQueryResults() {14const query = await client.insights.v3.query.create({15domain: "Conversations",16query: {17dimensions: [18"OperatorResult.ConversationId",19"OperatorResult.OperatorName",20"OperatorResult.KnowledgeBaseId",21],22filters: [23{24op: "AND",25expressions: [26{27op: "GT",28field: "OperatorResult.CreatedDate",29values: ["2026-04-10"],30},31{32op: "EQ",33field: "OperatorResult.KnowledgeBaseId",34values: ["know_knowledgebase_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"],35},36],37},38],39},40});4142console.log(query.domain);43}4445createQueryResults();
The response returns operator results filtered by the specified Knowledge Base:
1{2"domain": "Conversations",3"items": [4{5"OperatorResult.ConversationId": "conv_conversation_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",6"OperatorResult.OperatorName": "Sentiment",7"OperatorResult.KnowledgeBaseId": "know_knowledgebase_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"8}9],10"meta": {11"key": "items",12"nextToken": null,13"pageSize": 1,14"previousToken": null15}16}
To run queries asynchronously, use the QueryJobs resource instead of the Query resource. If you don't need results immediately, such as a query that takes longer than a synchronous request allows, you can submit it and check back for results later.
1curl -X POST "https://insights.twilio.com/v3/InsightsDomains/Conversations/QueryJobs" \2-u $TWILIO_API_KEY:$TWILIO_API_SECRET \3-H "Content-Type: application/json" \4-d '{5"domain": "Conversations",6"query": {7"dimensions": ["OperatorResult.ConversationId", "OperatorResult.OperatorName", "OperatorResult.OperatorLabel"],8"filters": [9{10"expressions": [11{12"op": "GT",13"field": "OperatorResult.CreatedDate",14"values": ["2026-01-01"]15}16]17}18]19}20}'
Twilio returns an operationId and a statusUrl. See Asynchronous queries for how to poll for completion and retrieve results.
To learn more about Conversation Insights, see the following resources:
- Core concepts: Understand cubes, measures, and dimensions.
- Query syntax: Learn how to construct complex queries with filters, ordering, and pagination.