SocialCrawl

Social listening pulse-check

Stream a "what is the internet saying right now about X" feed across 14 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, 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 14 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 17 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
// 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");

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 = "";

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 "clusters":
        console.log(`clustered into ${payload.clusters.length} themes`);
        break;
      case "comments_enriched":
        for (const item of payload.items) {
          const top = item.source_items[0]?.metadata?.top_comments?.[0];
          console.log(`[${item.source}] ${item.title}`);
          if (top) console.log(`  → "${top.text.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;
    }
  }
}

What you get back

JSON
// One `comments_enriched` SSE chunk, many of these arrive over the stream
{
  "type": "comments_enriched", // <-- discriminator
  "items": [
    {
      "candidate_id": "rd_18gha22",
      "source": "reddit", // <-- one of the 14 platforms
      "title": "Claude 4 is shockingly good at refactors",
      "url": "https://reddit.com/r/ClaudeAI/comments/...",
      "snippet": "I gave it a 4k-line Rust file and...",
      "final_score": 0.91, // <-- RRF + rerank fused
      "cluster_id": "cluster_3", // <-- groups related posts
      "source_items": [
        {
          "metadata": {
            "top_comments": [
              // <-- real-people sentiment
              {
                "text": "Same. Just shipped a migration in 20 min.",
                "score": 142,
              },
            ],
          },
        },
      ],
    },
  ],
}

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.

On this page