Threads Scraper — Posts, Profiles, Replies & Search
Pricing
from $3.50 / 1,000 results
Threads Scraper — Posts, Profiles, Replies & Search
Extract public Threads (Meta) data — posts, replies, profiles, keyword search — as clean structured JSON. No login or cookies. Recommended posts are filtered out, so replies are actually replies. Structure-adaptive parser that survives Meta's changes.
Pricing
from $3.50 / 1,000 results
Rating
0.0
(0)
Developer
Northbound Data
Maintained by CommunityActor stats
0
Bookmarked
7
Total users
2
Monthly active users
19 days ago
Last modified
Categories
Share
Threads Scraper — Posts, Profiles, Replies & Keyword Search
Extract public Threads (Meta) data as clean structured JSON: posts, replies, profiles and keyword search results. No login. No cookies. No account of yours is ever used.
Give it a post URL, a profile URL, a @username or a keyword — mix them freely in one run — and get back a flat, ready-to-use dataset.
"Replies" and "comments" are the same thing here. Threads calls them replies; most people and most tools call them comments. If you came looking for a Threads comments scraper, this is it — the replies under a post are its comments, and they come back in the same dataset either way. We use Threads' own word for it in the field names so the output matches the source.
Why this one
Most Threads scrapers break the moment Meta ships a change, because they hard-code GraphQL doc_id values or fixed JSON paths. This one identifies data by structural signature, not by path — so a Meta refactor degrades it instead of killing it.
| This Actor | Typical alternative | |
|---|---|---|
| Measured failure rate | 0% across 24 tasks — 8 profiles, 10 posts, 6 keyword searches, 647 records delivered, 72 fetches with zero render fallbacks | 13% on the two largest Threads Actors (measured 2026-08-19) |
| Recommended posts mixed into replies | Never — filtered out explicitly | Common, and it silently pollutes your dataset |
Breaks when Meta rotates doc_id | No — nothing is hard-coded | Yes |
| Login / cookies required | No | Varies |
Replies are actually replies
Threads serves recommended posts in the same payload as the real replies to a post. Naive scrapers hand you both, mixed together, with no way to tell them apart — you think you have 30 replies to your post, and 10 of them are strangers talking about something else.
This Actor separates them and returns only genuine replies, each carrying root_post_author and replied_to_username so you can verify the thread they belong to.
Honest limitation — please read before you buy
Meta caps logged-out access to Threads. Measured, as of August 2026:
| Surface | What you get without logging in |
|---|---|
| Replies to a post | ~20 (Threads then shows "Log in to see more replies.") |
| Keyword search | ~20 per surface — but this Actor merges all 5 public surfaces for ~50 (see below) |
| Posts on a profile | ~5 per tab — but this Actor merges all 4 public tabs for 16-22 (see below) |
Replies cannot exceed this — it is enforced by Meta, not by this Actor.
Profiles and search are the exceptions, because Meta caps each entry point, not the total.
Search is the exception. Threads exposes five separate public search surfaces (default, recent, top, users, tags), each capped at ~20 but each returning a different result set. This Actor queries all five and merges them deduplicated, which measured 47 posts for ai agents and 54 for climate tech — about 2.4–2.7x what a single-surface scraper returns. Every record carries a search_surface field. Set searchDepth: "standard" for the faster single-surface behaviour.
Profiles work the same way. A Threads profile has four public tabs — threads, replies, media, reposts — each capped at ~5 but each holding different posts. This Actor queries all four and merges them: measured 16 posts for @nasa and 22 for @mkbhd, against 5-6 from the main tab alone (2.7-4.4x). Every record carries a profile_tab field. Set profileDepth: "standard" to query only the main tab.
Neither of these is a bypass — every surface and tab is the same public endpoint the Threads website itself uses, read logged-out. Anything promising you "all 800 replies" without an account is either using logged-in accounts (against Threads' terms, and those accounts get banned) or it is not telling you the truth.
This Actor is built for per-target lookup at volume: point it at 1,000 posts and get the top ~20 replies for each, reliably. It is not a bulk archive crawler. If you need full reply archives, this is not the right tool and you should not buy it.
When the cap is reached the Actor stops immediately instead of burning your compute on scrolls that return nothing.
Dead handles do not count against us — and we tell you which ones they were
Feed in a list of 40 brand accounts and some of them will not exist on Threads. In our own 40-account test, six did not: tesla, spacex, apple, stripe, vercel, anthropicai.
Most scrapers count those as failures, which inflates the failure rate you see and tells you nothing about which inputs were bad. This Actor separates them:
failedTasks— runs that actually went wrongnotFoundTargets+notFoundList— targets that simply do not exist, listed by name so you can clean your inputfailureRate— computed over real attempts only, excluding non-existent targets
You get an honest reliability number and a list of the handles worth removing from your source data.
Why residential proxy is the default
Meta serves empty shell pages to datacenter IPs. When that happens this Actor falls back to full browser rendering, which still returns correct data but is dramatically slower and more expensive.
Measured on the Apify platform, same target, same day (2026-08-19):
| Proxy | Mode used | Time per profile | Compute cost per run |
|---|---|---|---|
| Datacenter (Apify default) | browser rendering | 150 s | $0.127 |
| Residential | direct fetch | 3.3 s | $0.0086 |
That is 45x faster and 15x cheaper, for a residential transfer cost of roughly 7% of what the returned records are worth. So RESIDENTIAL ships as the default proxy group.
You can override it, but if you switch to datacenter expect slow runs — the Actor will still work, it just has to render every page.
Input
{"startUrls": [{ "url": "https://www.threads.com/@natgeo/post/Db5pTtZFAmB" },{ "url": "https://www.threads.com/@nasa" }],"usernames": ["mkbhd"],"searchQueries": ["ai agents", "climate tech"],"includeReplies": true,"maxRepliesPerPost": 25,"maxItems": 1000}
| Field | Type | Notes |
|---|---|---|
startUrls | array | Post URLs, profile URLs or search URLs. Detected automatically. |
usernames | array | Bare usernames, with or without @. |
searchQueries | array | Keyword searches. |
includeReplies | boolean | Default true. Set false for posts only. |
maxRepliesPerPost | integer | Default 25. Values above ~20 will not return more — see the limitation above. Set to 20 for the fastest path (~2 s/post, no page rendering). |
searchDepth | string | deep (default) queries all five public search surfaces and merges them (~50 posts/keyword); standard queries only the default surface (~20). |
profileDepth | string | deep (default) queries all four profile tabs and merges them (16–22 posts); standard queries only the main tab (~5). |
maxItems | integer | Hard cap on billed records. Your safety net against surprise charges. |
proxyConfiguration | object | Defaults to RESIDENTIAL. See the section above — datacenter IPs get shell pages from Meta and force slow rendering. |
Output
One flat record per post or reply:
{"id": "3961381054679086896","code": "Db5pxS4G_cw","url": "https://www.threads.com/@catacolypse_/post/Db5pxS4G_cw","is_reply": true,"replied_to_username": "natgeo","root_post_author": "natgeo","text": "Ohmygosh, yes!! We just had this visitor yesterday!","posted_at": "2026-08-11T13:04:02.000Z","like_count": 101,"reply_count": 2,"repost_count": 0,"quote_count": 0,"author": {"id": "63294227753","username": "catacolypse_","full_name": "Cathie English","is_verified": false,"profile_pic_url": "https://…"},"media": { "images": [], "videos": [], "alt_text": null },"query_type": "post","query_value": "https://www.threads.com/@natgeo/post/Db5pTtZFAmB","source_url": "https://www.threads.com/@natgeo/post/Db5pTtZFAmB","scraped_at": "2026-08-12T13:56:56.667Z"}
Every run also writes a RUN_SUMMARY key with tasks, itemsPushed, failedTasks and failureRate, so you can monitor reliability yourself instead of taking our word for it.
What it's used for
- Brand & product monitoring — track the comments under your announcements, and under anyone else's, on a schedule; every record carries text, engagement counts and a timestamp
- Reading a whole conversation — a post plus the discussion underneath it, as one flat dataset,
with
root_post_authorandreplied_to_usernameon every row so the thread stays reconstructable - Competitor watch — follow competitor accounts and the sentiment underneath their posts
- Creator research — find accounts and posts that perform in a topic
- AI agents & RAG — clean JSON in, no HTML parsing, ready to embed
When the official API is not an option
Meta ships a Threads API, and for some jobs it is the right tool — publishing your own posts, reading your own analytics, managing replies to your own content. Use it for those.
But its content access is limited to the publisher. It will not give you the replies under someone else's post, or an arbitrary account's profile feed. If that is what you need, reading public pages is the only route, and this Actor is the Threads API alternative for exactly that gap.
The official API's Keyword Search endpoint is real and, with threads_keyword_search approved,
covers all public posts at up to 100 results per query — more than logged-out scraping returns.
We say so plainly rather than pretend otherwise. The full comparison, sourced from Meta's own
documentation, is here:
Threads API or scraping? What each one can actually do
Pricing
Pay per result. You are charged only for records actually delivered to your dataset, and duplicates within a run are never billed twice. maxItems caps your spend.
The numbers behind this page
Everything this Actor claims about Threads' logged-out ceilings — the ~20 reply cap, the five search surfaces, the four profile tabs, and the empty shell page Meta serves to datacenter IPs as a valid HTTP 200 — is written up with the measurements, dates and method here:
What Threads actually returns when you are not logged in
It is a reference, not a sales page. If you are evaluating any Threads scraper, including someone else's, those are the limits to test them against.
Open-source client
There is a small MIT-licensed JavaScript client for this Actor, so you do not have to write the run-start / polling / dataset-pagination plumbing yourself:
github.com/zhanghengrui0308/threads-data-client — zero dependencies, Node 18+.
import { ThreadsClient } from 'threads-data-client';const threads = new ThreadsClient(process.env.APIFY_TOKEN);const rows = await threads.scrape({startUrls: [{ url: 'https://www.threads.com/@natgeo/post/Db5pTtZFAmB' }],usernames: ['nasa'],});
It also exposes estimateCost(actor, records, tier), which tells you the exact
USD bill for a run before you start it, at your own plan tier.
You do not need it — the Actor works fine from the Apify Console, the API, or any HTTP client. It is there if you would rather read the code than trust a description of it.
Legal & scope
Reads public Threads pages only. No login, no cookies, no CAPTCHA solving, no access-control circumvention. On robots.txt, stated plainly: threads.com/robots.txt runs an allowlist. Named crawlers
(Googlebot, Bingbot, GPTBot, ClaudeBot and others) are granted specific access; for every other user
agent the file says Disallow: /, and its opening notice states that automated collection requires
express written permission from Meta. This Actor is not on that allowlist. We say so because you
should decide with the real facts rather than a comfortable summary, and because you are the party
accountable for how the data is collected and used under Meta's terms and applicable law. You are responsible for how you use the data, including GDPR/CCPA obligations where personal data is involved.