How ListingLens works
A real explanation of the agent architecture, API choices, and engineering decisions — written for the technical founder who wants to know whether the product is actually well-built, not just well-marketed.
Four agents, one synthesis layer
ListingLens doesn't run a single model against an Amazon URL. It runs four independent AI agents in parallel, each with a different data source and evaluation rubric, then synthesises their outputs into a unified report.
The fan-out runs via Promise.allSettled — all four agents start simultaneously, each streams its progress events independently, and a failed agent doesn't block the others. The synthesis layer only runs once all four have either completed or failed.
What each agent actually does
Visual auditor
Each image is base64-encoded and sent to Claude Sonnet with a custom rubric prompt: mobile readability (375px simulation), focal-point strength, text density, hierarchy clarity, and background competition. The model returns a structured JSON score for each image with per-failure explanations.
Claude Sonnet is chosen over GPT-4V because Sonnet is significantly more precise when scoring against a numerical rubric. GPT-4V tends to over-justify; Sonnet gives cleaner scores when the prompt is tightly constrained.
Review intelligence
Reviews are scraped via Firecrawl with an extraction schema (paginated, up to 50 reviews). Claude runs extraction in a single batch: identify purchase triggers, extract recurring complaints, and surface keywords that appear in reviews but not in listing images.
This gap list feeds directly into the brief generator — the most actionable output of the tool.
AI search visibility
This is the most novel agent. It constructs 6 high-intent shopper queries from the product category and sends each to both Claude and Gemini: "Recommend a product for this need." The agent checks whether the product ASIN, brand name, or primary keyword appears.
Both models are queried because AI shopping behaviour differs between them — a product can be visible on Claude and invisible on Gemini, or vice versa.
Category benchmarker
SerpAPI returns the top 5 organic competitors for the listing's primary keyword. Each competitor's hero image is fetched and proxied. Claude Vision then runs a pairwise comparison against your hero image on 4 axes: text clarity, visual hierarchy, trust signals, and mobile-first composition.
The output is a gap score (0–100) per competitor, plus a narrative callout on the single highest-opportunity visual gap. The benchmarker is started first as it's the slowest agent.
Why SSE, not WebSockets
The analysis pipeline is entirely server-to-client: the client submits a URL, then receives a stream of events. There is no bidirectional communication requirement after submission. SSE is strictly correct here — it's unidirectional by design, rides HTTP/2 for free multiplexing, and doesn't require a WebSocket handshake upgrade.
On Vercel Edge Functions specifically, WebSocket connections require a persistent connection that conflicts with the serverless execution model. SSE works natively with ReadableStream and flush control.
How agent failure is handled gracefully
Each agent runs inside a withTimeout(agentFn, 15_000) wrapper. If an agent exceeds 15 seconds or throws, it returns a degraded result object instead of propagating an exception.
Key architectural choices
| Decision | Chose | Rejected | Reason |
|---|---|---|---|
| Transport | SSE | WebSockets | Unidirectional flow; works on Vercel Edge without persistent connections |
| Visual scoring | Claude Sonnet | GPT-4V | Cleaner structured output; less over-justification on rubric-constrained scoring |
| Persistence | Upstash KV | Postgres | Serverless-native; no connection pooling overhead; free tier covers MVP volume |
| Agent fan-out | Promise.allSettled | Promise.all | Sequential is 4× slower; Promise.all fails-fast on any error |
| Image proxy | Edge Function | Direct CDN URLs | Amazon CDN URLs require browser cookies; proxying server-side bypasses CORS |
| Score card export | html-to-image | @vercel/og (Satori) | Client-side canvas rendering handles complex CSS seamlessly and avoids strict Satori layout limitations |