Threads Scraper: Posts, Threads Replies, Profile Scraper, API
Pricing
from $1.00 / 1,000 posts
Threads Scraper: Posts, Threads Replies, Profile Scraper, API
Meta Threads scraper API, no login: threads posts by link, a profile's posts with exact counts and views, threads replies and comment trees, a threads search scraper for keywords and tags, threads profiles with the exact follower count. One row per post, reply or profile; free rows for misses.
Pricing
from $1.00 / 1,000 posts
Rating
0.0
(0)
Developer
Hyperbach
Maintained by CommunityActor stats
0
Bookmarked
6
Total users
5
Monthly active users
3 days ago
Last modified
Categories
Share
Threads (Meta) data without a login: profiles with the exact follower count, a profile's posts to the end of its list, posts by link or code with their view count, replies to the end of the list with nested conversations, keyword and tag search — one row per post or profile, every count exact, and a free row that says why for an input that names nothing. Run it on a schedule with onlyNew and each run delivers only the posts no earlier run delivered (monitor accounts for new posts). No account, no cookie, no browser, proxies handled for you.
Why this Threads scraper
- Exact counts, every row, null where Threads withholds. Likes, replies, reposts, quotes and shares are the exact integers Threads serves (1,841 / 318 / 153 / 32 / 89 on our reference post, equal to the lane leader's row); the view count comes free on every post you name and on request for list rows; a count Threads does not give is null, never 0. In our test of the lane, actors wrote zeros for missing counts, rounded followers, or delivered Instagram's profile as Threads'.
- Profile history to the end of the list. A profile's Threads tab is read with Threads' own paging to the list's end (168 of the 168 shown threads in our test; 1,400+ for a busy account), newest first, with
postedAfterto stop at a date; the profile row carries the exact follower count, the shown threads count, bio, links, tags and the linked Instagram account. - Replies as a conversation. Replies under a post you name are read to the end of what Threads serves a visitor (250 of a post's 318 in our test; the row says how many and why), in Top or Recent order, with
includeNestedRepliesfor the conversations under each reply; every reply row carries its level, its parent and the root post. A walk Threads rate-limits says so on the post row and in the run summary. - One run, any mix, one row per entity. Usernames, profile links, post links and codes on threads.com or threads.net, keywords and #tags in one run; the same post given three ways is one row; a post that is also found on a profile tab or a search page is one row; every input that names nothing comes back as a free row that says why (not found, invalid, empty, duplicate).
- Search that says what it matched. Threads shows a visitor one page per surface (about 20 posts on Top, 20 under the topic tag), no Recent sort and no date window: the rows say so, every search row is flagged
keyword_match, andkeywordMatchOnlyleaves the off-keyword rows out before the charge.searchPassesloads a page again for the posts Threads rotates in (a second load added 43 posts to 58 for starbucks and #coffee in our test), and theaccountssurface gives the accounts Threads' search box offers, as exact profiles. - Built for schedules.
onlyNewdelivers only posts no earlier run delivered; with the memory on, a profile row says how its followers moved since the last run and a post read again carries its engagement change. Filters before the charge:minLikes,verifiedOnly. - Light and fast. Plain HTTP, no browser: about 2 KB of traffic per profile post, 4.5 KB per reply; 131 rows in 14 seconds and 250 replies in 48 seconds on one exit in our test, from datacenter IPs.
Who it's for
- Marketers and brand teams — what Threads says about a brand or a topic today: keyword and tag search with the match flag, the replies under a post with their authors, the exact engagement of a creator's recent posts.
- Researchers and analysts — a profile's full post history with exact counts and times, replies as threaded conversations with levels and parents, media and link URLs, in one typed row shape.
- Monitoring teams — a scheduled list of profiles or keywords that delivers only what is new, with the follower change and the engagement change since the last run.
- Developers and agents — typed fields, one row per input in input order, a free labelled row for every miss, and a run summary with a stop reason per input to check a pipeline against.
Quick start
A profile with its newest posts
{"profiles": ["zuck"],"maxPostsPerProfile": 25}
Posts by link or code, with views
{"posts": ["https://www.threads.com/@zuck/post/DdZ7sQvkTFn","Dd1MqfcG0aH"]}
A post with its replies and the conversations under them
{"posts": ["https://www.threads.com/@zuck/post/DdZ7sQvkTFn"],"maxRepliesPerPost": 300,"includeNestedReplies": true}
Keyword and tag search, matches only
{"keywords": ["superintelligence","#ai"],"searchSurfaces": ["top","tags"],"keywordMatchOnly": true}
A profile's whole history with views
{"profiles": ["threads"],"maxPostsPerProfile": 1000,"includeViews": true}
A daily monitor: new posts only
{"profiles": ["zuck","threads"],"maxPostsPerProfile": 50,"onlyNew": true,"stateStoreName": "my-threads-watch"}
Output
Two row types share one dataset (row_type says which): post (a post, a reply, a search hit) and profile:
| field | meaning |
|---|---|
row_type | profile or post: which columns of the row are filled. |
input | The value you gave that this row answers (the first form, when the same post or profile was given several ways); on a search row the keyword; on a reply row the post you named. |
input_index | The 1-based position of the input in its list (profiles, posts or keywords). |
inputs_merged | Other forms of the same post or profile you gave (a code and a link of one post), merged into this row. |
source_kind | Where the row came from: post (a post you named), replies / nested_replies (under a post you named), profile_threads / profile_replies / profile_reposts (a profile's tab), search_top / search_tags (a search surface), search_accounts (an account Threads' search box offered for a keyword), profile (a profile you named), author (an author's profile with includeAuthorProfiles). |
status | ok = a delivered record; not_found, invalid, empty, failed, duplicate = a free row that says why there is no record for this input. |
status_detail | Why a row is not ok, in words. |
scraped_at | When this row was read (UTC). |
post_code | The post's 11-character code, as in its link (DdZ7sQvkTFn). |
post_id | Threads' numeric id of the post, as a string. |
post_url | The post's link on threads.com. |
created_at | When the post was published (UTC, to the second). |
created_at_timestamp | The same moment as a Unix timestamp (seconds). |
text | The post's full text, as written (empty on a media-only post). |
text_length | Characters in text. |
media_type | text, image, video, carousel, or repost (a reposting item of the reposts tab: the post itself is in reposted_post). |
media | One object per picture or video of the post (every carousel slide): type, url (the largest rendition), width, height; a video adds has_audio and cover_url (its cover image). |
image_urls | The post's pictures, largest rendition URLs. |
video_urls | The post's videos (MP4 URLs; signed, they expire). |
media_count | How many pictures and videos the post has. |
gif_url | The GIF's own URL where Threads serves it; null when a visitor gets only Threads' placeholder image (every GIF of a logged-out read: accessibility_caption names the GIF). |
has_audio | The post's video has an audio track. |
accessibility_caption | The alt text Threads generated for the media. |
links | The links in the text (the real targets, unwrapped from Threads' redirector). |
mentions | The @users named in the text. |
stickers | The inline stickers of the text, as image URLs. |
topic_tag | The post's topic tag, when the author set one (Threads has one tag per post, not hashtags). |
link_preview | The link card under the post: title, url (unwrapped), display_url, description, image_url, favicon_url. |
like_count | Likes, exact. |
reply_count | Replies, exact, as Threads counts them (more than a visitor is served; see replies_note). |
repost_count | Reposts, exact. |
quote_count | Quotes, exact. |
share_count | Shares (reshares), exact; null where Threads sends none: on every reply, and on posts it shows no share count for (22 of 40 profile posts in our test; the post's own page sends null for them too). |
view_count | Views, exact, when read: always on a post you named; on list rows with includeViews; else null (never 0). |
views_source | page (the view count came with the post's own page, free) or fetched (read for this row with includeViews, charged as post_views); null when no count was read. |
engagement_rate | (likes + replies + reposts + quotes) ÷ the author's followers, when the followers are known (a profile's own posts; includeAuthorProfiles). |
is_reply | The post is a reply to another post. |
reply_to_username | The author the post replies to. |
reply_to_user_id | That author's Threads id. |
parent_post_code | On a reply row: the code of the post it answers (the post you named for a direct reply, the parent reply for a nested one); on a post you named that is itself a reply: its parent. |
root_post_code | On a reply row: the code of the post you named; on a reply you named: the root of its conversation. |
reply_level | 0 = a top-level post; 1 = a direct reply to the root; 2 and deeper = a nested reply. |
is_quote | The post quotes another post. |
quoted_post | The quoted post, in short: code, url, author, text, created_at, the five counts. |
is_repost | The row is a repost (the reposts tab). |
reposted_post | The reposted post, in short: code, url, author, text, created_at, the five counts. |
thread_id | The id of the thread the post belongs to on a tab or search page: the posts of one self-thread (a multi-post thread by one author) share it. |
thread_position | The post's position in its thread (0 = the first post). |
self_thread_count | How many posts the author's self-thread has on a tab or search page (the posts sharing thread_id by the thread's author); null on a post read alone. |
is_pinned | The post is pinned to its author's profile. |
is_edited | The post was edited. |
is_paid_partnership | The post is labelled a paid partnership. |
is_spoiler | The media is marked as a spoiler. |
reply_control | Who may reply, as the author set it (everyone, …). |
ai_label | Threads' AI-generated label on the post, where it shows one. |
author_username | The author's username. |
author_id | The author's Threads id (not the Instagram id). |
author_name | The author's display name. |
author_verified | The author is verified. |
author_profile_pic_url | The author's profile picture. |
author_is_private | The author's profile is private. |
author_followers | The author's exact follower count, when read this run (a profile's own posts; includeAuthorProfiles). |
query | On a search row (a post or an account the search found): the keyword or tag this row was found for. |
search_surface | On a search row: top, tags or accounts. |
search_tag | On a Tags-surface row: the topic tag Threads matched, when the page named it. |
keyword_match | On a search row: the keyword appears in the text, the topic tag, the quoted post or the author's names (Threads' Top surface ranks related posts too). |
list_note | What the list this row came from shows a visitor (one page per search surface; the first page of the replies and reposts tabs). |
replies_requested | On a post you named: maxRepliesPerPost. |
replies_delivered | On a post you named: how many reply rows were delivered under it. |
replies_note | Why fewer replies than requested were delivered (the list's end, with the post's own count; a stop). |
related_posts | On a post you named: the posts Threads shows under it as related (code, username, url). |
previous_read_at | With the memory on: when this post or profile was last delivered by an earlier run. |
engagement_change | With the memory on, on a post read again: the change of the five counts since the last delivered read (like_count, reply_count, repost_count, quote_count, view_count). |
raw | Threads' own object behind the row, with includeRaw. |
run_tag | Your runTag, copied onto every row. |
username | The profile's username. |
user_id | The profile's Threads id (not the Instagram id), as a string. |
full_name | The display name. |
biography | The bio, full. |
bio_links | The links in the bio (unwrapped). |
is_verified | The profile is verified. |
is_private | The profile is private (its posts are not shown to a visitor). |
profile_pic_url | The profile picture. |
profile_pic_hd_url | The largest profile picture Threads serves. |
follower_count | Followers, exact. |
threads_count | The profile's threads count as the page shows it, when it is a plain number (168); null when Threads rounds it (1.2K, kept in threads_count_shown). |
threads_count_shown | The threads count as shown (168, 1.2K). |
profile_tags | The profile's interest tags (AI, MMA, …). |
profile_url | The profile's link on threads.com. |
instagram_url | The linked Instagram account (a Threads account is its Instagram account of the same username). |
podcast_name | The podcast the profile links, where it shows one. |
podcast_url | The podcast's link. |
tab | The tabs read for this profile's posts (threads, replies, reposts, comma-separated). |
posts_requested | maxPostsPerProfile × the tabs read. |
posts_delivered | How many post rows were delivered for this profile. |
posts_note | Why fewer posts than requested were delivered (the list's end with the shown count, postedAfter, onlyNew, the filters, a tab's first page); on an account-search row, what the search box offers. |
last_post_at | The newest post's time among the Threads-tab posts read (pinned posts aside). |
recent_posts_read | How many Threads-tab posts the averages below are over. |
recent_avg_likes | Average likes over those posts. |
recent_avg_replies | Average replies over those posts. |
followers_previous | With the memory on: the follower count as last delivered by an earlier run. |
followers_change | With the memory on: follower_count minus followers_previous. |
Example record:
{"row_type": "post","input": "https://www.threads.com/@zuck/post/DdZ7sQvkTFn","input_index": 1,"inputs_merged": ["https://www.threads.net/@zuck/post/DdZ7sQvkTFn","DdZ7sQvkTFn"],"source_kind": "post","status": "ok","status_detail": null,"scraped_at": "2026-10-10T00:02:13Z","post_code": "DdZ7sQvkTFn","post_id": "3988481471392330087","post_url": "https://www.threads.com/@zuck/post/DdZ7sQvkTFn","created_at": "2026-09-17T22:27:44Z","created_at_timestamp": 1789684064,"text": "Muse for Mac is out today! It works across apps, files, calendar, notes, and messages on your computer. You control what it can access. The team is shipping fast. Download at ai.meta.com/muse/download","text_length": 200,"media_type": "text","media": null,"image_urls": null,"video_urls": null,"media_count": 0,"gif_url": null,"has_audio": null,"accessibility_caption": null,"links": ["http://ai.meta.com/muse/download"],"mentions": null,"stickers": null,"topic_tag": null,"link_preview": null,"like_count": 1841,"reply_count": 318,"repost_count": 153,"quote_count": 32,"share_count": 89,"view_count": 157870,"views_source": "page","engagement_rate": null,"is_reply": false,"reply_to_username": null,"reply_to_user_id": null,"parent_post_code": null,"root_post_code": null,"reply_level": 0,"is_quote": false,"quoted_post": null,"is_repost": false,"reposted_post": null,"thread_id": null,"thread_position": null,"self_thread_count": 0,"is_pinned": false,"is_edited": false,"is_paid_partnership": false,"is_spoiler": false,"reply_control": "everyone","ai_label": "{\"detection_method\": \"NONE\"}","author_username": "zuck","author_id": "63055343223","author_name": "Mark Zuckerberg","author_verified": true,"author_profile_pic_url": "https://scontent-phl2-1.cdninstagram.com/v/t51.82787-19/825322135_17989325280103224_1252773933700107438_n.jpg?stp=dst-jpg_s206x206_tt6&_nc_cat=107&ccb=7-5&_nc_sid=30ff31&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDgwLkMzIn0%3D&_nc_ohc=l7qeCXGmYHsQ7kNvwEFTVOn&_nc_oc=Adrf5-GaepFVtOPnPzNV5nLDWB-LX9x8r8A6YILbQNSGbvG-aisMvjRHoOvot8g78Ic&_nc_zt=24&_nc_ht=scontent-phl2-1.cdninstagram.com&_nc_gid=keE14ec5-x7nR_U-ifJgyQ&_nc_ss=7b289&oh=00_AQPz-ardxL9MjFDRJ_BfQjidx99SBVd3XeRT0kPhBq-J2w&oe=6ACF40EB","author_is_private": false,"author_followers": null,"query": null,"search_surface": null,"search_tag": null,"keyword_match": null,"list_note": null,"replies_requested": 20,"replies_delivered": 20,"replies_note": null,"related_posts": [{"code": "DdaWHdskkU3","username": "eastmel","url": "https://www.threads.com/@eastmel/post/DdaWHdskkU3"},{"code": "DdaoIYUgrJS","username": "elek7817","url": "https://www.threads.com/@elek7817/post/DdaoIYUgrJS"},{"code": "DdapXchIy7g","username": "thisiskhoagates","url": "https://www.threads.com/@thisiskhoagates/post/DdapXchIy7g"},{"code": "DddicpMjx7A","username": "luxury_maldives_voyage","url": "https://www.threads.com/@luxury_maldives_voyage/post/DddicpMjx7A"},{"code": "Ddg8OiciPQ0","username": "zurck53","url": "https://www.threads.com/@zurck53/post/Ddg8OiciPQ0"}],"previous_read_at": null,"engagement_change": null,"raw": null,"run_tag": null,"username": null,"user_id": null,"full_name": null,"biography": null,"bio_links": null,"is_verified": null,"is_private": null,"profile_pic_url": null,"profile_pic_hd_url": null,"follower_count": null,"threads_count": null,"threads_count_shown": null,"profile_tags": null,"profile_url": null,"instagram_url": null,"podcast_name": null,"podcast_url": null,"tab": null,"posts_requested": null,"posts_delivered": null,"posts_note": null,"last_post_at": null,"recent_posts_read": null,"recent_avg_likes": null,"recent_avg_replies": null,"followers_previous": null,"followers_change": null}
Pricing
Pay only for the rows a run delivers, with no start fee and no platform usage billed to you. Prices fall with your Apify plan.
| per 1,000 | Free | Starter | Scale | Business |
|---|---|---|---|---|
Post (post) | $2.00 | $1.60 | $1.40 | $1.00 |
Profile (profile) | $4.00 | $3.40 | $2.80 | $2.00 |
Reply (reply) | $2.00 | $1.70 | $1.40 | $1.00 |
View count (list rows) (post_views) | +$1.60 | +$1.36 | +$1.12 | +$0.80 |
A post is $2.00 per 1,000 on the Free plan and $1.00 on Business; a post you name by link or code carries its view count at no extra charge. The + fee is charged only on a list row that carries a view count read with includeViews ($1.60 per 1,000 on Free). A profile row is charged per profile, a reply row per reply (nested replies included). An input that names nothing (not found, invalid, empty, a duplicate) is a free row that says why; so is a run that failed. maxItems counts every charged row; before the first request the log says the most the run can cost at your plan's prices. Enterprise plans have their own rates — the Actor's Pricing tab shows the price for your plan.
Usage patterns
- Profiles — Paste usernames or profile links in
profiles. Each gives oneprofilerow (the exact follower count, the shown threads count, bio, links, tags, picture, the linked Instagram account) and up tomaxPostsPerProfilepostrows from the tabs inprofileTabs(threadsby default;repliesandrepostsgive their first page, about 30 posts, which is all Threads shows a visitor). The Threads tab is read newest first to the list's end;postedAfterstops it at a date. The replies tab gives the account's own replies, each with the code of the post it answers (parent_post_code). The profile row says how many posts were delivered and why fewer, when fewer (posts_note), and carries the newest post's time and the recent averages. WithmaxPostsPerProfile0 a run gives the profile rows only (exact follower counts for a list of accounts);includeProfileRowoff gives the posts only (image and video URLs from an account's posts). - Posts and replies — Paste post links or codes in
posts. Each gives onepostrow with its five exact counts and its view count (free: the post's own page carries it), media, links, mentions, the quoted or reposted post, the related posts, and — for a post that is itself a reply — its parent and root.maxRepliesPerPostadds the replies under it aspostrows (source_kindreplies,reply_level1), in Top or Recent order, to the end of what Threads serves a visitor;includeNestedRepliesadds the conversations under each reply (reply_level2 and deeper,parent_post_codethe reply answered). The post row says how many replies were delivered and why fewer than Threads' count (replies_note), including when Threads rate-limited the walk (the post is then listed in the run summary'spartial_inputs). Example: the replies to a post, with nested conversations. - Search — A keyword in
keywordsreads the Top surface (about 20 posts, the page a visitor sees);searchSurfacesadds the Tags surface andaccounts(the accounts Threads' search box offers for the keyword, up to 10, each an exact profile row charged as a profile); a#tagreads the Tags surface for that tag. Every search row names its keyword (query) and surface (search_surface). Threads shows a visitor one page per surface, no Recent sort and no date window:list_notesays so on every post row,keyword_matchsays whether the keyword is in the text, the topic tag, the quoted post or the author, andkeywordMatchOnlyleaves the rest out before the charge. The page changes between loads:searchPassesloads it again on fresh exits and adds the posts not seen yet, each charged once (a second load added 43 posts to 58 for starbucks and #coffee; 6 loads added 5 to 21 for a rare word). Examples: posts, tags and accounts for a keyword, popular posts that mention a keyword. - Views, authors, filters —
includeViewsreads the view count of every profile post, search hit and reply (one small request per row, charged aspost_views);includeAuthorProfilesadds one exactprofilerow per author and putsauthor_followersandengagement_rateon the post rows;includeRawkeeps Threads' own object on each row.minLikesandverifiedOnlyleave list rows out before the charge; a post you name is always delivered. Example: posts with view counts and engagement rate. - A schedule — Save a task with your profiles or keywords and
onlyNew, and schedule it: each run reads the newest posts and delivers only those no earlier run of the task delivered; a post skipped this way is free, so a run with nothing new costs the profile rows only. The caps bound the depth read, so a daily run withmaxPostsPerProfile50 reads the same newest 50 every day.stateStoreNamenames the memory; with it, profile rows carryfollowers_previousandfollowers_change, and a post read again carriesengagement_change. Example: monitor accounts for new posts.
Input configuration
| field | type | default | what it does |
|---|---|---|---|
profiles | array | [] | Threads profiles, one per line, in any form: zuck, @zuck, https://www.threads.com/@zuck, https://www.threads.net/@zuck, or a tab link such as https://www.threads.com/@zuck/replies. Each gives one profile row (the exact follower count, bio, links, tags, the shown threads count) and up to maxPostsPerProfile post rows from the tabs in profileTabs. The same user given several ways is one row. A value that is not a Threads profile comes back as a free row that says why. |
posts | array | [] | Threads posts, one per line: https://www.threads.com/@zuck/post/DdZ7sQvkTFn, the same on threads.net, https://www.threads.com/t/DdZ7sQvkTFn, or the 11-character code DdZ7sQvkTFn. Each gives one post row with its five exact counts and its view count, and up to maxRepliesPerPost post rows of replies. One row per post: the same post given several ways is one row. A post that does not exist is a free row that says so. |
keywords | array | [] | Search terms, one per line. A word or phrase reads the Top surface (about 20 posts, the page a visitor sees; searchSurfaces adds the Tags surface and the accounts the search box offers); #tag reads the Tags surface for that tag; a search link https://www.threads.com/search?q=…&serp_type=tags is read as given. Threads shows a visitor one page per surface, no Recent sort and no date window: every row says so (list_note) and whether it holds the keyword (keyword_match). |
maxPostsPerProfile | integer | 25 | How many posts to read for each profile, newest first, from each tab in profileTabs; 0 = the profile row only. The Threads tab is read to the list's end (168 of 168 shown in our test, 1,400+ for a busy account); the replies and reposts tabs give their first page (about 30 posts, all Threads shows a visitor). With onlyNew or the filters, fewer rows are delivered than read: the cap bounds the depth, so a scheduled run reads the same newest posts every time. |
profileTabs | array | [] | Which tabs of each profile to read for its posts; empty = threads. A tab given in a profile link (…/@zuck/replies) applies to that profile. Needs maxPostsPerProfile above 0. |
postedAfter | string | "" | A UTC date (2026-10-01) or time (2026-10-01T12:00:00Z): on the Threads tab, the walk stops at the first post older than this (pinned posts excepted), so a scheduled run reads only the recent posts. Empty = no date floor. Search has no date window (Threads shows a visitor none). |
includeProfileRow | boolean | true | Deliver each profile's own row (exact followers, bio, links; charged as a profile) with its posts. Off: the posts only, so 10 posts asked are 10 charged rows (the posts still carry the author's follower count from the profile page). A profile asked with maxPostsPerProfile 0 always gives its row. |
maxRepliesPerPost | integer | 0 | How many replies to read under each post in posts, as post rows with reply_level, parent_post_code and root_post_code; 0 = the post row only. Read to the list's end: Threads serves a visitor most but not all of a post's replies (231 + 33 nested of 318 in our test), and the post row says how many (replies_note). With the filters, fewer rows are delivered than read. |
repliesOrder | top / recent | "top" | The order Threads lists the replies in. |
includeNestedReplies | boolean | false | Also read the conversation under each reply that has replies (one request per such reply), as post rows with reply_level 2 and deeper. Counted in maxRepliesPerPost. |
searchSurfaces | array | [] | The surfaces read for each plain keyword, one page each; empty = top. A #tag keyword always reads the Tags surface. A post found on both surfaces is one row. accounts gives the accounts Threads' search box offers for the keyword (up to 10), each as an exact profile row charged as a profile. |
searchPasses | integer | 1 | How many times to load each post surface of a keyword. Threads gives a visitor one page with no cursor, but the page changes between loads: each pass after the first loads it again on a fresh exit and adds the posts not seen yet, charged once (a second pass added 43 posts to 58 for starbucks and #coffee; 6 passes added 5 to 21 for a rare word). 1 = the page a visitor sees. |
maxPostsPerKeyword | integer | 0 | The most posts read per keyword over its post surfaces (0 = every post of the pages read: about 20 a surface), and the most accounts from the accounts surface. With keywordMatchOnly, onlyNew or the filters, fewer rows are delivered than read. |
keywordMatchOnly | boolean | false | Deliver only the search rows whose text, topic tag, quoted post or author holds the keyword (keyword_match true). Threads' Top surface ranks related posts too (about half hold the word in our test); off, every row is delivered with its flag. |
includeViews | boolean | false | Read the view count of every profile post, search hit and reply (one request per row: Threads serves views only on a post's own page). A post you name in posts carries its views at no extra cost. Charged per row that gets one (post_views). |
includeAuthorProfiles | boolean | false | One exact profile row per distinct author of the posts delivered (the exact follower count; one small request per author), charged as a profile; the post rows then carry author_followers and engagement_rate. Every post row already carries the author's username, id, name, verification and picture. |
includeRaw | boolean | false | Keep Threads' own JSON object on each row (raw), for fields this Actor does not name. |
minLikes | integer | 0 | Leave out profile posts, search hits and replies with fewer likes than this; 0 = no floor. A post you name in posts is always delivered. |
verifiedOnly | boolean | false | Keep only list rows whose author is verified. |
onlyNew | boolean | false | Deliver only posts no earlier run of the same task delivered (profile tabs and search rows); turns the memory on. With the memory on, a profile row says how its followers moved since the last run and a post read again carries its engagement change. |
stateStoreName | string | "" | Name of the memory between runs. Given, it turns the memory on: profile rows get followers_previous and followers_change, post rows read again get engagement_change; with onlyNew, posts delivered before are skipped. Empty = derived from the inputs when onlyNew is on. |
maxItems | integer | 0 | The most charged rows this run delivers, profiles, posts and replies together. 0 = no limit. Free rows (not found, invalid, empty, duplicate) do not count. |
proxyUrl | string | http://user:pass@host:port — a proxy of yours to read Threads through, tried before the Actor's own exits. Leave empty: the Actor brings its own. | |
runTag | string | "" | A label copied onto every row (run_tag), to tell runs apart in a shared dataset. |
Errors
A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:
- the status message starts with
INPUT REJECTED; - the dataset holds one row,
{"error": true, "code": "…", "message": "…"}, and no results; - the key-value store record
ERRORholds the same object.
From code, check error on the first row before reading results.
A search that matches nothing is not an error: the dataset is empty and nothing is charged. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.
FAQ
Can it read Recent search results, search by date, or the followers, following and likers of an account?
No: these need a login. Threads' own page router strips the Recent filter and the date parameters from a visitor's search, and the follower, following and liker lists open only to a logged-in account; the actors that sell them use a login, their own or your session. This Actor does not log in or take a cookie, and the rows say what the source served (list_note). What a visitor does get: one page of Top and Tags results per keyword (more with searchPasses), the accounts the search box offers (searchSurfaces accounts), a profile's posts to the end of its list, and the replies to a post with their conversations.
Are the counts exact?
Yes: every count on every row is the exact integer Threads serves, equal to the counts a logged-in user sees. The view count is on every post you name (free) and on list rows with includeViews; where no count was read it is null, never 0. The profile's threads count is exact when Threads shows a plain number and null (with the shown text) when Threads rounds it.
Why are fewer replies delivered than the post's reply count?
Threads serves a visitor most but not all of a post's replies: on our reference post it served 250 of 318 (the rest are hidden, deleted or from private accounts). The post row's replies_note says how many were served and that the list ended; includeNestedReplies adds the conversations under each reply. When Threads rate-limited calls of the run, the note says so and the run summary lists the post under partial_inputs: a quieter read may serve more (in our test the same walk on a second exit served no reply the first had missed, 148 of 148).
What is charged?
Delivered rows: a profile, a post (a post you named, a profile's post, a search hit), a reply, and the post_views add-on on a list row whose view count was read for it. Rows for inputs that name nothing (not found, invalid, empty, duplicate), posts onlyNew skips or the filters leave out, and a run that failed before its first row are free; a run that stops early (a timeout, an abort) is charged for the rows it delivered. maxItems caps every charged row together.
Does it need a proxy or a Threads account?
No. The Actor brings its own exits (datacenter IPs are served) and reads Threads as a visitor; proxyUrl lets you put a proxy of your own in front.
Can an AI agent use it (MCP)?
Yes. Apify's MCP server (https://mcp.apify.com) offers Store Actors as tools to Claude, Cursor and other MCP clients: add this Actor and the agent sends profiles, posts or keywords and gets the rows back. The synchronous API (run-sync-get-dataset-items) does the same in one HTTP call.
Integration
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('hyperbach/threads-scraper').call({"profiles": ["zuck"], "maxPostsPerProfile": 25});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python
from apify_client import ApifyClientclient = ApifyClient('YOUR_TOKEN')run = client.actor('hyperbach/threads-scraper').call(run_input={'profiles': ['zuck'], 'maxPostsPerProfile': 25})items = client.dataset(run['defaultDatasetId']).list_items().items
CLI
$apify call hyperbach/threads-scraper --input '{"profiles": ["zuck"], "maxPostsPerProfile": 25}'
REST
curl -X POST "https://api.apify.com/v2/acts/hyperbach~threads-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H 'Content-Type: application/json' -d '{"profiles": ["zuck"], "maxPostsPerProfile": 25}'
Support
This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.