02 Get your data in /Integrations
Google Dialogflow CX
Send agent conversations from Google Dialogflow CX to Dimension Labs with the universal API.
- GD Google Dialogflow CXTickets, chats, calls, reviews
- ⟳ Your jobPull new · map fields · every 15 min
- { } Universal APIPOST /track · /trackhistorical
- Dimension LabsRead in full · enriched daily
This brings in your Dialogflow CX (Conversational Agents) conversations, turn by turn: what each end user said or typed and what the agent answered. Each Dialogflow conversation becomes one conversation. You run it on your side: a small script pulls from the Dialogflow CX Conversations API and posts each message to the universal API.
The Conversations API returns each turn’s user text and agent text as plain strings, which keeps the code short. If you already export conversation history to BigQuery, you can use that table instead: see BigQuery export.
What you need
Section titled “What you need”- Conversation history turned on for the agent. Dialogflow only stores conversations from the time it is on.
- A Google Cloud service account with the IAM permissions
dialogflow.conversations.listanddialogflow.conversations.geton the agent’s project. A custom role with just those two is enough. - Your project id, the agent’s location (for example
globalorus-central1) and the agent id. - A Dimension Labs API key for a new Universal API source. See Your API key.
1. Get API access in Dialogflow CX
Section titled “1. Get API access in Dialogflow CX”- Turn on conversation history: open the Conversational Agents console, choose your project and agent, and click the settings icon in the top right corner. Under Logging settings, turn on Enable conversation history, then click Save (agent settings).
- In the Google Cloud console, create a service account for the job, and grant it a role with
dialogflow.conversations.listanddialogflow.conversations.get(access control). - On the Service accounts page, click the account’s email address, open the Keys tab, and choose Add key > Create new key. Select JSON and click Create (create a service account key). Store the file in a secrets manager. The code finds it through the
GOOGLE_APPLICATION_CREDENTIALSenvironment variable. On Google Cloud, an attached service account works without a key file (Application Default Credentials).
Requests need the OAuth scope https://www.googleapis.com/auth/dialogflow (or cloud-platform). The google-auth-library package gets the token for you: npm install google-auth-library.
Use the right host. For the global location the host is dialogflow.googleapis.com; for any other region it is <region>-dialogflow.googleapis.com, and the region must also appear in the path (regionalization).
2. Pull new conversations
Section titled “2. Pull new conversations”List conversations created since a point in time:
curl -H "Authorization: Bearer $(gcloud auth print-access-token)" \ "https://dialogflow.googleapis.com/v3beta1/projects/YOUR_PROJECT/locations/global/agents/YOUR_AGENT_ID/conversations?pageSize=1000&filter=createTime%20%3E%20%222026-10-01T00:00:00Z%22"filtertakescreateTime > "<RFC 3339 time>". Results come newest first.pageSizedefaults to 100 and goes up to 1,000. PassnextPageTokenaspageTokenuntil it is empty.- The list leaves
interactionsempty. CallGET https://<host>/v3beta1/<conversation name>for each conversation to get its turns. - Each interaction has
requestUtterances(the user’s text, or the transcript of their audio),responseUtterances(the agent’s text or the transcript of its audio, joined into one string) andcreateTime. - Dialogflow logs at most 500 turns per conversation. How long it keeps conversations is set by the
retention_window_dayssecurity setting. - The Conversations API is on the
v3beta1version of the API.
A Dialogflow session stays open for 30 minutes after the last request by default, so a conversation can keep growing after it first appears. The code re-reads the conversations created in the last two hours on every run.
3. Map the fields
Section titled “3. Map the fields”| Dimension Labs | Dialogflow CX | Notes |
|---|---|---|
text | interaction requestUtterances (user), responseUtterances (agent) | One interaction gives up to two messages. Skip empty ones, such as an event-only request. |
userId | conversation id | Dialogflow doesn’t give an end-user id here, so use the sessionId on both sides. |
incoming | which field the text came from | true for requestUtterances, false for responseUtterances. |
sessionId | the last segment of the conversation name | Prefix it, for example dialogflow-<conversation id>. |
conversationId | the last segment of the conversation name | Same value as sessionId. |
dimensionlabs_timestamp | interaction createTime | Convert with toMillis. The agent’s reply gets the same time plus 1,000 ms. |
platformJson | conversation languageCode, type, environment.displayName, metrics.hasLiveAgentHandoff; interaction response.queryResult.match.intent.displayName, response.queryResult.currentPage.displayName | type is TEXT, AUDIO or UNDETERMINED. |
Personal data. End users sometimes say or type names, emails or account numbers: redact them before you send. See PII redaction.
4. Send it
Section titled “4. Send it”// dialogflow-cx.mjs. Environment: GOOGLE_APPLICATION_CREDENTIALS (service account key file), DIALOGFLOW_PROJECT, DIALOGFLOW_LOCATION (for example global), DIALOGFLOW_AGENT_ID, DL_API_KEY.import { GoogleAuth } from 'google-auth-library';import { sendToDimensionLabs, toMillis } from './dimensionlabs.mjs';
const HOUR = 60 * 60 * 1000;const LOOKBACK = 2 * HOUR; // re-read recent conversations: they keep growing until the session endsconst sleep = (ms) => new Promise((r) => setTimeout(r, ms));const auth = new GoogleAuth({ scopes: 'https://www.googleapis.com/auth/dialogflow' });const LOC = process.env.DIALOGFLOW_LOCATION;const HOST = `https://${LOC === 'global' ? '' : `${LOC}-`}dialogflow.googleapis.com/v3beta1`;const AGENT = `projects/${process.env.DIALOGFLOW_PROJECT}/locations/${LOC}/agents/${process.env.DIALOGFLOW_AGENT_ID}`;
// Retries Dialogflow's rate limits (429) and server errors (5xx), honoring Retry-After.async function get(url) { for (let attempt = 0; ; attempt++) { const res = await fetch(url, { headers: { Authorization: `Bearer ${await auth.getAccessToken()}` } }); if (res.ok) return res.json(); if ((res.status !== 429 && res.status < 500) || attempt === 5) throw new Error(`Dialogflow returned ${res.status}: ${await res.text()}`); await sleep((Number(res.headers.get('retry-after')) || 2 ** attempt) * 1000); }}
// Sends every turn of the conversations created since `since` (Unix ms), minus the lookback. Returns the new `since`.export async function syncDialogflowCx({ since, historical = false }) { const started = Date.now(); const filter = `createTime > "${new Date(since - LOOKBACK).toISOString()}"`; const names = []; let pageToken = ''; do { const page = await get(`${HOST}/${AGENT}/conversations?pageSize=1000&filter=${encodeURIComponent(filter)}${pageToken ? `&pageToken=${encodeURIComponent(pageToken)}` : ''}`); names.push(...(page.conversations ?? []).map((c) => c.name)); pageToken = page.nextPageToken; } while (pageToken);
for (const name of names.reverse()) { // oldest first const c = await get(`${HOST}/${name}`); const id = `dialogflow-${name.split('/').pop()}`.replace(/:/g, '-'); const turns = (c.interactions ?? []).slice().sort((a, b) => toMillis(a.createTime) - toMillis(b.createTime)); for (const i of turns) { const ts = toMillis(i.createTime); const result = i.response?.queryResult; const platformJson = { language: c.languageCode, type: c.type, environment: c.environment?.displayName, live_agent_handoff: c.metrics?.hasLiveAgentHandoff, intent: result?.match?.intent?.displayName, page: result?.currentPage?.displayName, }; for (const [text, incoming, at] of [[i.requestUtterances, true, ts], [i.responseUtterances, false, ts + 1000]]) { if (!text?.trim()) continue; await sendToDimensionLabs({ text, userId: id, incoming, sessionId: id, conversationId: id, dimensionlabs_timestamp: at, platformJson, }, { historical: historical || at < Date.now() - HOUR }); } } } return started;}5. Run it
Section titled “5. Run it”Save the code as dialogflow-cx.mjs in a project set up as in Set up your project, and run it with the scheduled sync runner: import { syncDialogflowCx as sync } from './dialogflow-cx.mjs';.
- History first:
node run.mjs 2026-01-01sends every conversation created since that date to/trackhistorical, as far back as your retention setting allows. Then start a backfill from the Backfill tab. - Then every 15 minutes: the scheduled job sends new messages to
/track, and they are enriched automatically every day. A message that is more than an hour old when the job sees it goes to/trackhistorical, and needs a backfill. - Re-runs are safe: duplicates are removed automatically. Each run re-sends the turns of the last two hours of conversations, so late turns are caught; the repeats are dropped. If your sessions run longer than that (
sessionTtlcan be up to a day), raiseLOOKBACK.
Each conversation costs one get call, so a long history takes a while; the code waits whenever Google asks it to. In the console, Conversation history > Export all conversations downloads at most 50 conversations as CSV, so for a file route use BigQuery.
BigQuery export instead
Section titled “BigQuery export instead”Dialogflow can write all live conversation history to a BigQuery table, one row per turn, with conversation_name, turn_position, request_time, and the request and response as JSON (export to BigQuery). You create the dataset and table yourself, then turn on BigQuery export in the agent settings. It needs conversation history turned on too, and only covers conversations from the time it is set up.
If you use it, read new rows by request_time and follow the BigQuery guide, with the same direction rules: the user’s input from request is incoming, the agent’s reply from response is outgoing, and conversation_name is the session.
Dialogflow CX reference
Section titled “Dialogflow CX reference”- Conversation history
- Agent settings
- Access control
- Regionalization
- Create and delete service account keys
- Application Default Credentials
- conversations.list
- Conversation resource
- Conversation history export to BigQuery
Checked against Google’s documentation on 2026-10-26.