Threads Profile Scraper — Followers, Bio Links, Recent Posts
Pricing
$2.00 / 1,000 per profile returneds
Threads Profile Scraper — Followers, Bio Links, Recent Posts
Bulk-scrape public Threads (threads.com) profiles by username or URL: follower count, full name, bio, every bio link, verified and private flags, topic tags, plus the 4-10 most recent posts with likes, replies and reposts — and a computed recent engagement rate. $2.00 per 1,000 profiles. No login.
Pricing
$2.00 / 1,000 per profile returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Bulk profile data from Threads, Meta's text network. One row per profile, carrying username, user_id, full_name, biography, follower_count, is_verified, is_private, bio_links, topic_tags, profile_pic_url and the profile's most recent posts — each with text, timestamp, likes, replies, reposts, quotes, media URLs and its permalink.
No login. No cookies. No Instagram account. No CAPTCHA solving.
$0.002 per profile returned — $2.00 per 1,000, no actor-start fee.
{"profiles": ["zuck", "@natgeo", "https://www.threads.com/@openai", "mosseri", "spotify"]}
Click Try for free and hit Start — that block is literally the input this Actor ships with. That run returns 5 rows and costs one cent.
⚠️ Read this first: you get the 4–10 most recent posts, not a post archive
Threads server-renders only the top of a profile's Threads tab, and that is what this Actor reads. Measured on 30 public profiles on 2026-08-15 through Apify proxies, and re-measured on 20 public profiles on 2026-08-18: the embedded feed block carried exactly 4 post cards on every single one of the 50. A card unpacks into more than one post when the author wrote a self-thread, so the real yield was:
| Posts returned | Profiles (2026-08-15, n=30) | Profiles (2026-08-18, n=20) |
|---|---|---|
| 4 | 26 | 15 |
| 5 | 2 | 2 |
| 6 | 1 | 0 |
| 7 | 1 | 1 |
| 8 | 0 | 1 |
| 10 | 0 | 1 |
127 posts across the first 30 profiles (4.2 each); 95 posts across the next 20 (4.8 each).
Correction, 2026-08-18. An earlier version of this page said the feed cursor "cannot be spent and there is no page 2". That was wrong, and it is corrected here rather than quietly deleted: Threads' paginated feed query is reachable logged-out, and a deeper post history is technically possible. It is simply not what this Actor does — deep post history is a different product with a different price and a different failure surface, and shipping it inside a per-profile scraper would change what you are billed for. What this Actor sells is one row per profile with a recency sample attached, and that is what the price and the field table describe.
So: if what you need is a creator's full post archive, this is not that Actor. If what you need is who this account is, how big it is, how to reach them, and whether they are still active, that is exactly what a row is.
The wedge: an engagement rate you can sort on
Every Threads profile scraper on the store hands you follower_count. Follower count alone is the
number that stopped meaning anything years ago. This Actor also computes, per profile, from the
posts it just read:
recent_avg_likes,recent_avg_replies,recent_avg_reposts— the mean across the profile's own recent posts, skipping any post whose counts the author hidrecent_engagement_rate—recent_avg_likes ÷ follower_count, to six decimalslast_post_atanddays_since_last_post— the dead-account filter
Sort a 5,000-handle pull by recent_engagement_rate descending and filter
days_since_last_post < 14, and you have a shortlist of accounts that are both alive and
actually read — which is the list an influencer-marketing or social-listening buyer was going to
build by hand anyway. It costs $10.00 to build for 5,000 handles.
Two honest caveats on that number: it is computed from 4–10 posts, so it is a coarse recent
signal and not a 90-day average; and Threads' like counts move for hours after a post goes up, so a
row scraped 20 minutes after publication under-reads. Both are why the field is called
recent_engagement_rate and not engagement_rate.
What you get — one row per profile
| Group | Fields |
|---|---|
| Identity | username, user_id (numeric, stable, the dedupe key), full_name, profile_url |
| Profile | biography, bio_link, bio_links (every link with its label), bio_link_count, topic_tags |
| Scale & status | follower_count, total_threads_approx, is_verified, is_private, has_threads_profile, transparency_label |
| Media | profile_pic_url, profile_pic_hd_url |
| Activity | recent_post_count, last_post_at, days_since_last_post |
| Engagement | recent_avg_likes, recent_avg_replies, recent_avg_reposts, recent_engagement_rate |
| Posts | recent_posts[] — see below |
| Provenance | queried_handle, scraped_at (ISO-8601 UTC) |
Each entry in recent_posts[]:
post_id · post_code · post_url · author_username · text · posted_at (ISO-8601 UTC) ·
like_count · reply_count · repost_count · quote_count · post_type
(text / image / video / carousel) · image_url · video_url · carousel_count ·
is_paid_partnership · counts_hidden · mentions[] · links[]
Counts are plain integers, timestamps are ISO-8601 UTC strings, arrays are [] when empty, and
anything Threads did not publish is null — never an empty string, never a zero standing in for
"missing".
Field fill — measured, not estimated
30 public profiles (brands, publishers, creators and Meta staff accounts), run through Apify proxies on the shipped defaults, 2026-08-15. Sparse fields in bold.
Profile fields (n = 30)
| Field | Fill |
|---|---|
username, user_id, full_name, profile_url | 100.0% |
biography | 100.0% |
follower_count | 100.0% |
profile_pic_url, profile_pic_hd_url | 100.0% |
total_threads_approx | 100.0% |
last_post_at, days_since_last_post | 100.0% |
recent_avg_likes / _replies / _reposts, recent_engagement_rate | 100.0% |
recent_posts (non-empty) | 100.0% |
is_verified = true | 93.3% (28 of 30 — a value, not a fill rate) |
bio_link / bio_links | 80.0% (24 of 30) |
topic_tags | 23.3% (7 of 30) |
transparency_label | 0.0% (0 of 30) |
is_private = true | 0.0% (this sample was all public accounts) |
topic_tags are the self-declared interest tags Threads shows under a bio ("AI Threads", "UFC
Threads"). Most accounts set none. transparency_label is the state-controlled-media banner — it
appeared on none of these 30, and you should expect it on a small minority of news accounts only.
bio_link is empty on one profile in five because that account published no link.
Re-measured independently on 24 different public profiles, 2026-08-19 (24 of 24 readable, one
pass, no retries needed): bio_link / bio_links 79.2%, topic_tags 20.8%,
transparency_label 0.0% — the same three sparse fields, at the same rates. For each of them
the raw Threads payload was dumped: profile_tags.edges is literally [] on 19 of 24,
transparency_label is literally null on 24 of 24, and bio_links is empty on exactly the 5
accounts that show no link on threads.com. These are properties of the accounts, not gaps in the
scrape.
One caveat the 2026-08-15 table missed: an account can exist on Threads with no bio and no
posts at all. In the 2026-08-19 sample, @lego returned biography: null, recent_post_count: 0
and an empty recent_posts (its raw Threads-tab payload is "edges":[] with
has_next_page: false). So read biography, last_post_at, days_since_last_post,
recent_avg_*, recent_engagement_rate and recent_posts as 95.8% (23 of 24) rather than
100% — a 0 / null there means that profile has published nothing, not that the run failed.
Post fields (n = 127 posts)
| Field | Fill |
|---|---|
post_id, post_code, post_url, author_username | 100.0% |
text | 100.0% |
posted_at | 100.0% |
like_count, reply_count, repost_count, quote_count | 100.0% |
image_url | 63.8% |
video_url | 30.7% |
links (non-empty) | 26.0% |
mentions (non-empty) | 13.4% |
Post types in that sample: 46 text-only, 39 video, 32 image, 10 carousel. The media fields are
sparse because most Threads posts have no media — a null video_url means the post was not a
video, not that the scrape failed.
Transport — what actually happens, with the numbers
Threads intermittently answers a logged-out profile request with its "Threads · Log in" interstitial instead of the profile: a 256–361 KB HTML shell with no data in it. This is transient and per-request — a retry on a fresh proxy session clears it, and the Actor does that for you.
Measured across two independent runs, 59 profiles, through Apify datacenter proxies, with a fresh pinned session on every attempt:
| Measure | Result |
|---|---|
| Profiles returned | 59 of 59 (100%), all within 3 attempts |
| Single requests that landed the profile | 59 of 81 (72.8%) |
| Attempts needed | 1st try 40, 2nd try 16, 3rd try 3 |
| Residential fallback needed | 0 times |
| Duplicate rows | 0 (0 duplicate profiles in 59; 0 duplicate post_id in 127 posts, in-profile and across profiles) |
Read that table honestly: a single HTTP request to Threads succeeds about seven times in ten,
and the Actor gets you to 100% by retrying up to four times on fresh sessions, then falling back to
RESIDENTIAL proxies (capped at max(3, 20% of your list) per run so the fallback cannot run away
with your proxy bill). That is why the per-profile price is flat: you pay for a profile returned,
not for the requests it took.
A handle that fails every rung is named in the log and not billed. Note that Threads serves the same log-in interstitial for a username that does not exist, so from outside those two cases are indistinguishable — the log says exactly that rather than guessing.
Sample row
{"username": "spotify","user_id": "63295417283","full_name": "Spotify","profile_url": "https://www.threads.com/@spotify","biography": "squeezing in a few more summer anthems","follower_count": 3130636,"is_verified": true,"is_private": false,"has_threads_profile": true,"transparency_label": null,"bio_link": "https://open.spotify.com/genre/0JQ5DAqbMKFJ6dHNHTv6Mx","bio_links": [{ "url": "https://open.spotify.com/genre/0JQ5DAqbMKFJ6dHNHTv6Mx", "title": "Fitness with Spotify" },{ "url": "http://open.spotify.com", "title": null },{ "url": "https://open.spotify.com/genre/section0JQ5IMCbQBLyGf0Sj0c3IJ", "title": "Editors’ Picks: Best Audiobooks of the Year so Far" }],"bio_link_count": 3,"topic_tags": [],"profile_pic_url": "https://scontent-lax3-2.cdninstagram.com/v/t51.2885-19/358162502_...jpg","profile_pic_hd_url": "https://scontent-lax3-2.cdninstagram.com/v/t51.2885-19/358162502_...jpg","total_threads_approx": 1100,"recent_post_count": 4,"last_post_at": "2026-08-15T12:59:15.000Z","days_since_last_post": 0,"recent_avg_likes": 28.75,"recent_avg_replies": 1.5,"recent_avg_reposts": 1,"recent_engagement_rate": 0.000009,"recent_posts": [{"post_id": "3964277724764062307","post_code": "DcD8ZZHjkJj","post_url": "https://www.threads.com/@spotify/post/DcD8ZZHjkJj","author_username": "spotify","text": "“Encouragement from other women is the best.” @Rosegray_ is opening up about …","posted_at": "2026-08-15T12:59:15.000Z","like_count": 8,"reply_count": 2,"repost_count": 1,"quote_count": 0,"post_type": "video","image_url": "https://scontent-lax3-2.cdninstagram.com/v/t51.82787-15/774136886_...jpg","video_url": "https://scontent-lax3-2.cdninstagram.com/o1/v/t2/f2/m86/AQPX0P2Uc6fDsnA...","carousel_count": null,"is_paid_partnership": false,"counts_hidden": false,"mentions": ["rosegray_"],"links": []}],"queried_handle": "spotify","scraped_at": "2026-08-15T13:04:41.902Z"}
How to use it
- Click Try for free, then Start — the prefilled input returns 5 rows immediately.
- Replace the demo profiles with your own list: a bare username (
zuck), an@handle(@natgeo), or a full URL (https://www.threads.com/@openai—threads.networks too). Mixed together is fine. - Bulk instead: open 📄 Profile URL list and paste hundreds of URLs, upload a
.txt/.csv, or link a Google Sheet. Entries there must be full Threads URLs — a bare username inside a file is ignored, because a CSV column of names cannot be told apart from data. - Watch the log. Every profile that could not be read is named, and the run prints its own totals at the end.
- Export as JSON, CSV, Excel or HTML, or pull it from the API. The Threads profiles dataset view gives you the flat spreadsheet columns (username, name, followers, verified, bio, bio link, recent posts, last post, avg likes, engagement rate, URL) without the nested post array.
Turning off posts
includePosts: false drops the recent_posts array and the derived engagement fields, for a
slimmer profile-only row. The price is identical — it is the same single page request either
way — so leave it on unless the nested array is inconvenient for your pipeline.
Pricing
| Model | Pay per event — one event, profile-scraped |
| Rate | $0.002 per profile returned ($2.00 per 1,000) |
| Actor start fee | none |
| Not billed | Profiles Threads refused to serve; duplicate handles that resolve to a profile already returned in the same run |
The shipped default input (5 profiles) costs $0.01. 1,000 profiles cost $2.00. Nothing else is metered — posts, bio links and the computed engagement fields all ride along inside the profile row at no extra charge.
Comparable live Threads profile rows on the store on 2026-08-15 ran from $0.0005 to $0.01 per item, with the lane leader at $0.005.
Honest limits
- 4–10 posts per profile — the recency sample, not an archive. Restated here because it is the single thing most likely to disappoint: this Actor reads the server-rendered top of the Threads tab and does not page back, so buying more rows does not buy more posts per row. Deep post history is reachable on Threads but is deliberately out of scope here (see the correction in the first section) and belongs in a separate post-history Actor.
total_threads_approxis rounded by Threads, not by us. Threads publishes "1.5K Threads" on the profile's own meta description; we parse it to1500. It is an approximation to two or three significant figures — use it for banding, not for arithmetic.follower_countis exact.- Like counts are a moving target. A post scraped minutes after publication has not finished accumulating likes. If you are comparing accounts, compare rows scraped in the same window.
- Private profiles are reported, not guessed at.
is_privateis Threads' own flag and is passed through as-is. All 30 profiles in the measured sample were public, so the shape of a private row is not something this page has measured — expect identity and follower count to be present andrecent_poststo be empty or short, because Threads does not serve a private account's feed to a logged-out client. - Discovery is not included. You bring the usernames. This Actor does not search Threads and does not enumerate followers, because logged-out Threads search is hard-capped and returns no pagination cursor — a search mode here would quietly truncate, so there isn't one.
- No e-mail field. Threads publishes no contact e-mail on a profile.
bio_linksis the contact path — for 80% of profiles it is a website you can then enrich. - This Actor returns profile data only — no replies, no follower lists, no hashtag or search feeds. Those are separate Threads surfaces and belong in their own Actors.
How it works
GET https://www.threads.com/@<username> returns a fully server-rendered page with the profile
record and the top of the profile's feed embedded as JSON inside Meta's RelayPrefetchedStreamCache
blocks. The Actor slices those two blocks out structurally (balanced-bracket scan, so a } inside a
string can never truncate the object), parses them, and builds one row.
That is the whole mechanism: no headless browser, no GraphQL token mint, no login, no cookie jar. The Actor runs in 512 MB. What it costs in reliability is the retry loop described in the transport section — which is a cheaper price than a 4 GB Chromium.
When a run comes back short
- Some profiles named "not readable" — either those usernames do not exist on Threads (an account has to opt in to Threads separately from Instagram), or Threads walled every session for them. Re-run just those handles; a fresh run gets fresh sessions.
- A run fails with "No Threads profiles returned" — that is deliberate. The Actor fails loudly rather than finishing green with an empty dataset. Check the usernames actually exist by opening one in a browser, then re-run.
recent_postsempty on a row — the account is private, or has posted nothing.- Fewer posts than you expected — see the first section. 4 is the normal number.
Who buys this
- Influencer / creator discovery — score and rank a candidate list by real recent engagement instead of follower count, and drop the accounts that have gone quiet.
- Social listening & brand monitoring — a repeatable daily snapshot of a watchlist: follower trajectory, posting cadence, what they said last and how it landed.
- Competitive research — the same fields for a competitor's account and everyone they mention.
- Lead enrichment — turn a list of Threads handles into names, bios and the websites in their bio links, which is the joinable key into the rest of your stack.
Legal & fair use
Read this before you run it. https://www.threads.com/robots.txt opens with:
# Notice: Collection of data on Threads through automated means is prohibited unless you have# express written permission from Threads and may only be conducted for the limited purpose# contained in said permission.
and its wildcard rule is:
User-agent: *Disallow: /
There is no allowed path in that file for a generic client — the per-path Disallow lists
further down apply only to named search-engine crawlers. This Actor reads pages that are public and
require no login, and it does not authenticate, does not solve challenges and does not touch private
data — but it is not operating inside a robots.txt allowance, and this page will not pretend
otherwise. Whether that is acceptable for your use is your decision to make against Meta's Terms of
Service and your own legal advice.
Profile records can contain personal data — a person's name, photograph, biography and links. You are responsible for how you store and use them, including GDPR, CCPA and the rules that apply to any outreach you do with them.
Threads® and Instagram® are trademarks of Meta Platforms, Inc. This Actor is not affiliated with, endorsed by, or connected to Meta.
Feedback
Found a missing field, or want a filter? Open an issue on the Issues tab. If the Actor earns it, a review on the Reviews tab helps other buyers find it.