BLOG · INTEGRATION
How to analyze Intercom conversations for product feedback
· 8 min read
If you run support on Intercom, your customers have already told you which bugs hurt and which features they want. It’s all in the inbox, spread over thousands of chats that each get read once, answered and closed.
This guide covers what Intercom’s own reporting gives you, where it stops, and how to get conversations into a tool that turns them into counted bugs and feature requests per part of your product. There’s a working webhook at the end you can copy.
What Intercom already tells you
Intercom has good built-in reporting for running a support team: volume, response times, ratings and tags. With the Pro add-on you also get Topics Explorer, which groups conversations into topics and subtopics without manual tagging, and CX Score, an AI rating of every conversation. Pro starts at $99 a month for up to 1,000 conversations (as listed in September 2026), and it needs Fin, Intercom’s AI agent, to be live.
For product questions it has three gaps:
| You want to know | Intercom reporting | Why |
|---|---|---|
| How many customers hit the export bug | Partly. Roughly | Topics label conversations, and one chat can be about three things |
| Bugs vs feature requests per module | No. No | Topics describe subjects, not the kind of feedback |
| The same bug in chat, email and App Store reviews | No. No | It only sees Intercom conversations |
| Support workload by topic | Yes. Yes | This is what it’s built for |
If support workload is the question, stay in Intercom. If the question is what to fix and build next, you need the conversations somewhere that reads them statement by statement.
A conversation is not one piece of feedback
Here is a typical chat. Intercom would give it one topic, maybe “Bank sync”.
Live chat · Intercom
hey! quick one: does the bank sync run on weekends? my Monday balance never matches. oh and it matched a €12 payment to a €1,200 invoice, that was a bit scary 😅 otherwise loving the new dashboard
- QuestionBank feedsneutral · low
“does the bank sync run on weekends?”
- BugBank feedsnegative · medium
“my Monday balance never matches”
- BugBank feeds / Matchingnegative · high
“it matched a €12 payment to a €1,200 invoice”
- ComplimentDashboardpositive · low
“loving the new dashboard”
A wrong payment match is the most serious thing in that chat, and it’s phrased as an aside with an emoji. Topic-level reporting counts this as one bank sync conversation. Statement-level analysis counts a question, two bugs (one of them high urgency) and a compliment for a different part of the product. Our guide to categorizing feedback explains the labels.
Which messages to analyze
Intercom sends webhooks for a lot of events. For feedback analysis you want the customer’s words and nothing else.
| Webhook topic | Send it? | Why |
|---|---|---|
conversation.user.created | Yes. Yes | A customer starts a conversation |
conversation.user.replied | Yes. Yes | A customer replies |
conversation.admin.replied | No. No | Your team’s words, not the customer’s |
conversation.operator.replied | No. No | Fin and bot replies |
conversation.admin.noted | Partly. Maybe | Internal notes sometimes summarise a call. Send them under their own source if so. |
Three ways to get conversations out
There are three practical routes, and you can combine them.
| Route | Best for | Effort |
|---|---|---|
| Webhooks | Every new message, seconds after it arrives | A small function, about 40 lines |
| Zapier, Make or n8n | No-code teams. Trigger on a new conversation or reply, then an HTTP step | Half an hour of clicking |
| REST API export | Backfilling the last months so you have history on day one | A one-off script |
Start with the backfill if you can. Trends only mean something against a baseline, and three months of history gives you one on the first day.
Forwarding with a webhook
STEP 1
Customer writes
A new chat or a reply in Intercom
STEP 2
Intercom calls you
Webhook with the conversation
STEP 3
Your function forwards
Only the customer’s message
STEP 4
SignalScoop classifies
Module, type, sentiment, urgency
In the Intercom Developer Hub, create an app, open Webhooks, add your endpoint URL and subscribe to the two topics from the table above. Then deploy a receiver like this one. It checks Intercom’s signature, picks out the customer’s message and posts it to SignalScoop’s messages API. Your API key and the endpoint URL are in your SignalScoop dashboard.
// Receives Intercom's webhook and forwards each customer message.// A Next.js route handler here; any serverless function works the same.import crypto from "node:crypto"; export async function POST(req: Request) { const raw = await req.text(); // Intercom signs the body with your app's client secret (HMAC-SHA1). const signature = "sha1=" + crypto .createHmac("sha1", process.env.INTERCOM_CLIENT_SECRET!) .update(raw).digest("hex"); if (req.headers.get("x-hub-signature") !== signature) { return new Response("bad signature", { status: 401 }); } const { topic, data } = JSON.parse(raw); const conversation = data.item; // A new conversation carries its first message in "source". // A reply is the newest conversation part. const part = topic === "conversation.user.created" ? { id: conversation.source.id, body: conversation.source.body, created_at: conversation.created_at } : conversation.conversation_parts.conversation_parts.at(-1); await fetch(process.env.SIGNALSCOOP_URL + "/v1/messages", { method: "POST", headers: { authorization: "Bearer " + process.env.SIGNALSCOOP_API_KEY, "content-type": "application/json", }, body: JSON.stringify({ source: "intercom", external_id: part.id, thread_id: conversation.id, received_at: new Date(part.created_at * 1000).toISOString(), body: part.body.replace(/<[^>]+>/g, " ").trim(), }), }); return new Response("ok");}
A few details that matter in production:
- Answer fast. Intercom expects a quick response. The messages API answers straight away and classifies in the background, so forwarding inline is fine.
- Deduplication is built in. Intercom can deliver a webhook twice. Because you send
external_id, a repeat is recognised and not counted again. - Use a constant-time compare for the signature in production, such as
crypto.timingSafeEqual. - Mind the HTML. Older API versions return message bodies as HTML. The regex strips tags; newer versions return plain text.
Keep each conversation together
Customers repeat themselves. “Still broken.” “Any update on the export?” “This is the third time I’m asking.” Counted per message, that’s three bug reports. It’s one bug that got more urgent.
Sending the Intercom conversation id as thread_id fixes this. SignalScoop reads the conversation as a whole, counts the bug once where it was first raised, and raises its urgency as the customer gets more frustrated.
What to look at every week
Once conversations flow in, the useful views are the ones Intercom can’t give you:
- Bugs by module, week over week. A spike the week after a release points at the release.
- High and critical signals, read one by one. That’s where the wrong payment match from the chat above turns up.
- Feature requests, merged by need. See tracking feature requests from support.
- Intercom next to your other sources. Once email and reviews are in too, a bug reported in all three shows as one trend.
Before wiring anything up, paste one of your own Intercom chats below to see what comes out. Nothing you paste is stored.
Your signals land here.
Pick an example to start.
Checklist
- Use Intercom’s reports for support workload, and statement-level analysis for product decisions.
- Subscribe to
conversation.user.createdandconversation.user.repliedonly. - Verify the
X-Hub-Signatureheader before trusting a webhook. - Send
external_idfor deduplication and the conversation id asthread_id. - Backfill a few months through the REST API so trends have a baseline.
- Read the high-urgency signals every week, not just the charts.