Threads Scraper: Posts, Profiles, Replies & Search (Apify Actor)

Récupérez des publications publiques Threads sans connexion : fils d’actualité de profils, publication unique avec ses réponses ou recherche par mots-clés. Chaque ligne contient le texte, les mentions J’aime, les réponses, les republications, les médias, la publication citée et l’auteur avec son nombre d’abonnés. Aucun compte Meta ni cookie requis. 1,50 $ pour 1 000 publications, 0,002 $ par démarrage d’exécution, 0,0005 $ par résultat vide. Fonctionne comme un Apify Actor, appelable depuis des clients MCP via le serveur MCP d’Apify (https://mcp.apify.com/?tools=cliqtomedia/threads-scraper).

Serveur MCP hébergé

npx add-mcp 'https://mcp.apify.com/?tools=cliqtomedia/threads-scraper'

S’installe dans Claude Code, Codex, Cursor et plus

Documentation

Threads Scraper — Posts, Profiles, Replies & Search (cliqtomedia/threads-scraper) Actor

Scrape public Threads posts without login: profile feeds, a post with its replies, or keyword search. Text, likes, replies, reposts, media, quoted post and author with followers in clean JSON. Pay per post.

Pricing

from $1.05 / 1,000 posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events. Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes. In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours, and optionally produces a well-defined JSON output, datasets with results, or files in key-value store. In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects. You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the API section below.

Each client library has reference documentation the quickstart does not restate: JavaScript/TypeScript (npm install apify-client) and Python (pip install apify-client).

README

Scrape public Threads posts with no login: the latest posts, replies or reposts of a profile, one post with its replies, or the top posts for a keyword. Each post is one clean JSON row with text, date, likes, replies, reposts, media, the quoted post and the author with followers.

Use it for social listening, brand and creator research, or AI pipelines. The smallest run is one username, such as zuck, with 20 posts: it finishes in under 10 seconds and costs $0.032 on the Free plan.

Threads Scraper: usernames, post links and keywords in; posts, replies, media, quotes and author followers out. No login.

Table of contents

What it does

Threads Scraper reads public pages of threads.com the way a logged-out visitor sees them. It needs no account, no cookies and no API token. It has three modes:

ModeYou giveYou get
profileUsernames or profile linksThe latest posts of each profile (or its replies or reposts tab), with the author's follower count
postPost links (threads.com or threads.net)The post, the author's own thread below it, and the replies Threads shows without login
searchKeywords or hashtagsThe top posts Threads shows for each keyword

A profile, post or search with no public posts returns one not_found row with the reason. It does not disappear silently, so you can see what happened to every input.

Good fit

  • Track what a brand, creator or competitor posts on Threads, with likes, replies and reposts.
  • Get only new posts since your last run with Posted after, for example 7 days.
  • Collect a post and its replies for sentiment or discussion analysis.
  • Find top posts about a topic or hashtag.
  • Feed clean, typed Threads rows into an AI agent, a spreadsheet, a database, Slack or Notion.

Not a fit

  • Only public data. No DMs, no private profiles, nothing that needs login.
  • No view counts: Threads does not show them without login.
  • No followers or following lists and no account search: they need login.
  • No "recent" search and no date-sorted search: threads.com redirects these to login.
  • Replies of a post: only the first page Threads shows without login, usually 10–15. More pages need login.
  • Some large profiles are shown only to logged-in visitors. They return not_found. The Actor does not try to get around this.
  • Counts are a snapshot at fetch time.

👉 Try it now: open the input form

How it works

  1. You give usernames, post links or keywords. The Actor opens the matching public threads.com pages as a logged-out visitor, through Apify Proxy.
  2. It reads the posts on those pages and loads more pages of a profile until it has your number of posts, reaches Posted after, or the public feed ends. Duplicates are dropped.
  3. It saves one row per post to the Dataset, one not_found or error row for every input without posts, and a run summary in RUN_SUMMARY. If you chose a connector, a short summary also goes to Slack or Notion.

👉 Try it now: open the input form

Quick start

Input form: profile posts mode, username zuck and 20 posts per input, boxes 1 to 3

  1. Open the Input tab. Mode is already Profile posts (box 1 in the picture).

  2. Keep zuck in Usernames, or add your own usernames or profile links (box 2).

  3. Keep Max posts per input at 20, the prefill and default (box 3).

  4. Click Start.

  5. Open the Posts view in the Output tab and check the follower count, text, date, likes, replies and reposts (box 5).

    Output: Posts view with followers, text, date, likes, replies and reposts, box 5

Expected result: the 20 newest posts of the profile, one row per post.

👉 Try it now: open the input form

Use cases

Buyer jobInput pathOutput entityKey fieldsNext integration
Brand or creator monitoringmode: profile, usernames, postedAfter: "7 days"posttext, createdAt, likes, replies, repostsWeekly schedule, Google Sheets or Slack
Reply and repost activity of an accountmode: profile, profileTab: replies or repostsposttext, replyToUsername, repostedPost, createdAtSpreadsheet or database
Discussion analysismode: post, postUrlspost with rolerole, text, replyToUsername, likesSentiment or topic analysis
Topic researchmode: search, queriesposttext, author.username, likes, urlAI summary, content ideas
Influencer shortlistmode: profile, usernamespost with authorauthor.followers, author.verified, likesCompare engagement per follower

👉 Try it now: open the input form

Input

Input fields

FieldPlain nameTypeRequiredDefault / prefillAllowed valuesEffectExample
modeModestringnoprofileprofile, post, searchWhich list is read when several are filled: profile (default) reads all of them, post or search only its own"post"
usernamesUsernamesstring[]for profileprefill ["zuck"]up to 50; name, @name or a threads.com / threads.net profile linkProfiles to read["zuck", "@natgeo"]
postUrlsPost URLsstring[]for postnoneup to 50; …/@user/post/CODE on threads.com or threads.netPosts to read["https://www.threads.com/@zuck/post/DeZtp-TkQHh"]
queriesSearch keywordsstring[]for searchnoneup to 50; up to 100 characters eachOne search per line["web scraping", "#coffee"]
maxItemsMax posts per inputintegerno20 (prefill 20)1–500Cap for each username, post URL or keyword200
maxTotalItemsMax posts per run (optional)integernonone1–25,000Cap for the whole run; paid rows (posts and not_found) count toward it1000
includeRepliesInclude replies (post mode)booleannotruePost mode: also save the author's thread and the replies; off = only the postfalse
profileTabProfile tab (profile mode)stringnothreadsthreads, replies, repostsWhich profile tab is read. replies and reposts give the first page only"replies"
postedAfterPosted after (optional)stringnononedate 2026-10-01 or a period like 7 days, 2 weeks, 24 hoursKeep only newer posts (profile and search)"7 days"
postedBeforePosted before (optional)stringnononesame as aboveKeep only older posts (profile and search)"2026-11-01"
proxyConfigurationProxyobjectnoApify Proxy (datacenter)Apify Proxy groups or your own proxiesWhere requests come from{"useApifyProxy": true}
deliveryConnectorSend results to (optional)stringnononeone of your MCP connectors in Apify ConsoleWhere the short run summary goesSlack or Notion connector
deliveryTargetNotion page or channel (optional)stringnononeNotion page link or Slack channel IDWhere in that service the summary goesC0123456789

With mode: profile (the default) every filled list is read; post or search reads only its own list. Duplicate values are removed, also when the same profile is written two ways (for example @NatGeo and its link).

A value that cannot be read, such as bad name!!, does not stop the run. It becomes one free error row with errorCode: INVALID_INPUT and the reason, and the other values are scraped. The run fails with INVALID_INPUT only when nothing usable is left; then no requests are made and only the start is charged.

Interacting settings

WhenInput AInput BEffective behavior
Post modepostUrlsmaxItemsThe post, its thread and its replies together count toward maxItems
Post modeincludeReplies: falsemaxItemsOnly the post itself, one row per URL
Search modequeriesmaxItems above 30Threads shows only the top ~25–30 posts per keyword; add more specific keywords to get more posts
Profile modeusernamesmaxItemsReading stops at the end of the profile's public feed, even if maxItems is higher
Profile modepostedAftermaxItemsReading stops at the first older post that is not pinned; filtered posts are free
Post modepostedAfter / postedBeforeNot used: the requested posts are returned as they are
Any modemaxTotalItemsmaxItemsEach input gets up to maxItems; the run stops when maxTotalItems is reached and the remaining inputs are marked not_processed

Input examples

New posts of several profiles in the last 7 days
{
  "mode": "profile",
  "usernames": ["zuck", "natgeo", "https://www.threads.com/@nasa"],
  "maxItems": 100,
  "postedAfter": "7 days"
}

Expected output: up to 100 post rows per profile from the last 7 days, with text, likes, media and author.followers.

A post with its replies
{
  "mode": "post",
  "postUrls": ["https://www.threads.com/@zuck/post/DeZtp-TkQHh"],
  "includeReplies": true,
  "maxItems": 50
}

Expected output: one row with role: target, rows with role: self_thread for the author's thread, and rows with role: reply.

Search with a run cap
{
  "mode": "search",
  "queries": ["web scraping", "#coffee"],
  "maxItems": 30,
  "maxTotalItems": 50
}

👉 Try it now: open the input form

Output

Every row goes to the default Dataset. The Posts view in the Output tab shows the main columns. The run summary is in the key-value store as RUN_SUMMARY.

Output fields

FieldMeaningTypeCan be empty?
statuscomplete (a post), not_found or errorstringno
statusReason, errorCodeWhy a not_found or error row has no poststringnull on posts
postId, code, urlThreads post ID, short code and linkstringnull on status rows
mode, inputMode and the username, post URL or keyword this row came fromstringno
roleprofile_post, search_result, target, self_thread or replystringnull on status rows
authorusername, fullName, userId, verified, followers, profilePicUrlobjectfollowers is only filled in profile mode, else null
textPost textstringcan be empty for media-only posts
createdAtPublish time, ISO 8601 UTCstring
likes, replies, reposts, quotes, sharesCounts at fetch timenumbernull when Threads does not show it, never a fake 0
mediaTypetext, photo, video, carousel or otherstring
mediaPhotos and videos: type, url, width, height, thumbnailUrlobject[]empty for text posts
quotedPost, repostedPostpostId, url, username, text, createdAtobjectnull when not a quote or repost
isReply, replyToUsernameReply marker and who it replies toboolean, string
linkUrl, linkTitleAttached link (Threads redirect removed) and its titlestringnull without a link
topicTopic tagstringoften null
pinnedPinned on the author's profileboolean
fetchedAtWhen the row was scraped, ISO 8601 UTCstringno

Media links are signed by Threads and stop working after some days. Download the files soon if you need them.

Status rows

statusWhenerrorCode
not_foundThe profile does not exist or is shown only to logged-in visitorsNOT_FOUND
not_foundThe profile is privatePRIVATE_PROFILE
not_foundThe profile has no public postsNO_POSTS
not_foundThe post was deleted or is not publicNOT_FOUND
not_foundThe keyword has no resultsNO_RESULTS
errorA username, URL or keyword cannot be read (free)INVALID_INPUT
errorThreads failed or refused the request after retries (free)RATE_LIMITED, BLOCKED, LOGIN_REQUIRED, SOURCE_UNAVAILABLE

A source failure is never shown as "no results". It is an error row, and the run status says so.

Run summary (RUN_SUMMARY)

FieldMeaning
statusCOMPLETE, PARTIAL, NOT_FOUND, NO_RESULTS, ERROR, INVALID_INPUT or CANCELLED
partialReasonFor PARTIAL: CHARGE_LIMIT, SOURCE_ERROR, SAFETY_LIMIT or CANCELLED
messageOne plain-English sentence about the result
countsinputs, postRows, chargedPostRows, emptyResultEvents, notFoundRows, errorRows, duplicatesSkipped
inputsOne entry per input (input, status, posts, reason): complete, partial, not_found, no_results, error or not_processed. reason is MAX_TOTAL_ITEMS when the run cap stopped it, INVALID_INPUT: … for a value that could not be read
warningsPlain-English notes, for example the first-page-of-replies limit or a field that was not used
deliveryOnly with a connector: status (delivered, skipped or failed) and the reason

Send results to Slack or Notion

Pick your connector in the optional deliveryConnector field. After the run saves its data, the Actor posts a short summary (up to 25 rows and a link to the full dataset) there. Put a Notion page link or a Slack channel ID in deliveryTarget: in Notion every run is added on top of that one page, so your workspace does not fill up with new pages. Without a page link, Notion delivery is skipped and the log says so. A delivery error never fails the run and costs nothing extra. Connect a service once in Apify Console → MCP connectors.

Output example

A real profile post, trimmed (long media and picture links shortened):

{
  "status": "complete",
  "statusReason": null,
  "errorCode": null,
  "postId": "4007137472223477566",
  "code": "DecNkzeCX8-",
  "url": "https://www.threads.com/@instagram/post/DecNkzeCX8-",
  "mode": "profile",
  "input": "instagram",
  "role": "profile_post",
  "author": {
    "username": "instagram",
    "fullName": "Instagram",
    "userId": "63404918397",
    "verified": false,
    "followers": 38354704,
    "profilePicUrl": "https://scontent-den2-1.cdninstagram.com/v/…"
  },
  "text": "@hichiyan686 made a whole retro wall phone by hand ☎️✨",
  "createdAt": "2026-10-13T16:14:12.000Z",
  "likes": 170,
  "replies": 10,
  "reposts": 6,
  "quotes": 1,
  "shares": 2,
  "mediaType": "video",
  "media": [
    { "type": "video", "url": "https://scontent-den2-1.cdninstagram.com/o1/v/…mp4?…", "width": 720, "height": 1280, "thumbnailUrl": "https://scontent-den2-1.cdninstagram.com/v/…jpg?…" }
  ],
  "quotedPost": null,
  "repostedPost": null,
  "isReply": false,
  "replyToUsername": null,
  "linkUrl": null,
  "linkTitle": null,
  "topic": null,
  "pinned": false,
  "fetchedAt": "2026-10-14T15:36:27.390Z"
}

null means Threads did not provide the value. It never stands for zero.

👉 Try it now: open the input form

Pricing

You pay per event. Platform usage (compute, proxy, storage) is included in the price.

EventFree planStarter (Bronze)Scale (Silver)Business (Gold) and higher
Post$0.0015$0.00135$0.0012$0.00105
Empty result$0.0005$0.0005$0.0005$0.0005
Actor start$0.002$0.002$0.002$0.002
  • Post: one per post row saved (profile post, the target post, a thread post, a reply or a search result). So 1,000 posts cost $1.50 on the Free plan and $1.05 on Business.
  • Empty result: one per input that returned no posts: a profile that does not exist, is private, has no posts or is shown only to logged-in visitors; a missing post; a search with no results. It covers the requests made for that input.
  • Actor start: charged by Apify once per run, per GB of memory. The default 512 MB counts as one.
  • Free: error rows (Threads failed or a value could not be read), posts dropped by the date filter, duplicate posts and duplicate inputs.

Cost examples (Free plan prices)

ScenarioInputCharged eventsCost
Prefill1 profile, 20 postsstart + 20 posts$0.032
1,000 posts5 profiles × 200start + 1,000 posts$1.502
Profile that does not exist1 usernamestart + 1 empty result$0.0025
Only invalid values1 valuestart$0.002

Spending limit

Set Maximum cost per run in the run options. The Actor checks the limit before every post. When the next post does not fit, the run stops with status PARTIAL and partialReason: CHARGE_LIMIT, and keeps everything saved so far. The platform's max paid results option works the same way for the number of rows.

👉 Try it now: open the input form

Limits

  • Up to 50 usernames, post URLs or keywords per run, up to 500 posts per input, and up to 25,000 posts per run with maxTotalItems.
  • One run has about 4 minutes of scraping time. In tests, 10 profiles × 200 posts gave 1,563 posts and 2 not_found rows in 53 seconds. A bigger request stops at this limit with PARTIAL and SAFETY_LIMIT, keeps the posts saved so far, and charges only for them. For more data, use several runs.
  • A profile ends where its public feed ends, even if maxItems is higher.
  • Profile tabs replies and reposts: the first page only, as Threads shows it without login.
  • Search: top ~25–30 posts per keyword. Replies of a post: the first page only, usually 10–15.
  • author.followers is filled only in profile mode. Threads does not show it on post and search pages without login.
  • Speed: a 20-post profile takes under 10 seconds. Three inputs are read at the same time; a slow request is retried in a new proxy session after 12 seconds.

👉 Try it now: open the input form

Switching from another Threads scraper

You can keep the input you used with another Threads scraper. The Actor reads these field names too and picks the mode from the filled list. Mixed lists (urls, targets, links) are split per value: a post link goes to post mode, a profile name or link to profile mode, a search link to search.

Your fieldRead as
profiles, user, username, handles, users, profileUrlsusernames
post_links, post_urls, postLinks, startUrls (strings or { "url": … }), postspostUrls
searchQueries, keywords, searchTerms, searchQuery, query, search, hashtagsqueries
maxPosts, max_posts, maxResults, maxItemsPerKeyword, maxPostsPerProfile, maxPostsPerQuery, maxPostsPerSource, maxResultsPerInput, resultsLimit, limitmaxItems
maxTotalPosts, maxTotalResultsmaxTotalItems
start_date, startDate, afterDate, after, onlyPostsNewerThan, dateFrom, sincepostedAfter
end_date, endDate, beforeDate, before, onlyPostsOlderThan, dateTo, untilpostedBefore
action or mode: user, posts, user_postsmode: profile
action or mode: user_replies, user_repostsmode: profile with profileTab: replies or reposts
action or mode: urls, post_link, threadmode: post
action or mode: keyword, hashtagmode: search
maxReplies, fetchAllRepliesincludeReplies

Output field names are camelCase and the author is a nested object. Typical mapping:

Other ActorThis Actor
post_url, post_codeurl, code
text_contenttext
created_atcreatedAt
like_count, reply_count, repost_count, quote_count, share_countlikes, replies, reposts, quotes, shares
media_type, media_url(s)mediaType, media[].url
quoted_post_urlquotedPost.url
is_reply, reply_to_usernameisReply, replyToUsername
is_pinned, topic_tag, link_titlepinned, topic, linkTitle
username, display_name, user_id, is_verified, followers_count, profile_pic_urlauthor.username, author.fullName, author.userId, author.verified, author.followers, author.profilePicUrl
scraped_atfetchedAt

Extra here: a post with its replies in the same Actor (role shows target, thread or reply), and not_found rows that explain every missing input. Not here: view counts, bios, followers lists and recent search.

👉 Try it now: open the input form

API, export and integrations

  • API: start a run with POST https://api.apify.com/v2/acts/cliqtomedia~threads-scraper/runs and the JSON input above. Read rows from the run's default Dataset, for example with ?view=posts.
  • Export: the Dataset downloads as JSON, CSV, Excel, XML or RSS from the Output tab or the API.
  • Scheduling: use Apify Schedules, for example a daily run over your list of profiles with postedAfter: "1 day".
  • Integrations: Make, Zapier, n8n, Google Sheets and webhooks connect through the Apify integrations tab. Slack and Notion also work through deliveryConnector.

Use with AI agents (MCP)

  • MCP server with only this Actor: https://mcp.apify.com?tools=cliqtomedia/threads-scraper.
  • Smallest useful input: {"mode": "profile", "usernames": ["zuck"], "maxItems": 20}.
  • Key fields: text (post text), author.username (who posted), createdAt (when), likes (engagement), url (link to cite).
  • A 20-post profile run takes under 10 seconds and costs $0.032 on the Free plan. At most 50 inputs and 500 posts per input; search gives the top ~25–30 posts per keyword. not_found and error rows explain missing data.

👉 Try it now: open the input form

Troubleshooting

A well-known profile returns not_found

Symptom: a row with status: not_found and errorCode: NOT_FOUND for a profile that exists. Reason: threads.com shows some profiles only to logged-in visitors. The Actor works without login, so it cannot read them. Action: check the profile in a private browser window. If it asks you to log in, this Actor cannot read it.

Search returns fewer posts than maxItems

Threads shows logged-out visitors only the top ~25–30 posts per keyword. Add more specific keywords, for example coffee roasting and #coffeeshop next to coffee.

A profile with postedAfter returns few posts

Reading stops at the first post older than Posted after (pinned posts are skipped), so a quiet profile gives few or no posts. A profile with no posts in the period returns one not_found row with NO_POSTS.

The run ends as PARTIAL

Check partialReason in RUN_SUMMARY. CHARGE_LIMIT: raise Maximum cost per run or max paid results. SAFETY_LIMIT: the request is larger than one run can do; split it into several runs. SOURCE_ERROR: Threads failed for some inputs; run them again later.

Rows with error status, RATE_LIMITED or BLOCKED

Threads refused the requests after retries. These rows are free. Keep the default Apify Proxy on, or switch the proxy to Residential in Advanced, and run the failed inputs again.

Rows with INVALID_INPUT, or the run fails with INVALID_INPUT

A username, post URL or keyword cannot be read. The row names the value and the reason; fix it and run again. The whole run fails with INVALID_INPUT only when no usable value is left, and the message shows an example of a valid input. Only the start was charged.

Nothing arrived in Slack or Notion

Check delivery in RUN_SUMMARY and the run log. For Notion, deliveryTarget must be a page link that the connector can open; for Slack, a channel ID. The run itself is not affected.

👉 Try it now: open the input form

FAQ

Do I need a Threads or Instagram account?

No. The Actor reads only public pages without login, cookies or tokens.

Why not use the official Threads API?

The official Threads API needs an app, an access token and review, and reads mainly your own account. This Actor reads public posts of any public profile, post or keyword without setup.

Why is there no view count?

Threads does not show view counts to logged-out visitors. The Actor never guesses a value.

How do I get only new posts?

Set Posted after to a period such as 1 day and schedule the Actor daily. Older posts are skipped and not charged.

Are the counts live?

They are a snapshot at fetchedAt. Run again to refresh them.

Is the data complete?

It is what threads.com shows a logged-out visitor at fetch time. Deleted posts, private profiles and profiles that need login are not included, and some counts can be null.

Is scraping Threads allowed?

The Actor reads only public pages at a modest rate and does not log in or bypass any wall. Meta's terms limit automated collection. You are responsible for how you collect, store and reuse the content, including personal data and authors' rights.

👉 Try it now: open the input form

Related Actors

👉 Try it now: open the input form

Support

Use the Issues tab of this Actor for bugs, questions and feature requests. Include the run ID, the mode and the error text. Never post tokens, cookies or private data.

⭐ Found it useful? Rate this Actor. Something wrong? Report a problem — we fix reported problems.

👉 Try it now: open the input form

Changelog

This Actor's version history is a separate document: https://apify.com/cliqtomedia/threads-scraper/changelog.md

Actor input Schema

mode (type: string):

profile: latest posts of each username. post: each post URL with its author's thread and the first page of replies. search: top posts for each keyword or hashtag. If only one list is filled, it is used whatever the mode. If several are filled, profile (the default) uses all of them; post or search uses only its own list.

usernames (type: array):

Profile mode. Up to 50 Threads usernames or profile URLs, e.g. zuck, @natgeo or https://www.threads.com/@zuck. Private and unknown profiles give a not_found row (one empty-result event).

postUrls (type: array):

Post mode. Up to 50 post links like https://www.threads.com/@zuck/post/DeZtp-TkQHh (threads.net links work too). Deleted or private posts give a not_found row (one empty-result event).

queries (type: array):

Search mode. Up to 50 keywords or hashtags, e.g. web scraping or #coffee. Threads shows logged-out visitors only the top ~25–30 posts per keyword, so add several specific keywords to get more posts.

maxItems (type: integer):

Limit per username, per post URL (the post, its thread and replies together) or per keyword, not per run. 1–500. You pay per post saved, not per limit.

maxTotalItems (type: integer):

Stops the whole run after this many paid rows (posts plus not_found rows), across all inputs. Empty = no run limit, only the per-input limit. Inputs not started because of it are listed in RUN_SUMMARY with reason MAX_TOTAL_ITEMS.

includeReplies (type: boolean):

Post mode only. Also save the author's own thread continuation and the replies Threads shows without login (usually the first 10–15). Turn off to get only the post itself.

profileTab (type: string):

threads: the profile's posts (default, paginated up to the limit). replies: the profile's replies to others. reposts: posts the profile reposted. For replies and reposts threads.com shows logged-out visitors only the first page (about 10–25).

postedAfter (type: string):

Keep only posts published on or after this date: 2026-10-01, a full ISO time, or a relative value like 7 days. Profiles stop loading at the first older post (pinned posts aside). Posts outside the range are not saved and not charged.

postedBefore (type: string):

Keep only posts published on or before this date: 2026-10-31, a full ISO time, or a relative value like 1 day. Works with Posted after for a date window.

proxyConfiguration (type: object):

Apify Proxy (datacenter) is on by default: threads.com often answers Apify server IPs with HTTP 429 without it. Switch to Residential if runs come back with BLOCKED or RATE_LIMITED.

deliveryConnector (type: string):

Your Slack, Notion or other MCP connector. After the run the Actor posts a short summary there. Connect services once in Apify Console → MCP connectors.

deliveryTarget (type: string):

Where to post the summary: a Notion page link (each run is added on top of that page) or a Slack channel ID. Notion needs a page here; without it the summary is not sent and the run summary says why.

Actor input object example

{
  "mode": "profile",
  "usernames": [
    "zuck"
  ],
  "maxItems": 20,
  "includeReplies": true,
  "profileTab": "threads",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}

Actor output Schema

posts (type: string):

One row per post: text, date, likes, replies, reposts, media, quoted post and author.

runSummary (type: string):

Run status, per-input results, counts and request statistics.

API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

JavaScript example

import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "profile",
    "usernames": [
        "zuck"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/threads-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

Python example

from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "profile",
    "usernames": ["zuck"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/threads-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

CLI example

echo '{
  "mode": "profile",
  "usernames": [
    "zuck"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call cliqtomedia/threads-scraper --silent --output-dataset

MCP server setup

{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cliqtomedia/threads-scraper"
        }
    }
}

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an Authorization: Bearer <APIFY_API_TOKEN> header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/lhgs1kL1GZGMBRi23/builds/igufD9oHD0JM0K73j/openapi.json