What You Can Actually Get From Each Social Platform Without an API Key
Ten platforms probed on one day from one IP, with status codes and byte counts — including the rows that returned nothing at all.
12 min read · 20 Aug 2026
Before you write any code, you want to know which platforms will answer you at all, what they hand over, and what it costs. That question is normally answered by someone selling you the answer, which is why every version of this page you have found so far concludes that you need a product.
Here is the version with the commands in it. Every row was produced by an actual request on the date shown, and the rows that failed are in the table alongside the ones that worked.
How to read this page
Method. Plain curl, following redirects, no browser, no JavaScript engine, no proxy, no authentication anywhere. One IP: AS133982, Excitel Broadband, New Delhi, India — a consumer broadband line. All requests on 2026-08-20.
"Works" means we received a parseable body containing the data we asked for. A 200 with an empty body is a failure. A 200 containing a bot challenge is a failure. Both appear below, because both are extremely common and neither shows up in a status-code check.
Three caveats you should weigh before using any of this.
- The IP is the biggest variable in the whole table, not the endpoint. A consumer ISP address gets served things a datacenter address does not. Several rows below would look worse from a cloud VM, and we say which.
- One region. Some of these behave differently from EU addresses (consent interstitials) or US ones (regional gating). We tested from one place.
- TikTok is inaccessible from India. It has been blocked there since 2020. Our TikTok row is therefore worthless as evidence about TikTok and we have labelled it that way rather than deleting it, because a table with a hole in it is more useful than a table that hides one.
The table
| Platform | Surface | Auth | Result on 2026-08-20 |
|---|---|---|---|
| YouTube | feeds/videos.xml?channel_id= |
none | ✅ 200 · 21,438 B · 15 videos with views + likes |
| YouTube | oembed?url= |
none | ✅ 200 · 868 B · title, author, thumbnail |
| YouTube | /@handle HTML |
none | ✅ 200 · 2,754,441 B · channel ID four ways |
| YouTube | /watch?v= HTML |
none | ✅ 200 · 1,320,339 B · full player response |
| YouTube | api/timedtext (exp=xpe) |
PO token | ⛔ 200 · 0 B in all 7 format variants |
| X / Twitter | cdn.syndication.twimg.com/tweet-result |
none | ✅ 200 · 920–2,791 B · one tweet |
| X / Twitter | syndication.twitter.com/srv/timeline-profile |
none | ✅ 200 · 115–637 KB · 20 tweets + full user |
| X / Twitter | publish.twitter.com/oembed |
none | ✅ 200 · 521 B · text only |
| X / Twitter | x.com/<handle> HTML |
none | ⚠️ 200 · 282,546 B · 6 tweets — IP-dependent |
| X / Twitter | widgets/followbutton/info.json |
none | ⛔ 200 · 0 B · retired |
| X / Twitter | api.x.com v2 |
paid | 💳 credits, priced per resource |
/<user>/ HTML |
none | ⚠️ 200 · 810,445 B · counts only, no posts | |
api/v1/users/web_profile_info/ |
none | ⛔ 429 · 0 B on the first request, 4/4 | |
/<user>/?__a=1&__d=dis |
none | ⛔ 201 · 0 B | |
/p/<code>/embed/captioned/ |
none | ⚠️ 200 · 233,159 B · author + avatar, empty caption | |
| Meta Ad Library | graph.facebook.com/…/ads_archive |
token | 🔑 500 · OAuthException without one |
| Meta Ad Library | facebook.com/ads/library/ UI |
none | ⛔ 403 + JS challenge |
| TikTok | oembed?url= (documented) |
none | ❓ 200 · 105,881 B of HTML, not JSON — invalid vantage point |
/company/<name>/ |
none | ⛔ HTTP 999 | |
/r/<sub>/.rss |
none | ✅ 200 · 50,686 B · Atom | |
/r/<sub>/new.json |
none | ⛔ 403 · 189,908 B HTML | |
| Bluesky | public.api.bsky.app/xrpc/… |
none | ✅ 200 · JSON · profile + feed, CORS * |
| Mastodon | <instance>/api/v1/accounts/lookup |
none | ✅ 200 · 2,371 B · JSON |
| Threads | /@<handle> HTML |
none | ⚠️ 200 · 782,893 B · counts only |
YouTube — still the most open surface on the web
Nothing else on this list comes close. Five separate no-key surfaces, all of them stable, all of them documented enough to be reliable, none of them requiring a proxy.
The channel feed is the one to build on. Fifteen entries, 3,886 bytes gzipped, and — contrary to almost every write-up — each entry carries media:statistics views and media:starRating count, so you get view and like counts for free. Cache-Control: public, max-age=900 with no ETag and no Last-Modified, which means fifteen-minute polling is both the etiquette and the ceiling; there is no conditional-request path to make it cheaper.
The blocker everyone hits is that these routes want a UC… ID and users hand you @handle. The channel page solves it four ways in one fetch, the cleanest being the <link rel="alternate" type="application/rss+xml"> tag that hands you the finished feed URL. The full write-up, with the quota arithmetic and the byte costs, covers the rest.
The one hard wall is captions. Every caption track carrying &exp=xpe returns 200 with zero bytes in every format we tried, including with a fake token attached. That gate needs a real proof-of-origin token minted from Google's BotGuard VM, which is a solved but genuinely involved problem.
Proxy required: no. The rows above are from the residential IP like everything else on this page, but YouTube is the one platform where that does not appear to matter — our own production traffic reads these same surfaces from plain datacenter addresses with no rotation and no proxy budget at all, which is why YouTube costs us close to nothing to serve.
X / Twitter — the embed infrastructure is the API now
Everything public that still answers is embed infrastructure, kept alive because publishers depend on it.
cdn.syndication.twimg.com/tweet-result returns one tweet as clean JSON. It requires a token query parameter that, as of this test, is not validated — token=a works and an omitted token returns 200 with the two-byte body {}. Compute the real value anyway.
syndication.twitter.com/srv/timeline-profile/screen-name/<handle> is the richer surface and the less-known one: 20 tweets with retweet_count, quote_count, reply_count and favorite_count, attached to a complete legacy user object including followers_count, statuses_count and the account creation date. Eight handles, eight successes.
The row to be suspicious of is x.com/<handle> HTML. From this residential IP it server-renders six tweets with full text and metrics — which contradicts the "logged-out x.com is a login wall" received wisdom. From a datacenter IP our own probes get rate-limited fast, which is exactly why our Twitter profile endpoints are documented as needing residential proxies. Treat that row as true of consumer IPs and unproven everywhere else.
The paid API is pay-per-usage credits — "no subscriptions," per X's own docs. Its unauthenticated pricing endpoint reports $0.005 per post read and $0.01 per user read, charged per resource returned, so a 20-post timeline call costs twenty units. The tested rundown of every route, including the nine Nitter instances, has the full numbers.
Proxy required: for single tweets and oEmbed, no. For profiles and timelines at any volume, yes.
Instagram — the honest picture, which is not a good one
We are going to be blunt here, because the alternative is being useful to nobody.
api/v1/users/web_profile_info/ — the endpoint every Instagram scraper is built on — returned HTTP 429 with a zero-byte body on the very first request, and on three retries after it. Not after a hundred requests. The first one. From a residential IP with the correct x-ig-app-id header. Meta is gating this by address, aggressively, and a consumer ISP is not enough on its own.
The legacy ?__a=1&__d=dis trick returns HTTP 201 with a zero-byte body, which is a genuinely strange thing for a GET to do and is best read as "no."
What still works is the public profile page, and only for aggregate numbers:
<meta property="og:description"
content="104M Followers, 96 Following, 4,886 Posts - See Instagram photos and videos from NASA (@nasa)">
A rounded follower count, an exact following count, an exact post count. 810 KB of HTML for three numbers. The page also contains eight /p/ and four /reel/ shortcodes, so you can enumerate a handful of recent post IDs — but not their captions, timestamps or engagement.
The post embed at /p/<code>/embed/captioned/ returns 233 KB, renders the author's handle, avatar and numeric owner ID, and leaves the class="Caption" div empty. The media loads by JavaScript.
Where our own product stands on this, stated plainly: our Instagram endpoints are documented as rate-limited from datacenter IPs and requiring residential proxies, and the single-post endpoint is marked untested. That is in our README, not buried. Instagram is the weakest platform we cover and it is weak for everyone; anybody telling you otherwise is quoting a success rate measured through proxies they are also selling you.
Proxy required: yes, residential, and it will still fail sometimes.
Meta Ad Library — the one with a real, sanctioned API
Different in kind from everything else here. The Ad Library exists because Article 39 of the EU Digital Services Act requires very large platforms to maintain it, and Meta exposes it through the official Graph API.
The UI is defended like any other Meta property — facebook.com/ads/library/ returned 403 with a JavaScript challenge. The API is not: it returned 500 with an OAuthException purely because we sent no token, which is a token problem rather than a bot problem, and token problems have a documented fix.
That distinction is the entire argument for building on the API rather than the page. No proxies, no fingerprint evasion, no breakage when Meta ships a frontend change. Field by field, including the identity-verification path for getting a token.
Our own four Ad Library endpoints are blocked on FACEBOOK_ADLIB_ACCESS_TOKEN and return a clean, unbilled error until it is set. They are not live without it, and we are not going to imply otherwise.
Proxy required: no. Token required: yes.
TikTok — we could not test this and neither should you pretend to
TikTok has been blocked in India since 2020. Our test IP is in Delhi. Every TikTok request we made returned an identical 105,881-byte HTML page, including the documented oembed endpoint that is supposed to return JSON.
That result is consistent with a regional block, with a bot challenge, or with the endpoint being genuinely broken, and we cannot distinguish between them from here. So: untested. We are not going to launder a bad vantage point into a finding.
What we can say without testing: TikTok has no open public read API. The Commercial Content API is application-gated and covers ads, not organic content. The Research API is limited to accredited institutions. Everything else in the ecosystem is HTML scraping through residential proxies, and it breaks often.
LinkedIn — HTTP 999
https://www.linkedin.com/company/nasa/ returns HTTP 999, a status code that does not exist in any RFC and that LinkedIn has used for years to mean "we know what you are." It is at least refreshingly direct.
There is no public read API, no bulk export, and no logged-out surface worth the name. The one exception is LinkedIn's DSA-mandated ad library, which is browse-only — no API, no bulk export, no date filters.
The ones nobody puts in these tables
Three platforms that are dramatically easier than the ones everyone writes about, and get left out because they are less commercially interesting.
Bluesky. public.api.bsky.app serves the unauthenticated AppView. app.bsky.actor.getProfile and app.bsky.feed.getAuthorFeed both returned clean JSON with no key, including exact follower, follow and post counts. It sets Access-Control-Allow-Origin: *, so it works directly from a browser. This is what a public social API looks like when the platform is not trying to stop you.
Mastodon. <instance>/api/v1/accounts/lookup?acct=<user> returned 200 and 2,371 bytes of JSON. Per-instance, so per-instance rate limits and per-instance policy, but open by default.
Reddit. Split verdict, and an instructive one. /r/<sub>/.rss returned 200 and 50,686 bytes of Atom. /r/<sub>/new.json — the classic route in every tutorial — returned 403 with 190 KB of HTML. Same content, same host, opposite outcome, because one is a feed and the other is the thing scrapers hammer.
Threads behaves exactly like Instagram, which it is: 783 KB of HTML, an og:description with "5.7M Followers • 155 Threads", four post codes, nothing else.
The CORS table, because it decides your architecture
If you are building anything browser-side, this matters more than any of the above.
| Endpoint | Access-Control-Allow-Origin |
|---|---|
public.api.bsky.app/xrpc/… |
* — fully open |
youtube.com/oembed |
reflects your origin |
publish.twitter.com/oembed |
reflects your origin |
cdn.syndication.twimg.com/tweet-result |
https://platform.twitter.com only |
youtube.com/feeds/videos.xml |
none |
The two oEmbed endpoints and Bluesky are callable from a page. Everything else needs a server in front of it, which for a lot of "just show a tweet on our site" requirements is the whole difference between an afternoon and a backend.
What we could not get to work
- Instagram's
web_profile_info, from a residential IP, at all. 429 on request one. - Any Instagram post caption without JavaScript.
- YouTube captions on
exp=xpetracks without a minted PO token. - Reddit's
.jsonroutes, which every tutorial still recommends. - Anything at all on TikTok, for reasons that are our fault, not TikTok's.
- LinkedIn, for reasons that are not.
- Retweet counts from X's single-tweet endpoint — present in the timeline payload, absent from
tweet-result, cause unknown. - Conditional requests against YouTube RSS. No
ETag, noLast-Modified, no 304.
Where we sit in this
We run 15 endpoints across 4 platforms, and the status table in our README uses the same symbols as the one above for the same reason: the five YouTube endpoints and the single-tweet endpoint are verified working unproxied, the Instagram and Twitter profile endpoints are rate-limited from datacenter IPs and want residential proxies, and the four Ad Library endpoints are blocked on a token until you set one. A request that fails for any of those reasons is never charged.
That is a shorter list than most vendors advertise. It is also a list where every row says what it actually does, which is the only reason to publish one.
Change log
- 2026-08-20 — first publication. All rows probed from AS133982 (New Delhi, IN) on this date. TikTok recorded as untested due to the regional block.
If a row here is wrong from where you are sitting, it probably is — check your ASN first, then tell us. We will re-run the whole table and re-date this page rather than quietly patching a cell.