# Meta Threads Scraper — Posts, Profiles & Engagement (`skipper_lume/threads-scraper`) Actor

Scrape Meta Threads without login. 4 modes: user posts, profiles with engagement rate, full threads with replies, user reply history. Hybrid GraphQL + browser engine. Extract text, likes, reposts, quote counts, images, videos, mentions, follower counts. The deepest Threads data tool on Apify.

- **URL**: https://apify.com/skipper\_lume/threads-scraper.md
- **Developed by:** [Maksym Horbachov](https://apify.com/skipper_lume) (community)
- **Categories:** Social media, SEO tools, Developer tools
- **Stats:** 16 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Threads Scraper — Posts, Profiles & Replies | Engagement Rate | No Login

The deepest **Meta Threads** analytics tool on Apify — no API key, no login, no cookies.

> **$1.50 per 1,000 results**. [See pricing](#pricing).

### Why This Scraper?

| Feature | This Actor | Top competitor |
|---------|:----------:|:--------------:|
| Modes | **4** | 3 |
| Engagement rate | **Yes** | No |
| Quote count | **Yes** | Yes |
| Thread replies | **Yes** | No |
| User replies | **Yes** | No |
| Login required | **No** | No |
| Price per 1k | **$1.50** | $2.00+ |

### 4 Scraping Modes

#### `profiles` — Profile Data + Engagement Rate

Extract bio, follower/following counts, verified status, and **calculated engagement rate** based on the last 20 posts.

```json
{
    "mode": "profiles",
    "profiles": ["zuck", "mosseri"]
}
```

**Sample output:**

```json
{
    "username": "mosseri",
    "fullName": "Adam Mosseri",
    "bio": "Father of three boys, head of Instagram and supporter of Threads.",
    "followerCount": 964700,
    "followingCount": 0,
    "isVerified": true,
    "engagementRate": 0.09,
    "url": "https://www.threads.net/@mosseri"
}
```

#### `posts` — User Timeline Posts

Get recent posts with full engagement metrics including **quote count**.

```json
{
    "mode": "posts",
    "profiles": ["zuck"],
    "maxResults": 20
}
```

**Sample output:**

```json
{
    "id": "3870872187813562164",
    "url": "https://www.threads.net/@zuck/post/DW4Gb79kQc0",
    "text": "Today we're sharing our new model family, Muse...",
    "username": "zuck",
    "userVerified": true,
    "publishedAt": "2026-04-08T15:59:05.000Z",
    "likeCount": 2740,
    "replyCount": 312,
    "repostCount": 89,
    "quoteCount": 45,
    "images": [],
    "videos": [],
    "hashtags": [],
    "mentions": [],
    "isReply": false
}
```

#### `thread` — Full Thread with Replies

Get the original post plus all reply chains — perfect for conversation analysis.

```json
{
    "mode": "thread",
    "postUrls": ["https://www.threads.net/t/C8H5FiCtESk"]
}
```

#### `replies` — User's Replies to Others

See what a user is saying across Threads — all their replies to other people's posts. Great for competitive intelligence and sentiment tracking.

```json
{
    "mode": "replies",
    "profiles": ["mosseri"],
    "maxResults": 50
}
```

### Output Fields

#### Posts & Replies

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique post ID |
| `code` | string | Short code (used in URL) |
| `url` | string | Direct link to the post |
| `text` | string | Full post text |
| `username` | string | Author's handle |
| `userVerified` | boolean | Blue checkmark |
| `publishedAt` | string | ISO 8601 timestamp |
| `likeCount` | number | Total likes |
| `replyCount` | number | Total replies |
| `repostCount` | number | Total reposts |
| `quoteCount` | number | Total quote posts |
| `images` | string\[] | Image CDN URLs |
| `videos` | string\[] | Video CDN URLs |
| `hashtags` | string\[] | Extracted #hashtags |
| `mentions` | string\[] | Extracted @mentions |
| `isReply` | boolean | Is this a reply? |

#### Profiles

| Field | Type | Description |
|-------|------|-------------|
| `username` | string | Threads handle |
| `fullName` | string | Display name |
| `bio` | string | Profile bio text |
| `profilePicUrl` | string | Avatar URL |
| `followerCount` | number | Followers |
| `followingCount` | number | Following |
| `isVerified` | boolean | Verified account |
| `isPrivate` | boolean | Private account |
| `engagementRate` | number | Avg engagement / followers (%) |
| `externalUrl` | string | Website link from bio |

### How It Works

```
Input (usernames, post URLs)
         │
         ▼
   ┌─────────────┐
   │  GraphQL API │ ← Fast, ~0.005 CU/request
   │  + CSRF auth │   Automatic token extraction
   └──────┬──────┘
          │ If blocked or empty response
          ▼
   ┌─────────────┐
   │  Playwright  │ ← Headless browser fallback
   │  + intercept │   Captures API responses from page
   └──────┬──────┘
          │
          ▼
   Structured JSON → Dataset
```

- **GraphQL layer**: extracts CSRF + LSD tokens, sends authenticated API requests
- **Playwright fallback**: headless Chromium with response interception
- **HTML meta fallback**: for profiles — extracts from og:tags when APIs fail
- **Anti-detection**: Chrome 131+ User-Agents, randomized delays, per-request proxy rotation

### Pricing

**$1.50 per 1,000 results** — pay per event.

| Volume | Cost |
|--------|------|
| 100 results | $0.15 |
| 1,000 results | $1.50 |
| 10,000 results | $15.00 |
| 100,000 results | $150.00 |

### Quick Start

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("skipper_lume/threads-scraper").call(run_input={
    "mode": "posts",
    "profiles": ["zuck"],
    "maxResults": 20,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"@{item['username']}: {item['text'][:80]}... ({item['likeCount']} likes)")
```

#### JavaScript

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('skipper_lume/threads-scraper').call({
    mode: 'profiles',
    profiles: ['zuck', 'mosseri'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => {
    console.log(`@${item.username}: ${item.followerCount} followers, ${item.engagementRate}% engagement`);
});
```

### Use Cases

| Industry | Use Case | Mode |
|----------|----------|------|
| **Marketing** | Influencer vetting with engagement rates | `profiles` |
| **PR** | Monitor executive responses | `replies` |
| **Sales** | Prospect research & enrichment | `profiles` + `posts` |
| **Agencies** | Competitor content analysis | `posts` |
| **Research** | Conversation mining | `thread` |
| **Recruiting** | Candidate research | `profiles` + `replies` |

### Integrations

- **Google Sheets** — auto-export
- **Webhooks** — trigger on completion
- **REST API** — programmatic access
- **Zapier / Make / n8n** — automated pipelines
- **Slack / Email** — notifications
- **AWS S3 / Google Cloud** — dataset storage

### Tips

- Use **residential proxies** (RESIDENTIAL group) for best reliability
- Keep `maxResults` at 50–200 for optimal speed
- 1 GB memory is enough for most runs
- Schedule recurring runs for continuous monitoring

### FAQ

**Q: Do I need a Threads account?**
A: No. Public profiles and posts only. No login, no tokens.

**Q: What's engagement rate?**
A: Average (likes + replies) per post divided by follower count, as a percentage. Calculated from the last 20 posts.

**Q: Can I get quote counts?**
A: Yes — `quoteCount` is included in every post. Most competitors don't extract this.

**Q: What's the replies mode for?**
A: It scrapes all replies a user has written to other people's posts. Useful for competitive intelligence — see how executives/influencers interact with others.

**Q: Can I scrape private accounts?**
A: No. Only public profiles and posts.

### Changelog

#### v1.2 (April 2026)

- Added `replies` mode — scrape all replies written by a user
- Added `quoteCount` to post output
- Added `engagementRate` to profile output (auto-calculated from last 20 posts)
- Now 4 modes: profiles, posts, thread, replies

#### v1.1 (April 2026)

- CSRF + LSD token authentication for GraphQL
- Response interception in Playwright
- HTML meta tag fallback for profiles
- Chrome 131+ User-Agents, per-request proxy rotation

#### v1.0 (April 2026)

- Initial release: profiles, posts, thread scraping

# Actor input Schema

## `mode` (type: `string`):

What to scrape from Threads:

- **Profiles** — bio, followers, verified status, engagement rate
- **User Posts** — recent posts with likes, replies, reposts, quotes
- **Thread + Replies** — full conversation thread with all replies
- **User Replies** — all replies a user has written to others

## `profiles` (type: `array`):

Threads usernames or full profile URLs. Works with Profiles, User Posts, and User Replies modes.

Examples: `zuck`, `@instagram`, `https://www.threads.net/@natgeo`

## `postUrls` (type: `array`):

Direct links to Threads posts. Used with Thread + Replies mode.

Example: `https://www.threads.net/t/C8H5FiCtESk`

## `maxResults` (type: `integer`):

Maximum number of results to return per profile or thread.

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

Residential proxies are strongly recommended for reliable results.

## Actor input object example

```json
{
  "mode": "profiles",
  "profiles": [
    "zuck"
  ],
  "postUrls": [
    "https://www.threads.net/t/C8H5FiCtESk"
  ],
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset of scraped Threads data (posts, profiles, replies).

# 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 = {
    "profiles": [
        "zuck"
    ],
    "postUrls": [
        "https://www.threads.net/t/C8H5FiCtESk"
    ],
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

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

```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 = {
    "profiles": ["zuck"],
    "postUrls": ["https://www.threads.net/t/C8H5FiCtESk"],
    "maxResults": 5,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

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

```bash
echo '{
  "profiles": [
    "zuck"
  ],
  "postUrls": [
    "https://www.threads.net/t/C8H5FiCtESk"
  ],
  "maxResults": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call skipper_lume/threads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,skipper_lume/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/AH2J0ViQDuaewqqa6/builds/I5sfhUf23lsSnWwMz/openapi.json
