Conversation data format
The universal format for conversations, reviews, surveys and tickets, column by column, with what breaks each one.
One row is one message. A conversation is one chat, ticket, call, review or survey response, and its rows share a sessionId. A review is a one-message conversation; a chat or ticket is several rows.
sessionId Required. Groups the rows of one conversation. Enrichment reads a whole session at once. No colons.
userId Required. Who sent the message. Must not be empty: if you have no user id, copy the sessionId into it. For a bot conversation, use the end user’s id on their messages and the bot’s.
incoming Required. true when the customer wrote it, false for your agent, bot or company. Lowercase only.
text Required. The words to enrich. Must not be empty on any row.
dimensionlabs_timestamp Required. Unix time in milliseconds: 13 digits. A 10-digit number is seconds, and reads as a date in 1970.
channel Optional. Any extra column is kept with the conversation as metadata, in structured_metadata, where the agent can filter and join on it.
Columns
Section titled “Columns”| Column | Required | Type | Example | Notes |
|---|---|---|---|---|
text | Yes | text | My order never arrived | The words to enrich. Must not be empty on any row. |
userId | Yes | text | cust-4471920 | Who sent the message. Must not be empty: if you don’t have one, copy the sessionId into it (the file checker does this for you). For a bot conversation, use the end user’s id on both their messages and the bot’s (the userId rule). Never an email address, phone number or name: use your tool’s internal id. |
incoming | Yes | true or false, lowercase | true | true when the customer or end user wrote it; false for your agent, bot or company. |
dimensionlabs_timestamp | Yes | number, Unix time in milliseconds (13 digits) | 1703240320000 | When the message was sent. |
sessionId | Yes | text | 1434868331 | Groups the rows of one conversation. Enrichment reads all the rows with the same sessionId at once. No colons, and no personal data. |
conversationId | Recommended | text | conv-88213407 | Keeps a multi-participant thread together, for example when a human agent joins a bot chat. No colons. |
intent | Only for an intent-based chatbot | text in a CSV; an object in JSONL | TRACK_ORDER | The intent your bot matched. Leave it out if your bot doesn’t use intents. |
| any other column | Optional | anything | store_id, rating, plan | Kept with the conversation as metadata. You map it during upload, and it appears in the structured_metadata table, where the agent can filter and join on it. Leave out emails, phone numbers, names and addresses (PII redaction). |
Column names are case-sensitive: userId and sessionId, not userid or SESSIONID. The upload screen’s column mapping lets you point your own column names at these fields, and the converter renames them for you. Uploads accept CSV, TSV and JSONL files of any size: Dimension Labs splits a large file for you.
Rules that break uploads
Section titled “Rules that break uploads”These are the problems behind most failed uploads. The file checker finds every one.
- Empty text. Any row with an empty
textcell. Remove the row. - Booleans in capitals.
TRUEandFALSE, or a mix of cases. Use lowercasetrueandfalse. - Timestamps in seconds. A 10-digit number like
1703240320is read as a date in 1970. Multiply by 1,000. - Excel’s scientific notation. Excel rewrites long numbers as
1.70324E+12when it saves a CSV, and the digits it drops are gone. Re-export from the source system, or give the checker the original.xlsx. - Newlines inside a text field. A line break inside a review or message can split one record into several. Replace line breaks with spaces.
- Every field in quotes. Some tools write every cell wrapped in quotes, including numbers and empty cells. Write the file with quotes only where needed.
- Colons in ids.
sessionIdandconversationIdcan’t contain:. Use-or_. - A byte order mark, or Windows line endings. Save as UTF-8 without a BOM, with Unix (LF) line endings.
- A header with a backslash or a trailing space.
Data Sourcewith a trailing space becomes a different column fromData Source. - No header row. The upload needs column names in the first row. Add one in a text editor.
Small rules that keep results clean
Section titled “Small rules that keep results clean”- Keep messages in the same conversation at least one second (1,000 ms) apart.
- Don’t use placeholder text such as
[No review text]for an empty review. Drop the row instead. - Pick one encoding for booleans and dates in your extra columns, and stick to it. Everything you upload is stored as text, so
Yes,yesand1become three different values.
Example
Section titled “Example”sessionId,userId,incoming,text,dimensionlabs_timestamp,channelconv-1001,cust-17,true,My order never arrived,1703240320000,chatconv-1001,cust-17,false,Sorry about that. Can you share the order number?,1703240325000,chatconv-1001,cust-17,true,DM34137KMX,1703240331000,chatreview-77,rev-77,true,Great staff but the wait was 40 minutes,1703278090000,google_reviewsThe agent’s reply in conv-1001 carries the customer’s id, cust-17. Download it as a template: conversation template. Then check your own file with the file checker.
A JSONL example
Section titled “A JSONL example”A JSONL file has one JSON object per line, with no commas between lines and no surrounding brackets. A line has the same shape as a universal API message: intent is an object, and extra fields go in a nested platformJson object. This example file holds two bot conversations: a customer asking how to track a delivery, and a customer whose order number isn’t found and who asks for a person.
{"text":"hey","userId":"7675836189527716","incoming":true,"sessionId":"1434868331","conversationId":"1434868331","dimensionlabs_timestamp":1703240310000,"intent":{"name":"HELLO","confidence":0.96},"platformJson":{"customerTier":"silver","locale":"en-CA"}}{"text":"Hi! How can I help you?","userId":"7675836189527716","incoming":false,"sessionId":"1434868331","conversationId":"1434868331","dimensionlabs_timestamp":1703240315000,"intent":{"name":"HELLO_RESPONSE","confidence":1},"platformJson":{"customerTier":"silver","locale":"en-CA"}}{"text":"I want to know where to track my deliveries","userId":"7675836189527716","incoming":true,"sessionId":"1434868331","conversationId":"1434868331","dimensionlabs_timestamp":1703240320000,"intent":{"name":"TRACK_ORDER","confidence":0.91},"platformJson":{"customerTier":"silver","locale":"en-CA"}}{"text":"DM34137KMX","userId":"1165873486259425","incoming":true,"sessionId":"9950934871","conversationId":"9950934871","dimensionlabs_timestamp":1703278090000,"intent":{"name":"ORDER_NUMBER","confidence":0.88},"platformJson":{"customerTier":"bronze","locale":"en-CA"}}{"text":"Sorry, I can't find any existing order matching that number.","userId":"1165873486259425","incoming":false,"sessionId":"9950934871","conversationId":"9950934871","dimensionlabs_timestamp":1703278095000,"intent":{"name":"ORDER_NOT_FOUND","confidence":1},"platformJson":{"customerTier":"bronze","locale":"en-CA"}}{"text":"Operator","userId":"1165873486259425","incoming":true,"sessionId":"9950934871","conversationId":"9950934871","dimensionlabs_timestamp":1703278100000,"intent":{"name":"REQUEST_HUMAN","confidence":0.97},"platformJson":{"customerTier":"bronze","locale":"en-CA"}}{"text":"Okay, I'm getting someone from my team to help you.","userId":"1165873486259425","incoming":false,"sessionId":"9950934871","conversationId":"9950934871","dimensionlabs_timestamp":1703278105000,"intent":{"name":"REQUEST_HUMAN_RESPONSE","confidence":1},"platformJson":{"customerTier":"bronze","locale":"en-CA"}}Things to notice:
userIdis the customer’s id on the bot’s messages too.incomingis a real boolean,trueorfalse, without quotes.- Timestamps rise within each conversation and are at least a second apart.
customerTierandlocaleare extra fields inplatformJson, kept as metadata the agent can filter on.- The timestamp field is
dimensionlabs_timestamp. Older examples used other names, such asdimension_timestamp, which don’t work.