Threads Posts Scraper 🧵 Public Profiles, No Login
Pricing
from $1.43 / 1,000 post returneds
Threads Posts Scraper 🧵 Public Profiles, No Login
Scrape posts from any public Threads profile. Pass profile handles or URLs; get post text, like, reply and repost counts, author handle, publish date and a direct post URL as JSON or CSV. No login required. Since date filter makes scheduled monitoring cheap.
Pricing
from $1.43 / 1,000 post returneds
Rating
0.0
(0)
Developer
Yaniv van der Stigchel
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
Threads Posts Scraper — monitor profiles, no login
Latest posts from any public Threads profile. Text, likes, replies, reposts, quotes and timestamps. No login, no app password, no API key.
What it does
- Monitor Threads profiles for new posts
- Export Threads posts to JSON or CSV
- Track Threads engagement metrics
- Watch competitor and creator accounts on Threads
Pass many profiles in one run. Every row is tagged with its source profile.
Scope — read this before running
Threads only exposes a recent window per profile, typically 5 to 15 posts. Deeper history is not available without an authenticated session, so this actor does not offer it and does not pretend to.
That makes it a monitoring tool, not an archive tool. It is built for
running on a schedule across many profiles: set since to your last run and
each run returns only what is new. If you need a profile's full back catalogue,
this is not the right tool.
Why it works where simpler scrapers do not
Threads serves a stripped page to standard HTTP clients — 265 KB with no post data, versus 874 KB with it. This actor uses browser TLS fingerprinting to receive the full payload, which is why it returns posts when plain scrapers return nothing.
Honest failure reporting
Unavailable profiles and misspelled handles return a row with a reason and cost you nothing. You are only charged for posts actually delivered.
Input
| Field | Required | Description |
|---|---|---|
profiles | yes | Handles or threads.net URLs |
maxPostsPerProfile | no | Default 25. Your cost ceiling. |
since | no | ISO date. Only newer posts — ideal for scheduled runs. |
proxy | no | Optional, for spreading load across many profiles |
Example input
{"profiles": ["@zuck", "mosseri"],"since": "2026-08-25"}
Output
Every row has the same fields whether it succeeded or failed, so you can select columns without branching. Failed rows are never charged.
| Field | Type | Description |
|---|---|---|
success | boolean | True when this row carries data. Failed rows are never charged. |
sourceProfile | string | The profile input this row came from. |
postUrl | string | Public threads.net link to the post. |
postId | string | Threads' numeric post identifier. |
shortcode | string | Short code used in the post URL. |
authorHandle | string | Handle of the profile that posted. |
authorId | string | Stable profile identifier. |
text | string | The post body. |
publishedAt | string | ISO 8601 timestamp of publication. |
likeCount | integer | Likes at the time of the run. |
replyCount | integer | Replies at the time of the run. |
repostCount | integer | Reposts at the time of the run. |
quoteCount | integer | Quote posts at the time of the run. |
hasMedia | boolean | True when the post includes an image or video. |
errorCode | string | Machine-readable failure reason. Null on success. |
errorMessage | string | Human-readable explanation of the failure. Null on success. |
Example — success
{"success": true,"sourceProfile": "@zuck","postUrl": "https://www.threads.net/@zuck/post/C1aBcDeFgHi","postId": "3141592653589793","shortcode": "C1aBcDeFgHi","authorHandle": "@zuck","authorId": "314159","text": "Testing a few new things in the app this week.","publishedAt": "2026-08-14T09:12:04.000Z","likeCount": 48210,"replyCount": 3112,"repostCount": 884,"quoteCount": 127,"hasMedia": true,"errorCode": null,"errorMessage": null}
Example — failure
A failure carries the same fields, so nothing downstream has to branch.
{"success": false,"sourceProfile": "@private_example","postUrl": null,"postId": null,"shortcode": null,"authorHandle": null,"authorId": null,"text": null,"publishedAt": null,"likeCount": null,"replyCount": null,"repostCount": null,"quoteCount": null,"hasMedia": null,"errorCode": "profile-unavailable","errorMessage": "No public Threads profile exists for this handle, or it is private."}
Error codes
profile-unavailableunparseable-handleno-posts-founderror
Use it for
- Threads profile posts — a public profile's timeline
- Meta Threads monitoring — scheduled runs with a since filter
- Social listening, brand and competitor tracking
- Research corpora and training datasets
Use it from an AI agent (MCP)
This Actor is callable as a tool through the Apify MCP server, so Claude, ChatGPT, Cursor and VS Code can run it directly.
Add the server to your MCP client:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com","headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
Then ask for what you want in plain language — for example “get the recent posts from this Threads profile” — and the agent calls cleanfeed/meta-threads-posts-scraper with the right input. Every output field is described in the dataset schema, so the agent knows what it is getting back before it runs anything.
Call it from code
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("cleanfeed/meta-threads-posts-scraper").call(run_input={"profiles": ["https://www.threads.net/@zuck"],})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item["success"]:print(item)
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('cleanfeed/meta-threads-posts-scraper').call({profiles: ["https://www.threads.net/@zuck"],});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.filter((i) => i.success));
cURL
curl -X POST "https://api.apify.com/v2/acts/cleanfeed~meta-threads-posts-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H 'Content-Type: application/json' \-d '{"profiles": ["https://www.threads.net/@zuck"]}'
Related actors
| If you need | Use |
|---|---|
| Posts from public Bluesky accounts | Bluesky Posts Scraper |
| Messages from public Telegram channels | Telegram Channel Scraper |
Limitations
- Public profiles only. Private profiles return
errorCode: profile-unavailable. - Threads exposes only a recent window — typically 5 to 15 posts per profile. There is no full history to page through, so
maxPostsPerProfileabove that returns what exists rather than erroring. - Because the window is short, scheduled runs with
sinceare the reliable way to build history over time.
FAQ
Do I need a Threads or Instagram login?
No login and no app password. Only public profiles are read.
Why do I only get 5 to 15 posts?
That is the window Threads exposes publicly. There is no deeper history to page through, so asking for more returns what exists rather than erroring.
How do I build a longer history then?
Run on a schedule with since. Each run adds what is new, and over time you accumulate the history the platform will not serve in one request.
What profile formats work?
An @handle or a threads.net profile URL.
Can I read private profiles?
No. Those return errorCode: profile-unavailable.
Notes
Only publicly visible posts are collected. No login, no private data.