Threads Scraper: Posts, Profiles, Replies & Search
Pricing
from $0.09 / 1,000 results
Threads Scraper: Posts, Profiles, Replies & Search
Scrape Threads without login: full post history of any public profile, profile data with follower count, replies under any post, keyword and topic search. Date filters, monitoring of new posts. Export to JSON, CSV or Excel.
Pricing
from $0.09 / 1,000 results
Rating
0.0
(0)
Developer
Nice Dev
Maintained by CommunityActor stats
0
Bookmarked
18
Total users
10
Monthly active users
9 hours ago
Last modified
Categories
Share
🧵 What is Threads Scraper?
Threads Scraper extracts posts, profiles, replies and search results from Threads, Meta's text network: the full post history of any public account, its profile with follower count, the replies under any post, and the posts a keyword or topic search shows — with likes, replies, reposts, quotes, media, links, polls and mentions on every post.
Type a few usernames (nasa), paste post URLs or a keyword, click Start, and download the results in JSON, CSV or Excel. No login, nothing to set up. About 1,000 posts in 3 minutes.
📋 What data can you extract from Threads?
One item per post or profile, 114 fields:
| Category | What you get |
|---|---|
| 📝 Post | text, link, date to the second, language, edited or not — Happy equinox, Earthlings! 🍂 |
| 📊 Engagement | likes, replies, reposts, quotes, shares — 2 234 likes, 44 replies; views of a post read by its URL — 161,167 views; a ready-made engagement rate (interactions per view, or per follower when a post has no views) |
| 🖼️ Media | every photo and video of the post (carousels included), alt text, video length, available resolutions and audio file, GIF, stickers, music and podcast shared — title, artist, episode, link |
| 🔗 Links and mentions | links of the text and of the link card (real target, no redirect), mentioned accounts, hashtags, topic |
| 🗳️ Polls | every option with its votes, total votes, closed or not, end date |
| 💬 Conversations | who the post answers, the text and link of that post, depth in the thread, place of a post in its author's thread and the posts Threads recommends next to it (post read by its URL), quoted post, reposts |
| 👤 Author | username, name, verified badge, picture, profile link, follower count, bio, e-mails and phone numbers of the bio, and on request those found on the website the author cites in the bio |
| 🪪 Profile | name, bio, links, e-mails and phone numbers written in the bio, followers, verified, private, topics |
| 📁 Extras (optional) | your own copy of the photos and videos of the posts, and the contacts found on the websites of the authors — media-3905-1.jpg · hello@acme-shop.fr |
| 🤖 AI (optional) | an AI sentiment label (positive, neutral or negative, with a score) and your own AI labels (the ones you wrote that apply to the post, with a score) — negative, 0.91 · pricing, 0.82 |
Every field, with an example, is listed in the Output section below.
✅ Why use Threads Scraper?
- 💸 Cheap: $0.17 per 1,000 results, down to $0.088 on paid Apify plans — proxy and platform usage included.
- ⚡ Fast: about 1,000 posts in 3 minutes and 4,000 in 10 minutes from one account, with the default settings.
- 📜 The whole history of an account: every post back to the account's first one — or stop at a date with Posted after (very long histories: see Known limitations).
- 💬 Replies included: the replies under any post, sorted as Threads shows them (Top) or newest first, with their depth in the conversation — in the same run as the posts.
- 🧩 Everything in one run: accounts, their replies and reposts, single posts, keywords and topics together; a post found by several of them is saved once.
- 🔔 Monitoring built in: tick Only new posts, schedule the Actor, and each run returns (and charges) only the posts it never delivered before.
- 🤖 What they think: tick AI sentiment label for a positive / neutral / negative label on each post, and write AI labels (
pricing,complaint: The author reports a problem) to see which of your topics each post is about. - 📁 Photos and videos that do not expire: the media links Threads gives are signed and stop working. Tick Download photos and videos and each file is kept in your run's key-value store, with a link on the row.
- 📊 A summary of each search: tick Keyword statistics and the key-value store gets a
KEYWORD_STATSrecord: posts per day, average and median likes, top hashtags, authors and posts of each keyword and topic you searched. - 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON / CSV / Excel export via the Apify platform.
🚀 How to scrape Threads
- Create a free Apify account.
- Open Threads Scraper and type one or more Usernames (e.g.
nasa). - Or paste Post URLs to get posts with their replies, or type a Search keyword, or paste any Threads profile, post or search URL into Threads URLs.
- Set Max results (100 by default, 0 = no limit) — and Max posts per source when you scrape several accounts — then click Start.
- Download the dataset in JSON, CSV, Excel or via API.
💰 How much does it cost to scrape Threads?
This Actor uses pay per event pricing: $0.17 per 1,000 results (posts, replies and profiles) without an Apify subscription — plus $0.01 per run start (one per GB of memory: one at the default 512 MB). Paid Apify plans pay less: $0.15 (Bronze), $0.11 (Silver) and $0.088 (Gold) per 1,000 results. Author follower counts, when you turn it on, adds $0.28 per 1,000 authors looked up ($0.27, $0.26 and $0.25 on Bronze, Silver and Gold). E-mails from bios and Phone numbers from bios (both unticked by default: tick the one you need) are two separate extras: each is charged once per account and per run whose bio holds at least one e-mail address (bio-email) at $3.59 per 1,000 accounts ($3.19, $2.89 and $2.49 on Bronze, Silver and Gold) or one phone number (bio-phone) at $3.59 per 1,000 accounts ($3.19, $2.89 and $2.49 on Bronze, Silver and Gold); an account without any of that kind costs nothing, and left unticked each leaves its fields empty. AI sentiment label (unticked by default) adds a positive, neutral or negative label and its score to each post and reply: one post-sentiment event per row labelled, at $8.09 per 1,000 rows labelled ($8.08, $8.07 and $8.06 on Bronze, Silver and Gold); a post without text costs nothing. AI labels (empty by default) judges the labels you write on each post and reply: one ai-label event per post and per label judged, whether the label applies or not; a post without text costs nothing. Download photos and videos (unticked by default) keeps your own copy of the files of the posts: one media-file event per file kept; a file that could not be kept costs nothing. Contacts from the author's website (unticked by default, needs Author follower counts) opens the website each author cites in its bio: one website-contacts event per author, once per run, for whom an e-mail address or a phone number is found there; a website that gives neither costs nothing. It is separate from E-mails from bios and Phone numbers from bios, which read the bio itself. Keyword statistics (unticked by default) adds a summary of each keyword and topic you search: one keyword-stats event per search given, only for a search with at least 5 posts in the run and at most 50 searches per run, the biggest first; a search under 5 posts costs nothing, and the posts of accounts and post URLs are not summarised. See the Pricing tab for the amounts of these four extras. The two AI options need 2 GB of memory (Run options → Memory): with less, they are skipped, the log says so and nothing is charged. The engagement rate is free. A run without the AI options keeps the default memory and pays nothing for them. Example, without a subscription: the whole history of 10 accounts of 500 posts each (5,000 posts) ≈ $0.86; a daily monitor of 300 new posts ≈ $0.06. The filters Threads does not apply itself (postedAfter / postedBefore, minLikes, minReplies, minReposts, mediaOnly, verifiedOnly, languages, includeAuthors, excludeAuthors, minAuthorFollowers, includeKeywords, excludeKeywords) are checked by the Actor on every post it reads, kept or not: each post checked is charged a filter check (filter-check): $0.055 per 1,000 posts checked ($0.050, $0.045 and $0.040 on Bronze, Silver and Gold). A post is checked once per run, however many searches or accounts show it again; with Only new posts, a post your filters dropped for good is not checked, nor charged, again by the next runs (see Monitoring). minAuthorFollowers needs Author follower counts: unticked, it is ignored (the log says so) and nothing is charged for it; ticked, the profile page of each author is read, and charged as an author profile, once per author, for every post the other filters keep — even when the post is then dropped for its author's followers. Platform usage (compute, proxy) is included in the price.
⚙️ Input
{"usernames": ["nasa", "natgeo"],"maxItems": 500}
Posts with their replies, recent replies first:
{"postUrls": ["https://www.threads.com/@nasa/post/DdXJKzbkqPg"],"maxReplies": 200,"repliesSort": "recent"}
Several accounts, a cap per account, only the last two weeks, only the posts not delivered before:
{"usernames": ["nasa", "spacex", "esa"],"maxItemsPerQuery": 100,"postedAfter": "14 days","onlyNew": true,"stateKey": "space-watch"}
| Field | Notes |
|---|---|
usernames | Threads usernames (nasa, @nasa) or profile URLs: every post of each account, newest first. |
includeProfile | One profile row per account (default on, no extra request). |
includeReplies, includeReposts | Also the replies the account wrote (about 20-30 shown without an account) and its reposts (the last 1-4). |
postUrls | Post URLs: the post, then its replies. |
maxReplies | Replies per post (0 = the post only). |
repliesSort | Order of the replies: top or recent. |
repliesForAllPosts | Also the replies under every post found through the accounts and the searches. |
query, searchQueries | Keyword searches. With deepSearch (on by default): hundreds of posts for a common word, a few dozen for a rare one, only the posts that contain the keyword; off: the one page Threads shows without an account (about 20-35 posts). |
hashtags | Topic searches (ai, #nfl): about 20-30 posts each, more with deepSearch. |
deepSearch | Deep search (on by default): after the first search page, Threads' Recent and topic views, the keyword as a hashtag, the phrases found around it ("nike dunk") and the site in other languages — keeping only the posts that contain the keyword (text, quoted post, link, image description or topic), as Threads pads its results with loosely related posts. |
maxSearchPagesPerQuery | Upper bound on the search pages Deep search reads for one keyword (default 300); it also stops by itself after several pages in a row without a new matching post. |
startUrls | Any Threads profile, post or search URL (https://www.threads.com/search?q=apify), or a text file of URLs (one per line, read once when the run starts: a resurrected or migrated run keeps its URLs). |
maxItems | Stop after this many results for the whole run (0 = unlimited). |
maxItemsPerQuery | Cap for EACH source (0 = none): an account's posts, its replies and its reposts are three sources; a post with its replies, a keyword, a topic one each. The profile row is not counted. |
includeAuthorProfiles | Fill the author follower count and bio of every post (one extra lookup per author, charged apart). |
includeBioEmails | E-mail addresses written in the bios, in their own fields: on profile rows, and on posts with Author follower counts. Off by default; charged once per account that has some. |
includeBioPhones | Phone numbers written in the bios, in their own fields: on profile rows, and on posts with Author follower counts. Off by default; charged once per account that has some. |
includeSentiment | An AI sentiment label (positive / neutral / negative) and its score on each post and reply, in two extra fields. Off by default; charged once per row labelled, nothing for a post without text. Requires 2 GB of memory (Run options → Memory); with less the option is skipped and nothing is charged. |
aiLabels | AI labels: your own labels, one per entry — a name (pricing) or a name and a sentence that is true when the label applies (competitor: The author compares tools); up to 20. Each post and reply gets the labels that apply, with a score from 0 to 1, in aiLabelMatches. Empty (the default) = off. Charged per row and per label judged, whether it applies or not; nothing for a post without text. Requires 2 GB of memory (Run options → Memory); with less the option is skipped and nothing is charged. |
downloadMedia, maxMediaFileMb | Keep the photos and videos of the posts, and the audio track of their video, in the key-value store and give their links in two extra columns of the row (off by default). Charged once per file kept; a file over maxMediaFileMb (50 MB by default, 1 to 100; at most 50 below 1 GB), gone or out of time is not kept and not charged. |
includeWebsiteContacts | Open the website each author cites in its bio and add the e-mails, phone numbers and social links found there (off by default; needs includeAuthorProfiles, without it nothing happens). Charged once per author for whom at least one e-mail or phone number is found; a website that cannot be opened or gives none costs nothing. Not the bio contacts of includeBioEmails / includeBioPhones. |
includeKeywordStats | A summary of each keyword and topic you search, in the KEYWORD_STATS record of the key-value store (never in the dataset); off by default. Charged once per search given: at least 5 posts in the run, at most 50 searches, the biggest first. Only the posts found by a keyword or topic search count: the posts of an account, of a post URL and the replies under a post are not summarised. |
postedAfter, postedBefore | Publication date range: 2026-09-01 (a UTC day), or a period before now (7 days, 2 weeks, 1 month, 24 hours). |
minLikes, minReplies, minReposts, mediaOnly | Only the posts with at least that many likes / replies / reposts, or with a photo or a video (a post whose count is unknown, because the account hides it, is dropped). |
verifiedOnly | Only the posts whose author has the verified badge (a post whose badge is unknown is dropped). |
languages | Only the posts written in one of these languages, as ISO 639-1 codes (en, fr, ja): the language column, given by Threads or detected from the text. A post whose language is unknown (text too short to tell) is dropped while the filter is on. |
minAuthorFollowers | Only the posts whose author has at least that many followers (0 = no minimum). Needs includeAuthorProfiles: without it the filter is ignored, with a warning in the log. |
includeAuthors, excludeAuthors | Keep only / drop the posts written by these accounts (usernames such as nasa or @nasa, case ignored). |
includeKeywords | Keep only the posts that contain one of these words, in the text, image descriptions, link card, hashtags or topic (case and accents ignored; a word is also found inside a longer word): with a keyword search, the results Threads returns without the keyword are dropped. |
excludeKeywords | Drop the posts whose text, image descriptions or link card contain one of these words (case and accents ignored; a word is also found inside a longer word). |
onlyNew, stateKey, resetState | Monitoring: only the posts never delivered under this memory key; resetState forgets the memory. |
| Advanced | proxyConfiguration (Apify proxy by default, included in the price; the residential proxy is not available), maxConcurrency, maxRequestsPerMinute, maxRequestRetries, debugLog. |
📦 Output
A post as the run saved it (empty fields left out, links shortened):
{"type": "post","id": "3991969585838706926","url": "https://www.threads.com/@nasa/post/DdmUzAeFFDu","source": "profile-posts","sourceInput": "nasa","searchUrl": "https://www.threads.com/@nasa","scrapedAt": "2026-09-24T00:03:59.949Z","code": "DdmUzAeFFDu","text": "Happy equinox, Earthlings! 🍂\n\nSept. 22 marks the the first day of fall in the Northern Hemisphere. From now until the beginning of spring, nighttime hours will last longer than daylight as the Sun travels a shorter arc across the sky each day.","createdAt": "2026-09-22T17:57:59.000Z","createdAtTimestamp": 1790099879,"isEdited": false,"likeCount": 2235,"replyCount": 44,"repostCount": 141,"quoteCount": 14,"shareCount": 18,"viewCount": null,"engagementRate": 0.0002,"engagementBase": "followers","mediaType": "image","hasMedia": true,"images": [{"url": "https://instagram.fnap7-2.fna.fbcdn.net/v/t51.82787-15/818654783_18120464002960389_7323725605055789618_n.jpg","width": 4096,"height": 3264,"altText": "This natural-color image shows the hilly region around State College, Pennsylvania. It show lines and ridges varying in size and color from orange to green."}],"videos": [],"mediaUrls": ["https://instagram.fnap7-2.fna.fbcdn.net/v/t51.82787-15/818654783_18120464002960389_7323725605055789618_n.jpg"],"accessibilityCaption": "This natural-color image shows the hilly region around State College, Pennsylvania. It show lines and ridges varying in size and color from orange to green.","mentions": [],"hashtags": [],"links": [],"isReply": false,"isQuotePost": false,"isRepost": false,"mediaCount": 1,"isGif": false,"stickerUrls": [],"pollOptions": [],"isGhostPost": false,"isLikedByAuthor": false,"likeCountsHidden": false,"isPinned": false,"replyControl": "everyone","isSpoiler": false,"authorId": "28829152388","authorUsername": "nasa","authorFullName": "NASA","authorIsVerified": true,"authorProfilePicUrl": "https://instagram.fnap7-2.fna.fbcdn.net/v/t51.82787-19/669747085_18089786557960389_922072622069351626_n.jpg","authorUrl": "https://www.threads.com/@nasa","authorFollowerCount": 12739850,"authorBio": "Making the seemingly impossible, possible. ✨","authorEmails": [],"authorPhones": [],"authorWebsiteEmails": [],"authorWebsitePhones": [],"authorSocialLinks": [],"bioLinks": [],"emails": [],"phones": [],"profileTags": []}
You can download the dataset in various formats such as JSON, HTML, CSV or Excel.
Media files
With Download photos and videos, every photo and video of the posts the run delivers is kept in the run's key-value store as media-<post id>-<n>.<extension>, with its real content type, and so is the audio track of the post's video (audioUrl, media-<post id>-audio.<extension>, one more file). The row says where, in storedMediaUrls (same order as mediaUrls; null for a file not kept) and storedAudioUrl. The links Threads gives in mediaUrls and audioUrl are signed by Meta and expire: your copy stays. A GIF (gifUrl), the author's picture and the picture of a link card are not copied.
A file is kept whole or not at all, and charged only when it is kept. Not kept, and not charged: a file larger than maxMediaFileMb, a file Threads no longer serves, a download that fails or runs out of time, and any file beyond what the run's maximum cost pays for. The log says how many files were kept and why the others were not.
Keyword statistics
With Keyword statistics, the run adds a KEYWORD_STATS record to its key-value store (never a row of the dataset) with one summary per keyword and per topic you searched, the biggest first: the number of posts and of replies, the first and last post date, posts per day, the average and the median of likes, replies, reposts, quotes and views (a count Threads hides is left out, never read as 0), the median engagement rate, the share of posts with media, the number of authors and the share of verified ones, the languages when Threads gives them, the 10 most used hashtags, the 10 most active authors, the 5 posts with the most likes, and — with AI sentiment label — the share of positive, neutral and negative posts. Each summary carries keyword (a topic with its #) and source (search or hashtag).
A summary is made of the posts the run delivered for that search: a post that two of your searches both show is counted under the first one, and a pasted Threads search URL is named by its keyword. The posts of an account, of a post URL and the replies under a post are not the result of a search and are not summarised. A search needs at least 5 posts in the run and at most 50 searches are given; the others are listed in notDelivered with the reason. One keyword-stats event is charged per search given, never twice for a run that was moved to another server, and never past the maximum cost of the run. With Only new posts, only the posts delivered in this run are counted. The link to the record is in the run log.
Contacts from the author's website
With Contacts from the author's website (and Author follower counts, where the links come from), the Actor opens the website each author cites in its bio: its home page and up to two pages of the same site that the home page links as contact, about or legal notice (a link-in-bio page such as Linktree is one page). The row gets authorWebsite (the site), authorWebsiteEmails and authorWebsitePhones (+ and digits for an international number), and authorSocialLinks (Instagram, Facebook, LinkedIn, X, YouTube, TikTok, WhatsApp and Telegram profiles, from the bio and from the website). Each website is read once per run: every post of the author carries the same values. The profile row of an account has none of these columns.
An author is charged once per run, and only when at least one e-mail address or phone number is found on its website; the social links are free. This is not the bio: the e-mails and phone numbers written in the bio itself stay in authorEmails / authorPhones (E-mails from bios, Phone numbers from bios). Links to Instagram, Facebook, YouTube, TikTok, X, LinkedIn, WhatsApp, Telegram and Threads are never opened, and the Actor reads only the website the author itself cites. A website that cannot be opened, is protected or gives nothing costs nothing, and the log counts them.
All 114 fields
| Fields | What you get |
|---|---|
type, id, url, source, sourceInput, searchUrl, scrapedAt | post or profile, Threads id, public link, what produced the row (profile-posts, profile-replies, profile-reposts, profile, post, replies, search, hashtag), the username / URL / keyword you gave, the threads.com page it was read from (the account's page or tab, the post, the search), ISO timestamp |
code, text, createdAt, createdAtTimestamp, isEdited, language | Post: code of its URL, full text, publication date (what the date filters read), edited, language (ISO 639-1 code such as en, ja, zh; left empty when the text is too short to tell) |
sentiment, sentimentScore, aiLabelMatches | AI (options): positive, neutral or negative for the text of the post or reply, and the confidence in it from 0 to 1 (0.91) (AI sentiment label); the labels you wrote that apply to the text, each as { "label", "score" }, [] when none applies (AI labels). null when the option is off or skipped, or when the row has no text |
likeCount, replyCount, repostCount, quoteCount, shareCount, viewCount, likeCountsHidden | Engagement: 2234, 44, 141, 14, 18; views (161167) only for a post read by its URL (Post URLs) — Threads shows them nowhere else, so posts of profiles, searches and replies have null; likeCountsHidden = the author hides likes and views (Threads shows no number): likeCount and viewCount are then null, never a false 0 |
engagementRate, engagementBase | Engagement rate (computed for you, free): likes + replies + reposts + quotes divided by the views (views, a post read by its URL), or by the author's follower count when the post has no views (followers: the posts of an account, or any post with Author follower counts), 4 decimals — 0.0249. A count Threads does not give counts 0, unless it gives none of the four. null when the post has neither views nor followers |
mediaType, hasMedia, hasAudio, mediaCount, images, videos, mediaUrls, accessibilityCaption | Media: text, image, video, carousel or audio; every photo (url, width, height, altText) and video (url, width, height, thumbnailUrl, durationSeconds) |
videoDurationSeconds, videoQualities, audioUrl | First video of the post (the one of videos[0], on every source, nothing extra to pay): its length in seconds (11.935), the resolutions Threads offers, smallest first (["720p", "1080p"]), and its audio track as a separate file; null for a post without video or when Threads gives no readable manifest for it. In a carousel with several videos, durationSeconds of each entry of videos gives the length of each one |
storedMediaUrls, storedAudioUrl | Your copy of the media (Download photos and videos): where each file of mediaUrls is kept in the run's key-value store, in the same order, null for a file not kept; where the audio track of audioUrl is kept. [] and null when the option is off |
isGif, gifUrl, stickerUrls, musicTitle, musicArtist, musicSongId, podcastName, podcastEpisodeName, podcastPlatform, podcastUrl | GIF, stickers, song attached, podcast episode shared (SPOTIFY, APPLE_PODCASTS…) |
mentions, hashtags, links, topicTag, linkUrl, linkTitle, linkDisplayUrl, linkImageUrl | Links and mentions: usernames, hashtags, links of the text, topic (NFL Threads), link card — real targets, no redirect |
pollOptions, pollTotalVotes, pollIsClosed, pollExpiresAt | Polls: {text, votes} per option |
isReply, replyToUsername, replyToUserId, replyToText, replyToPostId, replyToUrl, replyDepth, rootPostUsername, isLikedByAuthor, relatedTo | Conversations: the post answered, depth under the post whose replies are read (1 = direct reply), starter of the thread, liked by the author answered, the post URL the reply belongs to |
positionInThread, threadLength, relatedPostUrls | Thread of the author and recommendations, only for a post read by its URL (Post URLs, or a post link in Threads URLs) — nothing extra to pay: the place of the post in the thread of its author (2 of 9: the author's own posts in a row, 1 and 1 for a post alone; a reply to another author starts its own count) and the URLs of the posts Threads recommends on that page ([] when it shows none). Posts of profiles, searches and replies have null: their page does not give the whole thread |
isQuotePost, quotedPostId, quotedPostUrl, quotedPostText, quotedPostUsername, isRepost, repostedByUsername | Quoted post; reposts of Reposts by each account (the original post, and who reposted it) |
isPinned, replyControl, isPaidPartnership, isSpoiler, isAiGenerated, isGhostPost, locationId, locationName | Pinned on the profile, who can reply, paid partnership, spoiler, AI label, 24-hour post, place tagged |
authorId, authorUsername, authorFullName, authorIsVerified, authorProfilePicUrl, authorUrl, authorFollowerCount, authorBio, authorEmails, authorPhones | Author; followers and bio for the accounts of Usernames, and for every author with Author follower counts — with the e-mails (E-mails from bios) and phone numbers (Phone numbers from bios) written in that bio |
authorWebsite, authorWebsiteEmails, authorWebsitePhones, authorSocialLinks | Author's website (Contacts from the author's website): the website cited in the bio, the e-mails and phone numbers found on it, the social profiles of the bio and of the website. null and [] when the option is off |
username, fullName, bio, bioLinks, emails, phones, followerCount, isVerified, isPrivate, profilePicUrl, profileTags, transparencyLabel | Profile rows: nasa, NASA, bio, its links, e-mails and phone numbers written in it, 12739843 followers, badges, topics |
💡 Tips
How to get more results
Leave Max results at 0 and add usernames: an account gives its whole history. A keyword search with Deep search gives hundreds of posts for a common word, a few dozen for a rare one (Threads shows one page of about 20-35 to visitors without an account; Deep search reads its other views, related phrases and languages): add more keywords, or take the accounts that post about your topic.
How to reduce costs
The price is per result, so the levers are maxItems, maxItemsPerQuery, maxReplies, the filters (a filtered-out post is not charged as a result, only its filter check — a narrow filter on a long history checks many posts to keep few) and onlyNew for recurring runs (you never pay twice for the same post, and a post dropped by a date, language, author, keyword or media filter is not checked again). Author follower counts is charged per author: leave it off when you do not need the followers of every author. E-mails from bios and Phone numbers from bios are each charged per account that has some: leave off the one you do not need. The AI options are charged per post (and per label): leave them off, or keep the number of labels low, when you only need the text. Download photos and videos is charged per file kept and Contacts from the author's website per author for whom a contact is found: leave them off when the dataset is enough.
Several accounts, posts and searches in one run
Fill usernames, postUrls, searchQueries and hashtags together: each one is a source of its own. A post found by several sources is saved — and charged — once. Set maxItemsPerQuery to give every source its own cap: without it the first accounts can use up the whole maxItems budget.
Monitoring: only the new posts
Tick Only new posts (onlyNew) and schedule the Actor. The first run returns everything; each later run skips the posts already delivered: they are not saved and not charged. The memory lives in a named key-value store of your account (threads-posts-scraper-seen, up to 150,000 posts per key) and is only updated with posts that really reached the dataset, so a failed run never hides anything. Give each schedule its own stateKey (two schedules sharing a key would hide each other's posts), and tick resetState once to start over. An account's history stops once it meets 20 posts in a row you already have (pinned posts are not counted; fewer under a small maxItems or maxItemsPerQuery), so the older posts a cap left out of an earlier run are not fetched later. The posts your filters dropped for good are remembered too: postedAfter (older posts), languages, includeAuthors, excludeAuthors, includeKeywords, excludeKeywords and mediaOnly. The next run skips them without checking them, so it is not charged a filter check for them. This memory is kept as long as the rest of your input stays the same (the limits, the pace, the proxy and the memory key can change) and resetState forgets it. A post dropped by something that can change (minLikes, minReplies, minReposts, verifiedOnly, minAuthorFollowers, postedBefore) is checked again at every run, so it comes out the day it has enough likes or falls inside the dates. To get the older posts a cap left out, run once without onlyNew, with postedBefore set to the date of the oldest post you have (the newer ones are then filtered out, each one charged its filter check).
Filter by publication date
postedAfter and postedBefore take a date (2026-09-01, the whole day is included, UTC) or a period before now (7 days, 2 weeks, 1 month; via the API also 24 hours or a full ISO date-time), counted from the start of the run — a resurrected or migrated run keeps the period of its first start; the log shows it as Date range (UTC). The filter reads createdAt. Filtered-out posts are not saved and do not count in maxItems; each post the date filter checks is charged a filter check, kept or not (see Pricing). On an account, the history stops at the first page older than postedAfter (pinned posts excepted).
🔌 Integrations and API
Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.
🤖 Use with AI agents (MCP)
AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the Apify MCP server, billed to their Apify account like any run. It returns one item per Threads post, reply or profile (column type). Actor id: nice_dev/threads-posts-scraper; MCP server with this Actor only: https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/threads-posts-scraper.
Smallest input, for a cheap first call:
{"usernames": ["nasa"],"maxItems": 10}
Key output fields: type, url, text, createdAt, likeCount, replyCount, repostCount, engagementRate and authorUsername.
Cost: $0.17 per 1,000 results plus $0.01 per run start ($0.088 per 1,000 on the Gold plan). Author follower counts, the e-mails and the phone numbers of the bios (each off by default: includeBioEmails: true, includeBioPhones: true), the AI sentiment label and your AI labels (off by default: includeSentiment: true, aiLabels), the copy of the media files (downloadMedia: true), the contacts of the authors' websites (includeWebsiteContacts: true), the summary of each search (includeKeywordStats: true) and the filters cost extra, see the pricing section above. Cap each call with maxItems and, through the API, with the run option maxTotalChargeUsd.
❓ FAQ
Is it legal to scrape Threads?
The Actor only reads what Threads shows publicly to any visitor without an account. It logs in to nothing and uses no account or cookie of yours. With Contacts from the author's website it also opens the public website an author itself cites in its bio, and nothing else. Results contain personal data (usernames, names, bios, posts, and the e-mails or phone numbers people wrote in their bio or published on their website), which is protected by GDPR: do not store it without a legitimate reason, and delete what an author has deleted. You are responsible for using the data in compliance with Threads' Terms of Use and applicable law. This Actor is not affiliated with Threads or Meta.
Does it need a Threads account or a proxy?
No account. The proxy is included in the price: leave the default setting (the residential proxy is not available). When Threads refuses a request, it is sent again at once on a new proxy session.
Is the data safe to open in Excel or to show on a web page?
Posts and bios are their authors' own words, copied as they are. A text can begin with -, +, = or @ (a mention, -20% today): Excel and Google Sheets may read such a cell of a CSV file as a formula. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. Every URL field holds an http(s) URL or null. On a web page, escape every field like any text written by a stranger.
Known limitations
- Keyword and topic searches: Threads shows visitors without an account one page of about 20-35 posts per search, and ignores the dates and author of its search. Deep search widens it (views, related phrases, languages), up to a few hundred posts for a common word — not the whole history of a keyword, which needs an account. The date filters of this Actor are applied to what the pages show.
- Followers and following lists need a Threads account: not available.
- Replies under a post: Threads shows visitors about 80 % of the replies it counts (hidden, deleted and some nested replies are missing).
- An account's Replies tab shows about 20-30 replies, its Reposts tab the last 1-4, to visitors without an account.
- A private account gives its profile row only.
- Threads answers a limited number of requests per IP address (about 2,000 posts' worth), then refuses that address for more than half an hour. The Actor moves to another proxy address at each refusal; a run that reads very long histories (tens of thousands of posts) can run out of fresh addresses: its last requests then fail, are counted in the last line of the log and listed in
FAILED_REQUESTS, and nothing is charged for them. Your own proxies (Proxy configuration) add addresses. onlyNewremembers post ids, not their content: a post whose likes changed is not returned again.- Files kept with Download photos and videos weigh on the run's storage and memory: a photo is a fraction of a MB, a video can be tens. With less than 1 GB (the default is 512 MB) the files are copied 4 at a time and none over 50 MB is kept; for many videos, or for videos above 50 MB, give the run 1 GB or more (Run options → Memory) and raise
maxMediaFileMb.
A run the platform stops without warning (out of memory, run timeout)
- Resurrect it: it goes on from where it stood at most a minute before the stop. The results already saved are skipped: none is delivered or charged twice, and
maxItemsstill counts them. - With
onlyNew, the memory is saved right after posts are written, at most once every 2 seconds: resurrect the stopped run and the posts it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the last few seconds of them once more.
Something doesn't work?
The last line of the log counts the results saved, filtered out, not found on Threads (an account or a post that does not exist, was deleted or is not public), and the requests that failed after every retry. Those requests and the targets not found are listed, with the reason, in the FAILED_REQUESTS record of the run's key-value store. A run that saved nothing fails when requests failed, or when every account or post asked was not found; its last message gives the cause. A run that saved some results fails too when Threads refused at least as many of its API calls as it answered (the pages alone hold only the first posts of each account or post), or when at least as many requests failed as were read: a green run with a short dataset would hide the outage. One failed request among many is only a warning. It also fails when Threads changes its pages: the run stops and names what it could not read, instead of ending green with empty columns or no results.
If Threads changes its pages, you are told instead of paying for blank rows: if the first 20 posts read all lack their date, author or counts — or the first 20 profiles their username or followers —, the run saves nothing more, stops and fails, and its last message names the missing field.
🛟 Support
Open an issue in the Issues tab with a link to your run: the run log and the FAILED_REQUESTS record of the key-value store show exactly which URLs failed and why.