How to Collect Threads Posts and Profile Snapshots
The Threads Posts Scraper collects public profiles and posts, keyword matches, or individual posts with top replies. I maintain the Actor. This guide creates a recent-post sample for the NBA profile and prepares it for a content review.
Profile, search, and direct-post inputs answer different questions. Choose the mode that matches your task before combining their results.

Choose profile coverage or keyword discovery
usernames accepts handles, handles beginning with @, and profile URLs. This returns a profile record plus posts, newest first. includeReplies adds the profile's replies to other people's posts; leave it false when reviewing its main publishing activity.
searchQueries is useful for discovery, but logged-out Threads search exposes roughly the top 30 posts per keyword. It is not a comprehensive archive of every mention. postUrls opens specific posts and can return view counts and top replies.
maxPosts is per profile, query, or post URL. postedAfter filters by date, but does not remember which IDs you exported before. The default Apify proxy works without requiring residential proxies.
Budget for the sample
Pricing as of September 6, 2026. Posts cost $0.0035 and profile records cost $0.005. These events are additive when a profile input returns both one profile record and posts. The Actor-start event is $0.00005 per GB of allocated memory, with a minimum of one event. Check current Actor pricing and the run charge breakdown; these calculations describe Actor events, and separately billed platform or proxy resources may also apply.
Collect recent profile posts
Open the Actor on Apify. In Input, switch to the JSON editor and paste:
{
"usernames": [
"@nba"
],
"includeReplies": false,
"searchQueries": [],
"postUrls": [],
"maxPosts": 30,
"postedAfter": "2026-09-01",
"proxyConfiguration": {
"useApifyProxy": true
}
}
Click Start, then open the completed run’s output dataset.
The example uses September 1, 2026 as a starting date. Adjust that date for the period you intend to study. A short date window and a 30-post cap can return fewer than 30 posts, and the profile record is a separate record type.
After completion, inspect type before interpreting the row count. A dataset containing a profile and posts is not a dataset of posts only.
Read the returned fields
| Field | How to use it |
|---|---|
type | post or profile record |
url | Canonical Threads URL |
text | Post text |
createdAt | Timestamp |
author | Nested author fields |
likes | Displayed engagement count |
Post rows use fields such as text, createdAt, likes, and nested author. Profile rows instead carry profile information such as followers and bio. Keep the source id as text so spreadsheet number formatting does not round long identifiers.
When replies are included, isReply and replyTo provide context. Mixing replies with original posts can distort a publishing-frequency or engagement comparison. View counts from direct-post mode should not be assumed present in every profile-feed row.

Create a recent-content review sheet
Export JSON to preserve nested authors, media arrays, and reply context. Split the dataset into profile and post tables using type. In the post table retain ID, URL, author username, text, creation time, engagement fields, isReply, and scrapedAt.
Deduplicate by post ID and choose whether the analysis covers original posts, replies, or both. Add manual categories for topic and format after reading the text and linked media. Record a short note explaining the category so another reviewer can reproduce it.
Compare posts of similar age when using engagement counts. A post collected an hour after publication has had less time to accumulate reactions than one collected after five days. Keep observation time beside publication time instead of interpreting current likes as a lifetime total.
For a deeper discussion review, take an actual returned post URL and use postUrls in a separate small run. Treat returned top replies as a selected sample, not the complete conversation. Preserve the parent link when exporting replies so their text remains intelligible.
For monitoring, save IDs in your own destination and upsert each new snapshot. Use overlapping date windows if you need resilience to delayed runs, then suppress repeated IDs downstream. If you want to measure count changes, retain dated observations rather than replacing every earlier value.
Avoid confusing coverage limits with inactivity
If keyword search stops around 30 posts, that is a documented logged-out search limit, not evidence that only 30 relevant posts exist. Raising maxPosts does not remove it.
For empty profile results, verify the handle, public accessibility, and postedAfter date. A date later than the profile's latest post can legitimately leave no post rows. Keep missing engagement counts distinct from zero and do not derive an engagement rate from a missing follower denominator.
For another public-feed workflow, see Weibo feed snapshots. For influencer price research, Collabstr provides a different kind of evidence from engagement counts.
For saving Threads post observations, see the Node.js example. Use the current input fields above if the example differs.
Frequently asked questions
Does keyword search return every matching Threads post?
No. Logged-out keyword search exposes roughly the top 30 posts per keyword, so it is a discovery sample rather than a complete archive.
Does postedAfter prevent duplicates across runs?
No. It filters by date. Store post IDs in your destination to deduplicate overlapping runs.
Why does the dataset include rows without post text?
Profile inputs return profile records as well as posts. Separate rows using type before analyzing post counts or engagement.
