# Social listening pulse-check (/docs/recipes/social-listening-pulse-check) Stream a "what is the internet saying right now about X" feed across 15 platforms with one API call. Ranked, clustered, and enriched with real comments. You will build a streaming "what is the internet saying right now about X" feed for a brand-monitoring dashboard, an editorial newsroom, or an investor screening a thesis. Results render as they arrive, before the request finishes. **Cost per run:** 20 credits flat, regardless of how many sources respond or how much comment enrichment lands. Running it hourly for a day is 480 credits, daily for a month is 600. ## How do you search all social media platforms at once? Call `GET /v1/search/everywhere` with a query. SocialCrawl fans it out across Reddit, X, YouTube, TikTok, Instagram, Hacker News, Polymarket, GitHub, Threads, Pinterest, LinkedIn, Rumble, Perplexity, and Tavily in parallel, plus Naver when the query is written in Korean, then returns ranked, clustered results enriched with each post's top real-people comments. One request, one flat 20-credit charge. Listening to one platform misses the conversation: a launch trends on X, gets dissected on Reddit, becomes a meme on TikTok, and shows up as a prediction market on Polymarket, all in the same afternoon. ## What you need One endpoint does the fan-out, fusion, and ranking: - `GET /v1/search/everywhere` fans out across the 15 platforms named above and returns ranked, clustered results with the top comments from each post. In hashtag mode three more sources join the fan-out (TikTok, Instagram, and YouTube each add a hashtag-search sibling), for up to 20 in total. The response mode is selected by the `Accept` header. `text/event-stream` streams chunks as enrichment lands; `application/json` returns the full ranked set in one body. Same data either way. ## The code ```typescript title="TypeScript" // recipe-pulse-check.ts // Streams universal search results for a single topic. // Run with: SOCIALCRAWL_KEY=sc_... npx tsx recipe-pulse-check.ts const KEY = process.env.SOCIALCRAWL_KEY; if (!KEY) throw new Error("Set SOCIALCRAWL_KEY"); const url = new URL("https://www.socialcrawl.dev/v1/search/everywhere"); url.searchParams.set("query", "anthropic claude 4"); url.searchParams.set("lookback_days", "7"); url.searchParams.set("relevance", "filter"); // drop off-topic results, free const res = await fetch(url, { headers: { "x-api-key": KEY, accept: "text/event-stream", }, }); if (!res.ok || !res.body) { throw new Error(`Search failed: ${res.status} ${await res.text()}`); } const decoder = new TextDecoder(); let buffer = ""; // ranked_final names each result; comments_enriched arrives per result by id. const titles = new Map(); for await (const chunk of res.body) { buffer += decoder.decode(chunk as Uint8Array, { stream: true }); const events = buffer.split("\n\n"); buffer = events.pop() ?? ""; for (const event of events) { const dataLine = event .split("\n") .find((line) => line.startsWith("data: ")); if (!dataLine) continue; const payload = JSON.parse(dataLine.slice(6)); switch (payload.type) { case "plan_refined": console.log("plan ready, sub-queries:", payload.plan.subqueries.length); break; case "ranked_final": // The ranked list after relevance=filter: build your feed from this. console.log(`${payload.items.length} on-topic results`); for (const item of payload.items) titles.set(item.candidate_id, item.title); break; case "clusters": console.log(`clustered into ${payload.clusters.length} themes`); break; case "comments_enriched": { // One result's top comments, as they land. const top = payload.comments[0]; const title = titles.get(payload.candidate_id) ?? payload.candidate_id; console.log(`[${payload.source}] ${title}`); if (top) console.log(` → "${top.excerpt.slice(0, 120)}"`); break; } case "done": console.log( `done: ${payload.summary.total_items} results from ${payload.summary.sources_called.length} sources, charged ${payload.summary.credits_used}cr`, ); break; case "error": console.error("search error:", payload.message); break; } } } ``` `relevance=filter` drops the results the ranking step judged off-topic for your query and is included in the flat 20 credits. The `ranked_final` chunk carries the filtered list. `comments_enriched` chunks arrive per result as comments land and are not filtered, so one can arrive for a result that `ranked_final` leaves out: key your feed on `ranked_final` and merge comments into it by `candidate_id`. ## What you get back ```jsonc title="JSON" // One `comments_enriched` SSE chunk: one result's comments. One arrives per result. { "type": "comments_enriched", // <-- discriminator "candidate_id": "rd_18gha22", // <-- the result in ranked_final it belongs to "source": "reddit", "comments": [ // <-- real-people sentiment, also written to source_items[0].metadata.top_comments { "score": 142, "excerpt": "Same. Just shipped a migration in 20 min.", // <-- up to 300 characters "truncated": false, // <-- true when the comment was longer than the excerpt "author": "rustacean_42", "url": "https://reddit.com/r/ClaudeAI/comments/.../comment/...", }, ], } ``` ## What to change - **`query`**: a brand, a competitor, a person, a meme, a vertical, an asset. The endpoint does not care. - **`lookback_days`**: shorten it for breaking topics, lengthen it for slow ones. - **Drop streaming**: switch the `Accept` header to `application/json` and the same endpoint returns the full ranked set in one response body, with no chunk handling. - **Narrow the fan-out**: add `sources=` or `exclude=` to scope which platforms answer. The charge stays flat. - **Keep every result**: remove `relevance=filter` and nothing is dropped. Each result still carries `computed.relevance`, with `on_topic: false` on exactly the results the filter would have dropped, and a `computed.stance` toward your query. ## Go further This feed is a live look at the last few days. When the question is what was said during an exact date window, with every post judged against your question and duplicates removed across platforms, use [Discover](/docs/prism/discover.md). Send `brands` or `keywords` with a `period` such as `30d`, and a large request continues in the background and answers `202` with a run you can follow. To keep watching, send the same request as a `POST` with `schedule` and each run adds only the posts the last one did not have. A free `dry_run` prices it first. ## Related - [Brand mention monitoring](/docs/recipes/brand-mention-monitoring.md): The same call on a cron, with dedupe and alerting. - [Hybrid search-then-enrich](/docs/recipes/search-then-enrich.md): Feed these results into per-platform transcripts. - [Universal social search](/platforms/search/everywhere): Full chunk schema, source names, and date-bounded queries. - [Streaming](/docs/streaming.md): How SocialCrawl streams responses and what the chunks mean. - [Quickstart](/docs/quickstart.md): New here? Get a key and make your first request.