Threads Profile Scraper — Followers, Bio Links, Recent Posts avatar

Threads Profile Scraper — Followers, Bio Links, Recent Posts

Pricing

$2.00 / 1,000 per profile returneds

Go to Apify Store
Threads Profile Scraper — Followers, Bio Links, Recent Posts

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

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

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 returnedProfiles (2026-08-15, n=30)Profiles (2026-08-18, n=20)
42615
522
610
711
801
1001

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 hid
  • recent_engagement_raterecent_avg_likes ÷ follower_count, to six decimals
  • last_post_at and days_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

GroupFields
Identityusername, user_id (numeric, stable, the dedupe key), full_name, profile_url
Profilebiography, bio_link, bio_links (every link with its label), bio_link_count, topic_tags
Scale & statusfollower_count, total_threads_approx, is_verified, is_private, has_threads_profile, transparency_label
Mediaprofile_pic_url, profile_pic_hd_url
Activityrecent_post_count, last_post_at, days_since_last_post
Engagementrecent_avg_likes, recent_avg_replies, recent_avg_reposts, recent_engagement_rate
Postsrecent_posts[] — see below
Provenancequeried_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)

FieldFill
username, user_id, full_name, profile_url100.0%
biography100.0%
follower_count100.0%
profile_pic_url, profile_pic_hd_url100.0%
total_threads_approx100.0%
last_post_at, days_since_last_post100.0%
recent_avg_likes / _replies / _reposts, recent_engagement_rate100.0%
recent_posts (non-empty)100.0%
is_verified = true93.3% (28 of 30 — a value, not a fill rate)
bio_link / bio_links80.0% (24 of 30)
topic_tags23.3% (7 of 30)
transparency_label0.0% (0 of 30)
is_private = true0.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)

FieldFill
post_id, post_code, post_url, author_username100.0%
text100.0%
posted_at100.0%
like_count, reply_count, repost_count, quote_count100.0%
image_url63.8%
video_url30.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:

MeasureResult
Profiles returned59 of 59 (100%), all within 3 attempts
Single requests that landed the profile59 of 81 (72.8%)
Attempts needed1st try 40, 2nd try 16, 3rd try 3
Residential fallback needed0 times
Duplicate rows0 (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

  1. Click Try for free, then Start — the prefilled input returns 5 rows immediately.
  2. Replace the demo profiles with your own list: a bare username (zuck), an @handle (@natgeo), or a full URL (https://www.threads.com/@openaithreads.net works too). Mixed together is fine.
  3. 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.
  4. Watch the log. Every profile that could not be read is named, and the run prints its own totals at the end.
  5. 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

ModelPay per event — one event, profile-scraped
Rate$0.002 per profile returned ($2.00 per 1,000)
Actor start feenone
Not billedProfiles 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

  1. 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.
  2. total_threads_approx is rounded by Threads, not by us. Threads publishes "1.5K Threads" on the profile's own meta description; we parse it to 1500. It is an approximation to two or three significant figures — use it for banding, not for arithmetic. follower_count is exact.
  3. 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.
  4. Private profiles are reported, not guessed at. is_private is 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 and recent_posts to be empty or short, because Threads does not serve a private account's feed to a logged-out client.
  5. 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.
  6. No e-mail field. Threads publishes no contact e-mail on a profile. bio_links is the contact path — for 80% of profiles it is a website you can then enrich.
  7. 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_posts empty 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.

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.