Primitive/social-data3 min read

Introducing /social-data: read public posts, two platforms with no credentials at all

Search and collect public posts from Bluesky, Hacker News, X and Reddit behind one canonical schema — two of them with no API key at all, at a tenth of the cost, and Reddit routed to async because a sync read cannot finish.

Social data primitive →Read the docs →

Primitive/social-data
TL;DR
  • /social-data read public posts, comments and engagement. Read-only, and separate from /social, which publishes
  • Bluesky and Hacker News work with NO credential and cost a tenth of the credentialed platforms
  • Reddit is ASYNC-ONLY, because a live read took 53–219 seconds for five posts
  • Metrics are platform-honest a metric a platform lacks is absent, not zero
  • One canonical schema across platforms, with the untouched provider payload kept under `raw`

Most social-data APIs start with a procurement problem. X charges per read with no free tier. Reddit's commercial API closed self-service registration and takes weeks to approve. Collection vendors cost money and sit on contested terms-of-service ground.

/social-data ships four platforms, and two of them have none of those problems.

Two platforms, no credential, no vendor invoice

Bluesky and Hacker News serve public read APIs. No key, no application, no scraping — and no vendor invoice, so deriving their price from provider spend would be multiplying zero. They keep a flat one credit per 100 posts, where the scraped platforms bill 3× whatever their run really cost.

Not free, deliberately: a zero-cost call is one nothing bounds, and an unmetered endpoint is an unmetered abuse surface. The rate is keyed on the resolved provider, not the platform, so wiring a paid provider for one of them later cannot silently inherit the free price.

naive social-data discover --platform hackernews --query "postgres" --engagement-min 50

Reddit is asynchronous, and that is a measurement

A live Reddit run took 53 to 219 seconds to return five posts, against a request budget in the tens of seconds. That is not a slow case with a fast case — it is a timeout, and the expensive shape of one: the actor run bills and the settle completes while the client has already given up and retried.

So both sync entry points refuse Reddit outright, in discover as well as collect, and point at /v1/social-data/tasks. The CLI and SDK refuse it before the request leaves the process, and the MCP tools do not offer Reddit as a sync option at all. "Reddit is async" should not be a rule you learn from a 504.

One shape, platform-honest metrics

Every post normalizes to the same fields — id, platform, author, text, url, created_at, metrics, optional comments. What we refuse to do is invent parity: retweets is X-only, upvotes is Reddit-only, and a metric a platform does not have is absent rather than zero, because zero is a claim. Hacker News has points, not likes, and the response says points. Anything the canonical schema does not model stays available under raw.

include_comments is where an honest schema costs something. Hacker News threads come back flattened; Reddit threads come back through the batch route. Bluesky and X refuse it, because on both, replies are a separate fetch neither adapter performs — and billing the higher with-comments rate for posts that arrive without any would be the wrong kind of quiet.

prefer_official, and what it means now

Routing used to pick the cheapest capable vendor among four, including sending Reddit to its official API whenever a credential existed. Those adapters were never implemented, so the "cheaper" route chose a provider that could not serve the call.

The flag stays in the contract and stays meaningful. For Bluesky and Hacker News it is already satisfied — those are the official APIs. For X and Reddit it is refused explicitly, because claiming a ToS-clean route that does not exist would be worse than saying so.

Billing shape

Per block of 100 posts, rounded up: a one-post call pays one block, a 250-post batch pays three, zero posts pays nothing. Filters apply before metering, so a date_from or engagement_min that removes half the results removes half the bill.

Blocks are safe here where they would not be for People, because the collection actors bill per 1,000 records — the worst case for a 100-post call is bounded. Reddit is the thinnest margin on the platform and the one to watch.

Public is not unrestricted

Posts are personal data, and you are the controller of what you retain. Terms Section 18 prohibits building personal profiles of authors, monitoring people rather than topics, and feeding employment, credit, insurance or housing decisions. Each platform's own terms continue to apply.

Sync reads store nothing; async batches prune at 90 days. POST /v1/social-data/erasure clears a subject from stored results, unmetered — though the posts remain public on the platform, and the response says so.

Full reference: Social Data docs. Current gaps, in one place: what is not done.

Frequently Asked Questions
What is /social-data?+
The Naïve primitive for reading public social content. It is read-only and separate from /social, which connects accounts and publishes.
Do I need an API key?+
Not for Bluesky or Hacker News — both serve public read APIs. X and Reddit run on Apify actors and need APIFY_API_TOKEN.
Why is Reddit batch-only?+
Because a live Reddit run took 53 to 219 seconds to return five posts. A sync route would time out while the run still billed, so both sync entry points refuse it and point at /v1/social-data/tasks.
Why is it cheaper than other social data APIs?+
For Bluesky and Hacker News there is no vendor invoice behind the read, so the meter reflects Naïve's own request handling — a tenth of the scrape rate.
A
AshleyEngineering

Engineering at Naïve. Owns the data primitives.

@ashley_naive