# Threads Profile Scraper: Posts, Views, Likes, $1.50/1K (`transparent_meteorite/threads-profile-scraper`) Actor

Scrape public Threads profiles and posts without login: post text, views, likes, replies, reposts, quotes, media URLs, hashtags, links, exact date, plus followers, bio and verified flag. Filter by date, monitor for new posts. No API key, no cookies. Flat price, no start fee.

- **URL**: https://apify.com/transparent_meteorite/threads-profile-scraper.md
- **Developed by:** [Detroit Web Agent - Open Data](https://apify.com/transparent_meteorite) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Threads Profile Scraper: Posts, Views, Likes, Replies and Follower Stats

![Threads Profile Scraper: features, price and a real output row](https://api.apify.com/v2/key-value-stores/9BAn0msnxToXlD9TO/records/sf-threads-profile-scraper-banner-10141249.png)

[![Run it free on Apify](https://api.apify.com/v2/key-value-stores/9BAn0msnxToXlD9TO/records/sf-cta.png)](https://console.apify.com/actors/8btPq90wxGXFjcLpV/input)

| Price per 1,000 posts | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| **This Actor** | **$1.50** | **$1.40** | **$1.20** | **$1.00** |
| Most-used alternative | $2.50 | $2.50 | $2.50 | $2.50 |

<sub>Pay per event, no monthly rental. Prices read from each Actor's public Apify pricing on 2026-10-13; check the Pricing tab for the current figure.</sub>

![Threads Profile Scraper sample output table from a real run](https://api.apify.com/v2/key-value-stores/9BAn0msnxToXlD9TO/records/sf-threads-profile-scraper-output-10141249.png)

Scrape public Threads profiles and their posts without logging in. Give it a list of usernames and get one clean row per post: text, view count, likes, replies, reposts, quotes, shares, exact publish time, media URLs, hashtags, links and the full author block (followers, bio, bio links, verified flag, profile picture). No Threads account, no cookies, no API key and no browser to maintain.

The price is flat at **$1.50 per 1,000 posts on the Free plan and falling to $1.00 per 1,000 on the Gold plan and above**. There is no per-run start fee beyond Apify's own platform event, and you are never charged for a missing account, a failed page, a post filtered out by date or a post already delivered by an earlier monitor run.

### Run in 30 seconds

1. Click **Try for free** and leave the prefilled username `zuck` in place, or type your own list under **Usernames**.
2. Press **Start**. The run finishes in well under a minute for a normal list.
3. Open the **Overview** tab for a table, or export JSON, CSV or Excel from the **Export** button.

That is the whole setup. The default input returns the 20 newest posts of the profile with view counts and the complete profile block on every row.

### What you get for every post

| Group | Fields |
|---|---|
| Post | `id`, `code`, `url`, `text`, `createdAt`, `createdAtTimestamp`, `createdAtDisplay`, `language`, `topicTag`, `isEdited`, `isPinned`, `isReply`, `isQuotePost`, `isRepost`, `replyControl`, `canReply` |
| Engagement | `viewCount`, `viewCountStatus`, `likeCount`, `replyCount`, `repostCount`, `quoteCount`, `shareCount` |
| Media | `hasMedia`, `mediaType` (text, image, video, carousel), `mediaCount`, `mediaUrl`, `mediaUrls`, `media` (type, URL, thumbnail, size and alt text for each item), `mediaWidth`, `mediaHeight`, `hasAudio`, `videoDuration`, `altText`, `audioTitle`, `musicTitle` |
| Content signals | `hashtags`, `mentions`, `links`, `externalLinks`, `linkPreview`, `poll`, `quotedPostUrl`, `quotedPostText`, `repostedPostUrl`, `replyToUsername` |
| Author profile | `username`, `userId`, `displayName`, `profileUrl`, `isVerified`, `isPrivate`, `followersCount`, `bio`, `bioLinks`, `profilePicUrl`, `profilePicHdUrl`, `profileTags` |
| Housekeeping | `type`, `sourceTab`, `requestedUsername`, `scrapedAt` |

Around 80 columns are available in total, and more than 50 are filled on a typical text-and-image post. Fields that do not apply to a post (a poll on a plain text post, for example) come back empty instead of being dropped, so every row has the same shape and loads cleanly into a spreadsheet or database.

### Input

| Field | What it does |
|---|---|
| `usernames` | Threads usernames, `@handles` or profile links. One per line. Duplicates are removed. |
| `startUrls` | The same, in URL-list form. Profile links such as `https://www.threads.com/@zuck` are accepted. |
| `maxPosts` | Posts to return per profile, newest first. Default 20, up to 100,000. |
| `oldestPostDate` | A date (`2025-01-31`) or a relative period (`24 hours`, `7 days`, `2 weeks`, `3 months`, `1 year`). Older posts are skipped and not charged. Pinned posts are always kept. |
| `includeViewCounts` | On by default. Opens each post page to read its view count. Turn it off for the fastest possible listing. |
| `maxConcurrency` | How many post pages load at once for view counts. Default 8. |
| `monitorMode` and `stateStoreName` | Only deliver posts that earlier runs have not delivered. Use one store name per schedule. |
| `autoProxyFallback` and `proxyConfiguration` | Apify datacenter proxy is used by default. If Threads starts rate-limiting it, the run switches itself to residential proxy. |

### Pricing

Pay per event. You pay for results, not for compute time or monthly rental. Rates per 1,000 delivered rows, by Apify plan:

| Plan | Price per 1,000 |
|---|---|
| Free | $1.50 |
| Starter | $1.40 |
| Scale | $1.20 |
| Business and above | $1.00 |

Platform costs such as the tiny run-start event and any residential proxy traffic are billed by Apify at their own published rates. A run that finds nothing, or only already-seen posts in monitor mode, costs nearly nothing. Set a maximum charge per run in the run options and the Actor stops cleanly when it reaches it.

### Use it from code, schedules or AI agents

The Actor works with the Apify API, the official JavaScript and Python clients, schedules, webhooks, Zapier, Make and n8n. It is also exposed as a tool to AI agents through the Apify MCP server, so an assistant can call it with a username and get structured rows back.

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("transparent_meteorite/threads-profile-scraper").call(
    run_input={"usernames": ["zuck", "nasa"], "maxPosts": 50, "oldestPostDate": "30 days"}
)
for post in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(post["username"], post["createdAt"], post["viewCount"], post["likeCount"], post["text"][:80])
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('transparent_meteorite/threads-profile-scraper').call({
  usernames: ['zuck'],
  maxPosts: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'posts');
```

### Who uses it and why

- **Brand and social teams** track what a competitor, a creator or their own account posts, with views and likes per post, and compare it week over week.
- **Influencer and partnership researchers** pull follower counts, bios, bio links and recent post performance for a shortlist of creators before a deal. The paid-partnership flag is included on every post.
- **Journalists and analysts** archive the public statements of officials, companies and newsmakers with exact timestamps and permalinks.
- **Agencies** schedule a daily run in monitor mode on a client list and receive only posts published since the last run.
- **Dataset builders** collect post text, language, hashtags and engagement for classification, sentiment or trend work. Each row is flat JSON that loads straight into a notebook or warehouse.

### How the input fields work together

Use `usernames` for plain handles and `startUrls` for links you already have. You can fill both in one run, and each profile gets its own `maxPosts` limit. Every run reads the profile page first, which gives the profile block and the newest posts, then loads further pages of the same public feed until it has enough posts, runs out, or reaches the date cutoff.

With `oldestPostDate` set, paging stops as soon as a whole page is older than the cutoff, so a 7-day window on a quiet account costs one or two requests. Pinned posts are kept regardless of age because Threads lists them first, and they are labelled with `isPinned`.

`includeViewCounts` is the main speed switch. The public feed does not carry view counts, so with the switch on, each post page is opened once to read its count. Those requests run in parallel (`maxConcurrency`) and the run still finishes quickly. With the switch off, `viewCount` is empty and `viewCountStatus` says `unavailable`; everything else is identical and the price is the same.

Monitor mode stores the post codes already delivered in a named key-value store. The next run with the same store name returns only newer posts. Entries older than a year are dropped automatically.

### Worked examples

**Latest posts of a few accounts**

```json
{ "usernames": ["zuck", "nasa", "mosseri"], "maxPosts": 20 }
```

**Last 30 days of a brand account, with views**

```json
{ "usernames": ["natgeo"], "maxPosts": 100, "oldestPostDate": "30 days" }
```

**Fast listing without view counts**

```json
{ "usernames": ["zuck", "nasa"], "maxPosts": 40, "includeViewCounts": false }
```

**Daily schedule, only new posts**

```json
{ "usernames": ["zuck"], "maxPosts": 50, "monitorMode": true, "stateStoreName": "threads-daily-brand-watch" }
```

### Sample row

```json
{
  "type": "post",
  "code": "DeZtp-TkQHh",
  "url": "https://www.threads.com/@zuck/post/DeZtp-TkQHh",
  "text": "Introducing Muse Wonder, our new family of frontier models ...",
  "createdAt": "2026-10-12T16:56:29.000Z",
  "viewCount": 117629,
  "likeCount": 1889,
  "replyCount": 294,
  "repostCount": 134,
  "quoteCount": 53,
  "shareCount": 136,
  "mediaType": "image",
  "replyControl": "everyone",
  "username": "zuck",
  "displayName": "Mark Zuckerberg",
  "isVerified": true,
  "followersCount": 5746955,
  "bio": "Mostly superintelligence and MMA takes"
}
```

### Choosing what to keep

Most analyses need only a handful of columns. The default **Overview** table shows the profile picture, username, link, text, date, views, likes, replies, reposts, media type, followers and the verified flag. Use the API `fields` parameter or the Export dialog to keep just the columns you need, and the `omit` parameter to drop heavy ones such as `media` or `profileTags`.

### Reading the engagement numbers

`likeCount`, `replyCount`, `repostCount`, `quoteCount` and `shareCount` are the public counters Threads shows under each post. `repostCount` counts plain reposts, `quoteCount` counts reposts with a comment, and `shareCount` counts shares out of the app. A simple engagement rate for a post is `(likeCount + replyCount + repostCount + quoteCount) / followersCount`, and because the follower count sits on every row you can compute it in a spreadsheet column with no second lookup. `viewCount` lets you go one step further and divide by views for a reach-based rate.

To compare accounts, run several usernames in one go with the same `maxPosts`, then group the dataset by `username`. Averages of `viewCount` and `likeCount` per account are enough for a first ranking, and `createdAt` lets you check posting frequency. For trend work, schedule a daily run with monitor mode and append each day's rows to one table; the post `code` is a stable key.

### Cleaning and joining the data

Timestamps are ISO 8601 in UTC (`createdAt`) with the raw Unix value alongside (`createdAtTimestamp`). `hashtags` and `mentions` are arrays of plain strings without the leading symbol. `links` lists the full URLs found in the post, while `linkPreview` holds the card Threads shows for the first link. `media` is a list with one entry per image or video, so a carousel has several. If you only need one picture per post, use `mediaUrl`. Use `userId` as the stable account key, because usernames can be renamed.

### Tips to keep runs fast and cheap

- Put many usernames in one run. Profile pages are fetched one after another, but the posts inside each profile load in parallel, so one run is cheaper than many small runs.
- Turn view counts off when you only need text, dates and likes.
- Use `oldestPostDate` for recurring runs instead of a huge `maxPosts`.
- Use monitor mode for schedules. You pay only for new posts.
- Set a maximum charge per run when you test a new list.

### Limits and honest caveats

- Only public profiles are read. Private accounts return a profile row with `isPrivate` set and no posts.
- The Threads tab is read: a profile's own posts and self-replies. Replies to other people, the reposts tab and keyword search are not covered.
- Threads decides how far back a logged-out visitor can page. Very large accounts return recent history reliably; if the feed stops early, the run says so in its warnings and delivers everything it did get.
- View counts are the numbers Threads shows publicly and are rounded or hidden for some posts. When a post has none, `viewCount` is empty.
- Follower counts update with Threads' own caching, so they can differ by a few from the app at the same moment.
- Data is public information shown to any visitor. Use it in line with Threads' terms and local data-protection law, especially when personal data is involved.

### More questions

**Do I need a Threads account or cookies?** No. The Actor reads only what a logged-out visitor sees.

**Why is a post missing?** Posts that are deleted, restricted or hidden from logged-out visitors are not returned. Posts older than your date cutoff are skipped on purpose.

**Why do two runs show slightly different like counts?** The counts are live. A post gaining likes between runs changes the number.

**Can I get replies or search by keyword?** Not in this version. It focuses on profiles and their posts.

**What happens if Threads blocks the datacenter IP?** With automatic fallback on, the run retries through residential proxy and carries on. The residential traffic is billed by Apify.

### FAQ

**How fast is it?** A 20-post profile with view counts typically finishes in 10 to 20 seconds, and 100 posts in under a minute.

**Is the data JSON-ready?** Yes. Every row is flat JSON with consistent keys, and the dataset exports to CSV, Excel, XML and HTML.

**Can I schedule it?** Yes. Use Apify schedules with monitor mode for a daily feed of new posts.

**Where do I report a problem?** Open an issue on the Actor page with the username and run link, and it will be looked at.

### More resources

- [Apify API documentation](https://docs.apify.com/api/v2)
- [Schedules](https://docs.apify.com/platform/schedules) and [webhooks](https://docs.apify.com/platform/integrations/webhooks)
- [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) for AI agents

New to Apify? [Create a free account](https://console.apify.com/sign-up?fpr=rnmakg) and run this Actor in under a minute. Some links are affiliate links.

# Actor input Schema

## `usernames` (type: `array`):

Threads usernames (zuck), @handles or profile links (threads.com/@zuck). One per line.

## `startUrls` (type: `array`):

Same as Usernames, in URL-list form. Profile links like https://www.threads.com/@zuck.

## `maxPosts` (type: `integer`):

How many posts to return from each profile, newest first. Profiles with fewer posts return what exists.

## `oldestPostDate` (type: `string`):

A date (2025-01-31) or a relative period (24 hours, 7 days, 2 weeks, 3 months, 1 year). Older posts are skipped and not charged. Pinned posts are always kept.

## `includeViewCounts` (type: `boolean`):

On (default): opens each post page to read its view count (one extra request per post, run in parallel). Off: faster, view count left empty. Same price.

## `maxConcurrency` (type: `integer`):

How many post pages to load at once for view counts.

## `monitorMode` (type: `boolean`):

Remembers posts delivered by earlier runs (in a named key-value store) and only returns and charges new ones. Ideal for schedules.

## `stateStoreName` (type: `string`):

Use a different name per schedule if you monitor different profiles.

## `directFirst` (type: `boolean`):

On by default: the run starts without a proxy (fastest) and switches to the proxy below, then to residential, only if Threads blocks or times out. Turn off to always use the proxy.

## `autoProxyFallback` (type: `boolean`):

On by default: if Threads starts rate-limiting the datacenter IP, the run switches itself to Apify residential proxy instead of returning errors. Residential traffic is billed by Apify separately.

## `proxyConfiguration` (type: `object`):

Apify datacenter proxy is used by default and is enough for normal runs. Change it only to force a country or group.

## Actor input object example

```json
{
  "usernames": [
    "zuck"
  ],
  "maxPosts": 20,
  "includeViewCounts": true,
  "maxConcurrency": 8,
  "monitorMode": false,
  "stateStoreName": "threads-profile-scraper-seen",
  "directFirst": true,
  "autoProxyFallback": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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

```javascript
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 = {
    "usernames": [
        "zuck"
    ],
    "maxPosts": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("transparent_meteorite/threads-profile-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

```python
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 = {
    "usernames": ["zuck"],
    "maxPosts": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("transparent_meteorite/threads-profile-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

```bash
echo '{
  "usernames": [
    "zuck"
  ],
  "maxPosts": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call transparent_meteorite/threads-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,transparent_meteorite/threads-profile-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/8btPq90wxGXFjcLpV/builds/Kgmaq5B2rdjkiRcBI/openapi.json
