# Twitter/X public data, no official developer platform

2026-08-04

> Search, profiles, timelines, and followers as JSON on twitter.fetcher.sh. Not developer.x.com, not OAuth, not app review.

- Index: https://fetcher.sh/blog.md
- This page (HTML): https://fetcher.sh/blog/twitter-x-public-data-without-developer-platform

![A 3D render of the X social logo](https://images.unsplash.com/photo-1611605698323-b1e99cfd37ea?auto=format&fit=crop&w=1600&q=80)

Photo by Alexander Shatov on [Unsplash](https://unsplash.com/?utm_source=fetcher_sh&utm_medium=referral).

If you want public tweets as JSON, the official path is the X developer platform: an app, OAuth, review, a SKU. That is the right path if you are building *on* X. It is a slow path if you need search, a timeline, or a follower list tonight and you are not applying to become a partner.

[twitter.fetcher.sh](https://twitter.fetcher.sh) is the other path. You call a GET. Public tweets, handles, search, timelines, and follower lists come back in the usual `{ status, message, data }` envelope. You do not wait in an app-review queue.

x.com is still X. The host is just the API. Private accounts and DMs are not in the catalog, and this is not a firehose contract. It is a priced JSON API for public objects.

## What you can fetch

Search, including X’s own operators when you put them in `query`. Tweets by id. User timelines, replies, retweeters, lists, trends. Resolve a handle to a profile. Pull followers and followings. Every path is GET. Prices and parameters are on the host and in [/docs](/docs).

A first call, with a prepaid key:

`curl -H 'Authorization: Bearer bby_live_…' 'https://twitter.fetcher.sh/api/search?query=from:OpenAI'`

Without a key the same URL answers 402. [Pay per call](/blog/pay-per-call-vs-monthly-api-plans) and [how an agent pays](/blog/how-an-agent-pays-for-a-public-data-request) cover the settlement. [from:, since:, until:](/blog/x-search-operators-from-since-until) is the operator deep dive.

Most list endpoints want a numeric id. [Resolving a handle](/blog/resolving-a-social-handle-to-a-stable-id) is the lookup. [Follower graphs](/blog/follower-following-graphs-x-instagram-tiktok) are the edges. [Brand mentions](/blog/brand-mention-monitoring-x-reddit-google-news) reuse search. None of those jobs require Elevated access.

## How this feels compared to the developer portal

The portal is an identity and a contract. You are an app. You have scopes. You might post. You might pay for a firehose. That is a product company relationship.

This host is a URL. You are a client of fetcher.sh. You read what is already public. You do not post. You do not read DMs. You do not get a compliance archive. If a tweet is gone, the envelope says so in JSON instead of a spinner on x.com.

Teams stall because they think they must apply *in case* they need write access later. Apply when you need write access. Fetch when you need a tweet. Mixing those decisions is how a research task waits six weeks.

Google’s `site:x.com` is not a substitute. It is a SERP. Use google.fetcher.sh for the open web; use this host for tweets.

## A case: a reporter reconstructing a public thread

A reporter has a tweet URL and a handle. They need the tweet, the replies under it, and a week of that account’s public timeline — not to republish a firehose, but to sit the quotes next to each other.

They resolve `@OpenAI` to an id. They fetch the tweet by id. They pull replies. They run search with `from:OpenAI since:2026-01-01 until:2026-01-08`. None of that requires Elevated access. None of it returns DMs or protected accounts. If a tweet is gone, the envelope says so in JSON.

That is a morning’s work with a key from [/topup](/topup). The official platform is still the right tool if they need write access or a compliance firehose. For public reconstruction, the host is enough.

A second reporter on the same desk only has a search string, not a URL. They start with operators instead of a tweet id: `from:OpenAI since:2026-01-01 until:2026-01-08 -filter:replies`. They page until the window is covered, store tweet ids, and only then fetch replies on the ones that matter. Search is the net. Tweet-by-id is the close read. Mixing those two in one confused GET is how you get a page of Latest results you already had.

## A case: an agent that should not store an X app secret

A small agent searches `from:OpenAI` when a user asks what the lab posted. The developer does not want an X client secret in the prompt or in a shared repo.

They use `@x402/fetch` or a `bby_live_` key. The agent calls search, maybe resolves a handle, maybe pulls a tweet by id. It never completes OAuth. It never sees a DM. If the user wanted to *post*, they would need the official platform, and this agent would refuse.

A newsroom weekly that is still not a firehose: one `from:` query for the accounts on the beat, one keyword query with `since:` for the last seven days, store tweet ids, fetch replies only on the ones that became the story. Lists and trends exist on the host when the question is a list or a trend. They are not a substitute for search.

DMs, protected accounts, and write access remain official-platform work. Public JSON remains this host. The 402 you see without a key is checkout, not a ban.

## When to use the official platform instead

Use developer.x.com if you post as a user, if you need private data, or if you have already signed a firehose contract. We return public objects. A failed call is JSON, not an HTML error page. Docs live on the host and at [/docs](/docs); agents can read [`/skill.md`](/skill.md).
