# Reviews, surveys and tickets

> How to shape non-chat sources into the conversation format so they enrich correctly.

The conversation format was built for chats, but it fits any customer text. The rule: **anything written by the customer or someone outside your company is `incoming: true`. Anything your company wrote is `incoming: false`.**

## Reviews

One review is one row, and one conversation.

| Column | Value |
|---|---|
| `sessionId` | The review id |
| `userId` | The reviewer id, or the review id if there isn't one |
| `incoming` | `true` |
| `text` | The review body |
| extra columns | Star rating, location, source, review date |

If you also have your company's replies, add each reply as a second row with the same `sessionId` and `userId`, with `incoming: false` and the reply's own time.

Drop reviews with no text rather than filling them with placeholder text such as `[No review text]`. A placeholder looks like a real review to the model. Keep the star rating in an extra column: Dimensions are read from the text only, so the model never sees the stars.

## Surveys

Each respondent is one conversation, with the response id as `sessionId`. Each question your company asked is an outgoing message, and each answer is an incoming one.

| Row | `incoming` | `text` |
|---|---|---|
| 1 | `false` | Why did you give that score? |
| 2 | `true` | The checkout kept failing on my phone. |
| 3 | `false` | What one thing should we improve? |
| 4 | `true` | Fix the app. |

Keep the scores (NPS, CSAT, ratings) as extra columns. The [converter](/data/convert-a-file) turns a wide survey export (one row per respondent, one column per question) into this shape, and can take the question text from the row of question wording many survey tools put under the column names. Use the wording respondents saw, not column codes such as `Q3_why`. For more control, see [Reshape a wide survey](/transform/recipe-wide-survey).

:::tip
Because the model reads only the text, it can't see which question a short answer like "Fix the app" responds to unless the question is in the session too. That's why the questions go in as outgoing rows.
:::

## Tickets and email threads

One ticket is one conversation. Each message in the thread is a row, `incoming: true` for the customer and `false` for your agents. Use the ticket id as `sessionId` and `conversationId`, so the thread stays together when different agents reply. Use the customer's id as `userId`, on the agents' replies too ([the userId rule](/data/sessions-and-conversations#the-userid-rule)). Strip HTML and quoted replies first: see [Clean ticket and email text](/transform/recipe-clean-text).

## Call transcripts

One call is one conversation, with the call id as `sessionId` and one row per speaker turn. Turns need timestamps at least one second apart, in the order they were spoken.

## Several channels in one place

You can upload chat, email, reviews and surveys as separate sources, or together under the **Omni Channel** type. Either way, add a `channel` column so the agent can compare them.

## Templates

Start from a template: [reviews](/templates/reviews-template.csv), [survey answers](/templates/survey-template.csv) or [chats and tickets](/templates/conversation-template.csv).
