Overheard 🎧

Turn public customer feedback into product decisions.

💡 Inspiration

When people dislike something about a product, they usually do not fill out a feedback form. They complain in a YouTube comment, a Reddit thread, or somewhere the company never checks.

There can be thousands of useful comments spread across the internet, but reading them manually is not realistic. Even after finding them, a product manager still has to work out which complaints are repeated and which came from a single popular post.

We built Overheard to do that research for them. It gathers public feedback and turns it into a small set of problems a product team can review and act on.

🔍 What it does

A user adds a product and starts a research run. Overheard searches the available sources, collects relevant public comments, then runs them through a cleaning and analysis pipeline that removes duplicate or unrelated content and groups the rest by the product problem they describe.

When the run finishes, the dashboard shows the actions that seem most important. Each one links directly to the comments behind it, so a manager can read the recommendation first, then check the evidence before deciding whether it makes sense. There are also pages for browsing every detected pain point and the strongest individual comments.

ElevenLabs is our voice interface, built on ElevenLabs, so a user can ask a plain-language question and get an answer from the same data shown in the dashboard.

🏗️ How it works

Overheard architecture diagram

The diagram follows a single research run from left to right, in five steps.

1️⃣ Plan. The product name goes to the language model first, not to a scraper. The Collection Planner decides which sources are worth searching and writes per-platform queries.

2️⃣ Collect. FastAPI runs the connectors in parallel. Each talks to a different platform with its own auth, pagination and rate limits, returning raw documents in that platform's shape.

3️⃣ Clean and classify. Everything is converted into one common feedback record. Duplicates are removed twice, once by identifier and once by comparing the text itself. The survivors go back to the model in batches, which decides whether each is about the product, how the author feels, whether it is a complaint, and which issue it belongs to.

4️⃣ Index. Results are written to Elasticsearch with the original comment text kept alongside the analysis, which is what makes every conclusion traceable back to a real quote.

5️⃣ Serve. The dashboard asks Elasticsearch for aggregated pain points and their evidence. Vox uses the same backend, so a spoken answer and an on-screen answer always agree.

The model appears twice, at the start to decide what to look for and after collection to interpret what came back. Everything between is ordinary retrieval, deduplication and aggregation.

🧗 Challenges we ran into

Finding usable data was the biggest challenge. There is no standard way to collect public feedback. YouTube has an API, but other platforms have different access rules, and some pages return CAPTCHA or login walls when accessed automatically. We made sure one failed source never stops a run: the collection result reports what succeeded and what was skipped, which prevented an empty source from looking like an empty market.

The data formats were also inconsistent. A YouTube like does not mean the same thing as a forum reply, usernames and timestamps go missing, and some comments are sarcastic or too short to classify. The normalized feedback record let the pipeline process them together without throwing away source-specific details.

Sentiment was its own problem, since a customer can like a product while disliking one feature. A simple positive or negative label misses that, so our current version combines sentiment with complaint detection and issue categories.

🏆 Accomplishments that we're proud of

The dashboard does not hide its conclusions behind an AI summary. If Overheard recommends addressing an issue, the user can immediately read the comments that led to it.

The collection system also lets new sources be added without changing the rest of the app. Once a connector produces the common feedback format, the same cleaning process and Elasticsearch queries work for it.

The part we are happiest with is the complete flow: add a product, collect real feedback, see the main problems, and open the source comments without leaving the app.

📚 What we learned

Collecting more comments does not always improve the result. A large batch may all come from one thread, while a smaller set spread across independent sources can be more useful. Keeping the source attached to every record matters too, because different platforms have different audiences and one combined number can mislead. Most of all, generated insights need to be easy to verify, which is why we made the evidence part of the main experience rather than a hidden input.

🚀 What's next for Overheard

We want the analysis to understand sentiment about individual parts of a product, so it can handle comments that praise the product but criticize pricing or performance, along with better detection for sarcasm, severity and version-specific issues.

The next major feature is integration with Linear, Jira, and GitHub, so a team can send a pain point into its existing workflow with the original comments, source links and product area already attached. After a team approves an issue, a coding agent could investigate the relevant code and prepare a pull request for the responsible engineers to review. The goal is to shorten the time between hearing a customer problem and getting a well-informed fix in front of the right team.

🛠️ Built with

OpenAI (gpt-5.6-sol)

We use GPT exactly twice per run: once to decide where to look, and once to read what we found. Everything in between is ordinary code.

First, it plans the search. You give Overheard a product name and nothing else. Before anything is downloaded, GPT works out which websites are actually worth searching and writes the search terms for each one. It knows Steam is the right place for a video game and pointless for headphones. It also knows the sites behave differently: Hacker News needs short keyword searches, while YouTube understands full sentences. Searching Hacker News for "Notion" returns 345,000 results, but "Notion productivity tool opinions" returns 7, so getting this wrong quietly destroys the run.

Then it reads every comment. Collecting comments is easy. Working out which ones are worth keeping is the hard part, and it is not something keyword rules can do. GPT reads each comment (10 at a time, 12 groups at once for speed) and answers four questions: is this even about the product, how does this person feel, are they complaining, and what are they complaining about.

That second step is what fixed our biggest quality problem. We started with a word-scoring library that simply adds up how positive or negative each word is. It got sarcasm completely backwards: "I love how it deletes my data" scored as positive. It also had no way to tell that "great video man, keep it up" is about the video, not the product. GPT gets both right.

Elasticsearch

Elasticsearch is a search engine, and we use it as the app's memory. Once comments are collected and analyzed, this is where they live and where every number on the dashboard comes from. We picked it because we needed to do two things to the same data at once: search the full text of comments, and count things fast ("how many complaints mention pricing, broken down by website").

Everything lives in one place. All customers, products and websites share a single collection of data, and each comment is tagged with who it belongs to. Queries filter on those tags. The obvious alternative, giving each product its own separate storage, gets expensive quickly and makes it impossible to compare across products.

Collecting twice does not create duplicates. Each comment's ID is generated from its content and origin rather than being random, so re-running a collection overwrites the old copy instead of adding a second one. That means a job that crashes halfway can safely be run again. We tested this by indexing the same 2,146 comments twice and confirming we still had 2,146.

One website cannot drown out the others. This one surprised us. We first showed the "most engaging" comments by sorting on likes. But a YouTube comment might have 8,843 likes while a Steam review has 4 and a blog post has none, because every site counts engagement differently. Sorting them together meant YouTube won every slot and the other sources never appeared on screen at all, even though they were collected. Elasticsearch can group results by website first and take the best from each, which is what we do now.

Every statistic is also returned with a breakdown by website, because a complaint rate averaged across Hacker News and YouTube says as much about which sites we searched as it does about the product.

Browserbase

Most of the internet has no API. Browserbase is how we reach the rest of it.

It searches the web, then reads the pages. One call finds relevant pages for a search, another downloads a page and returns clean readable text instead of raw HTML full of menus and scripts. This is what lets us pick up review sites, forums and blog posts that have no official way in.

It also matters for the sites we cannot touch directly. Reddit and X block automated access, but plenty of articles quote those discussions, and Browserbase finds those articles. We get the opinions without scraping platforms that do not allow it.

Web pages fight back, so we check what we got. Some sites answer a robot with a "Prove you are human" page instead of real content, and confusingly they report it as a successful request. We check the text we get back for those telltale pages and throw them away. Sites we already know will block us are skipped before we waste a request on them. And because one long article could easily supply every quote in a run, we limit how much any single page or website can contribute.

ElevenLabs

ElevenLabs powers Vox, which lets you talk to the app instead of reading it. The hard part of a voice assistant is not the voice, it is making sure it does not make things up.

Vox is not allowed to answer from memory. We gave the ElevenLabs agent three specific abilities: look up a product's overall numbers, search the collected comments, and check a claim against the evidence. When you ask a question, the agent calls back into our backend, which looks up the real answer in Elasticsearch. It has no other source of information, so what it says out loud and what the dashboard displays always match. You can push back on something it claims and it will pull up the actual comments behind it.

Each conversation is locked to one product. Before a conversation starts, the browser asks our backend for permission, which hands back a temporary pass tied to the specific product you are looking at. Every question the agent asks our backend carries that pass, so it physically cannot read another customer's or another product's data.

Everything else

Python + FastAPI The backend. Runs the collection jobs, holds the connectors, serves the dashboard's data
Supabase Accounts, companies, products and the history of past collection runs. The database enforces who can see what, so a user cannot read another company's data even if the app asked it to
React + TypeScript + Vite The dashboard, the evidence pages, and the Vox panel
YouTube Data API Comments under product videos. We check a video's title actually mentions the product first, because searching "Notion" otherwise returns a song by that name
Steam Web API Game reviews, and the most useful thing in the project: each review carries the author's own thumbs up or down, which gave us a correct answer to test our sentiment analysis against
Hacker News (Algolia) Technical discussion, around 1,000 comments per search
Lemmy A Reddit-style network with an open API, read across three servers

Built With

Share this project:

Updates

Submission history