# Threads Scraper — Search, Posts & Profiles · No Login (`memo23/threads-scraper`) Actor

Search Threads by keyword or hashtag, or scrape a whole account's posts and replies, with no login. Paste handles, post URLs, search URLs or tags. Date windows and like or reply floors drop junk before billing. Each row has the text, author, likes, replies and media. JSON, CSV or Excel.

- **URL**: https://apify.com/memo23/threads-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Social media, Lead generation, AI
- **Features:** Limited permissions
- **Stats:** 151 total users, 34 monthly users, 98.7% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $2.50 / 1,000 post scrapeds

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 Scraper — Search, Posts & Profiles

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/threads/logo.png" width="130" alt="Threads Scraper">
</p>

Search **Threads** by keyword or hashtag, or scrape a whole account — **without a login, cookies, or an account**. Paste handles, post URLs, search URLs or tags. Each row: text, like/reply/repost counts, media, timestamps and author. JSON, CSV or Excel.

### Why use this scraper

- **No login, no cookies.** Nothing to configure and no account to keep alive.
- **Whole-account in one run, no 25-post cap.** Point it at any set of usernames and pull their posts or replies together, as far back as the row cap you set. 200 posts from @zuck reach back to August 2023. Many Threads scrapers stop at the first 25.
- **Find posts without knowing the author.** Search any keyword or hashtag and get matching posts from across Threads — brand monitoring and social listening, not just known handles.
- **Paste any Threads URL.** One `startUrls` box accepts profiles, posts, `/search?q=…` and `/tag/…` and routes each automatically.
- **Drop zero-engagement filler.** `minLikes` / `minReplies` filter keyword search before billing.
- **Structured output.** One row per post with a stable schema — ready for analysis, monitoring, or feeding an AI agent.
- **Post-level detail.** Paste a Threads post URL to pull the post and its whole reply thread.
- **Filter by date.** Set a publication window and posts outside it are dropped **before** they reach your dataset, so you are never charged for rows you asked not to receive.
- **It tells you when it fails.** See below — this is the part that actually costs people money.

### You are not billed for empty runs

A Threads target does not fail loudly. When one is gated, a run can look
successful and still return nothing, and keep charging for it. That is the
single most common complaint on competing Threads actors, up to public requests
for refunds after a hundred-plus consecutive billed runs produced no data.

This actor treats that as a failure:

- **Every target returning nothing fails the run.** You get a `FAILED` status and a message naming the cause, instead of a green run with an empty dataset.
- **Partial failures are reported.** If 3 of 10 targets come back empty, the run still succeeds — you keep the rows you got — but the status message says `7/10 targets`, so a target that has gone empty is visible before the whole run is.
- **Date-filtered rows are never charged.** Filtering happens before billing, and the run tells you how many posts the window excluded.
- **Your cost cap is honoured cleanly.** At `maxTotalChargeUsd` the run stops and finishes normally with the rows you paid for, rather than overrunning into a killed run.
- **A short timeout doesn't kill the run.** About 30 seconds before the run's timeout the actor stops starting new targets, finishes, and says so in the status message, so you keep a clean SUCCEEDED run with the rows it got.
- **Login-walled profiles are reported, not failed.** Some accounts are visible only to logged-in users. A run made only of those ends SUCCEEDED with a status message naming them, because nothing is broken.
- **No padding.** Threads' post pages embed a "more like this" carousel of unrelated posts. Those are excluded by design — they would inflate your dataset and your bill. Rows are also deduplicated by post ID.

### Coming from another Threads scraper?

These are the things users most often ask for on other Threads actors. This actor
already returns all of them:

| What people ask for elsewhere | Field here | Notes |
|---|---|---|
| More than 25 posts per account | `maxItems` | Pages through the whole profile, newest first, until your cap |
| A stable numeric user ID | `userId` | Populated on every row, not just some |
| Real reply / repost / quote counts | `replyCount`, `repostCount`, `quoteCount` | Actual values, not zeros |
| Reshare counts | `reshareCount` | Where Threads exposes it |
| A working "is this a reply" flag | `isReply` | Verified against Threads' own flag across live posts |
| A direct link to each post | `url` | Built on every row |
| Top vs Recent search ranking | `searchSortType` | Both supported |
| Date / datetime filtering | `postedAfter`, `postedBefore` | Applied before billing |
| Sortable timestamps | `publishedAt`, `takenAtTimestamp` | ISO 8601 and epoch seconds |

**View counts are not available.** Threads does not expose them to logged-out
requests — the field simply is not in the response. Any actor that promises view
counts without a logged-in session cannot be reading them from Threads. We would
rather tell you that than ship a column of nulls.

### What it does

| Input | Mode | You get |
|---|---|---|
| Usernames | **Posts** | Each user's Threads posts, as many as `maxItems` allows (no 25-post cap) |
| Usernames | **Replies** | Each user's replies, paged the same way |
| Usernames | **Profile info** | Full name, follower count, bio, verification, profile picture |
| Usernames | **Reposts** | The threads each user reposted, with who reposted them and when, plus one summary row per user with the repost count |
| Post URLs | (automatic) | The post, plus its full reply thread unless you turn replies off |
| Search keywords | (automatic) | Posts mentioning each term, from any author |
| Hashtags | (automatic) | Posts under each tag |
| Profile search keywords | (automatic) | Accounts matching each keyword: username, full name, verification, avatar |

### How it works

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/threads/how-it-works.png" width="820" alt="How the Threads Scraper works">
</p>

You give it Threads usernames, post URLs, keywords or hashtags. Profiles, posts, searches and tags all come back as the same flat row: text, author, counts and media. No login and no account.

### Input

| Field | Type | Description |
|---|---|---|
| `usernames` | array | Threads handles, `@handles`, or profile URLs. Each is scraped per **mode**. |
| `mode` | select | `posts` (default), `replies`, `reposts` or `profile`. Applies to `usernames` only. |
| `postUrls` | array | Threads post URLs (`https://www.threads.com/@user/post/CODE`). `threads.net` links work too. |
| `includeReplies` | boolean | For post URLs: `true` (default) returns the post **plus every reply** in its conversation; `false` returns just the post you asked for. See the note below. |
| `searchQueries` | array | Keywords or phrases to search for — returns matching posts from any author. |
| `hashtags` | array | Hashtag feeds to pull, with or without the leading `#`. |
| `profileSearchQueries` | array | Keywords for finding accounts, 10 accounts per keyword. |
| `searchSortType` | select | For keyword searches: `top` (default) or `recent`. Hashtag feeds are unaffected. |
| `postedAfter` | string | Keep only posts published on or after this date. `YYYY-MM-DD` or a full ISO timestamp. |
| `postedBefore` | string | Keep only posts published on or before this date. A bare `YYYY-MM-DD` includes the whole day. |
| `maxItems` | integer | Max rows for each target (each username, post URL, search query and hashtag). For usernames the actor keeps paging until it reaches this number or the end of the profile. |
| `proxy` | object | Datacenter (default) works and is fast; switch to Residential for very high volume. |

> **How many rows will a post URL return?** With `includeReplies` on (the default), one post URL returns the whole conversation — typically **5–30 rows**, since active threads have many replies. If you only want the posts you pasted, set `includeReplies` to `false` and you'll get exactly one row per URL. `maxItems` caps the rows for each URL either way.

> **How far back does a username go?** As far as `maxItems` reaches. Threads serves a profile 15 threads at a time and the actor keeps loading pages until the cap, the end of the profile, or the start of your `postedAfter` window, whichever comes first. With `postedAfter` set, it stops paging once a whole page is older than the window, so a narrow window costs a page or two, not the account's whole history.

> **Date filtering works on every input type** — search, hashtags, profiles and post URLs alike. Posts Threads returns without a timestamp are kept rather than silently dropped, so a filtered run never quietly loses rows you can't account for. The run's status message reports how many posts the window excluded.

#### Example input

```json
{
  "usernames": ["zuck", "mosseri"],
  "mode": "posts",
  "maxItems": 100
}
```

Keyword and hashtag discovery, no handle needed:

```json
{
  "searchQueries": ["climate change"],
  "hashtags": ["coffee"],
  "searchSortType": "recent",
  "maxItems": 200
}
```

Just the posts you pasted, one row each:

```json
{
  "postUrls": ["https://www.threads.com/@zuck/post/DakyAavlKLZ"],
  "includeReplies": false
}
```

### Output

Each post row includes:

| Field | Description |
|---|---|
| `postId`, `code`, `url` | Post identifiers + canonical Threads URL |
| `username`, `userId`, `userFullName`, `userIsVerified` | Author |
| `text` | Post text |
| `publishedAt`, `takenAtTimestamp` | ISO timestamp + unix |
| `likeCount`, `replyCount`, `repostCount`, `quoteCount` | Engagement — real counts, not placeholder zeros |
| `reshareCount` | Reshares. Threads populates this on some posts only, so expect nulls |
| `isReply`, `replyToAuthor` | Reply context |
| `mediaCount`, `mediaUrls` | Attached images/videos |
| `linkPreviewUrl` | Link preview target, if any |
| `hasAudio` | Whether attached video carries audio |
| `scrapedFromMode` | Which input produced the row: `posts`, `replies`, `reposts`, `reposts-summary`, `thread`, `search`, `hashtag` or `profile-search` |
| `searchQuery` | The keyword or `#hashtag` that matched — on discovery rows only |

Rows from `mode: "profile"` are account records rather than posts, and carry `username`, `userId`, `fullName`, `isVerified`, `followerCount`, `biography`, `profilePicUrl` and `profileUrl`.

#### Sample output

```json
{
  "postId": "3937491905269768921",
  "code": "DakyAavlKLZ",
  "url": "https://www.threads.com/@zuck/post/DakyAavlKLZ",
  "username": "zuck",
  "userIsVerified": true,
  "text": "Today we're releasing Muse Spark 1.1 ...",
  "publishedAt": "2026-07-09T14:00:34.000Z",
  "likeCount": 2767,
  "replyCount": 412,
  "repostCount": 88,
  "quoteCount": 19,
  "reshareCount": 7,
  "isReply": false,
  "mediaCount": 0,
  "scrapedFromMode": "posts"
}
```

Posts published in a given window only:

```json
{
  "searchQueries": ["product launch"],
  "postedAfter": "2026-08-01",
  "postedBefore": "2026-08-14",
  "maxItems": 500
}
```

### Pricing

Pay-per-result — you only pay for what you get. See the **Pricing** tab on the actor page for current rates.

| Event | When you're charged |
|---|---|
| Actor start | Once per run (platform floor) |
| Post scraped | Per row returned in the output. That includes account rows from profile search, and in Reposts mode one summary row per username (`repostsFound`), also when that user has reposted nothing |

### FAQ

**Do I need a Threads or Instagram account?** No. It only reads what Threads serves publicly to logged-out visitors — no login, no cookies.

**Can I scrape a single post and its replies?** Yes — put its URL in `postUrls`. By default you get the post and every reply in its thread; set `includeReplies` to `false` for just the post itself.

**Why did 20 post URLs return 200+ rows?** Because each URL brings back its whole conversation. Threads posts often have dozens of replies. Set `includeReplies` to `false` for one row per URL, or lower `maxItems` to cap the rows each URL can return.

**Can I find posts without knowing who wrote them?** Yes — use `searchQueries` for keywords or `hashtags` for tag feeds. Neither needs a handle.

**A post URL returned nothing. Why?** The post was deleted, made private, or its author's account was removed. The run's status message reports how many targets came back empty. An empty post is retried before it is treated as gone.

**Can I get view counts?** No. Threads does not show view counts unless you are logged in. Likes, replies, reposts, quotes and reshares are included.

**Can I filter by date?** Yes — `postedAfter` and `postedBefore` accept `YYYY-MM-DD` or a full ISO timestamp, and work with every input type. Posts outside the window are dropped before billing, so they cost nothing.

**I set a date range and got zero rows. Is it broken?** Almost certainly not. The status message tells you how many posts were excluded by the window; if that number is large, widen the range. A run that cannot read Threads fails instead of returning an empty dataset.

**Which pricing model?** Pay per result — you only pay for rows returned. See the **Pricing** tab.

### Support

Found a bug or want a new field/mode? Open an issue on the actor's **Issues** tab.

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/threads-scraper`).

**Purpose:** Scrape Threads (threads.com) — user posts, replies, profiles, single post threads, keyword searches, and hashtag feeds — with no login or cookies, returning flat post rows.

**Minimal input:**

```json
{
  "usernames": ["zuck"],
  "mode": "posts",
  "maxItems": 20
}
```

For keyword/hashtag discovery with no handle: `{ "searchQueries": ["climate change"], "hashtags": ["coffee"], "searchSortType": "recent", "maxItems": 20 }`.

**Output:** one row per post with postId, code, url, username, userId, userFullName, userIsVerified, text, publishedAt, takenAtTimestamp, likeCount, replyCount, repostCount, quoteCount, reshareCount, isReply, replyToAuthor, mediaCount, mediaUrls\[], linkPreviewUrl, hasAudio, scrapedFromMode, searchQuery. `mode: "reposts"` returns the original posts with `repostedBy` and `repostedAt`, plus one `reposts-summary` row per username. `profileSearchQueries` rows are accounts (username, userId, fullName, isVerified, profilePicUrl, profileUrl, searchQuery, searchRank). `mode: "profile"` rows are account records (username, userId, fullName, isVerified, followerCount, biography, profilePicUrl, profileUrl).

**Behaviors an agent should know:**

- Always set `maxItems`. It applies to each target separately, so 3 usernames with `maxItems: 50` can return up to 150 rows. A post URL with `includeReplies` on (default) returns the whole conversation (typically 5–30 rows per URL); set `includeReplies: false` for one row per URL.
- `usernames` are scraped per `mode` (`posts`/`replies`/`profile`); `searchQueries` and `hashtags` need no handle. `searchSortType` is `top` or `recent`.
- Every target that returns nothing fails the run (guards against empty-but-billed runs); partial emptiness is reported in the status message.
- `postedAfter`/`postedBefore` (YYYY-MM-DD or ISO) filter before billing, so excluded posts cost nothing.
- View counts are not available to logged-out requests and are never returned.
- Pay-per-result: charged once per run at actor start, then per post row returned; date-filtered and empty results are not charged.

### ⚠️ Disclaimer

This scraper only collects data that is **publicly available** on Threads without logging in. Use it in compliance with Threads' terms and applicable law (including data-protection rules such as GDPR). You are responsible for how you use the data.

### SEO Keywords

threads scraper, scrape threads, threads.com scraper, threads.net scraper, threads api, scrape threads posts, threads post scraper, threads profile scraper, threads replies scraper, threads hashtag scraper, threads keyword search, threads social listening, brand monitoring threads, social media scraper, threads data export, threads content analysis, no-login threads scraper, Apify threads, threads json csv

# Changelog

This Actor's version history is a separate document: https://apify.com/memo23/threads-scraper/changelog.md

# Actor input Schema

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

Profile, post, search or tag URLs — each is routed automatically. <code>https://www.threads.com/@zuck</code>, a <code>/post/…</code> link, <code>/search?q=…</code> or <code>/tag/nba</code>. You can still fill the typed fields below instead.

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

Threads usernames — a handle (zuck), @handle, or full profile URL. Each is scraped according to the Mode below.

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

What to pull for each username: their posts, their replies, their reposts, or just profile info. Reposts returns one summary row per account (with the number of reposts found) plus one row per reposted thread.

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

Threads post URLs (https://www.threads.com/@user/post/CODE) — pulls the post plus its reply thread. threads.net links work too.

## `includeReplies` (type: `boolean`):

On: each post URL returns the post plus every reply in its conversation (typically 5–30 rows per URL). Off: returns only the post you asked for, one row per URL.

## `searchQueries` (type: `array`):

Keywords/phrases to search Threads for — returns posts mentioning each term, from any author. e.g. "climate change", "your brand name".

## `expandQueries` (type: `boolean`):

Threads shows a logged-out visitor only about 20–25 posts per keyword per result page, and will not go further — so a search stops there however high you set the row cap. Different wordings return different posts. On, every keyword is also searched on the other result page, as a joined hashtag, and in its singular/plural form, and the answers are merged and de-duplicated. Several times more unique posts per keyword, within the same row cap you already set. Only affects <b>Search keywords</b>; hashtag feeds are untouched.

## `hashtags` (type: `array`):

Hashtag feeds to pull (with or without the leading #), e.g. "coffee" or "#coffee". Returns recent/top posts under each tag.

## `profileSearchQueries` (type: `array`):

Find Threads accounts by keyword: username, full name, verification and avatar, 10 accounts per keyword. e.g. "coffee", "your brand name".

## `searchSortType` (type: `string`):

For keyword searches: 'Top' (most relevant/engaged) or 'Recent' (newest first). Hashtag feeds are unaffected.

## `postedAfter` (type: `string`):

Keep only posts published on or after this date. Accepts YYYY-MM-DD or a full ISO timestamp.

## `postedBefore` (type: `string`):

Keep only posts published on or before this date. A bare YYYY-MM-DD includes the whole day.

## `minLikes` (type: `integer`):

Drop posts with fewer likes. Useful on keyword search, which returns a lot of zero-engagement filler. 0 = keep everything. Posts with no like count are kept.

## `minReplies` (type: `integer`):

Drop posts with fewer replies. 0 = keep everything. Posts with no reply count are kept.

## `maxItems` (type: `integer`):

Maximum rows for EACH target: each username, post URL, search query and hashtag gets up to this many rows. With 3 usernames and 50 here, a run returns up to 150 rows. To cap what a whole run can spend, set a maximum cost per run when you start it.

## `proxy` (type: `object`):

Residential proxies recommended. The default works out of the box.

## `includeKeywords` (type: `array`):

Only keep posts whose text or username contains at least one of these (case-insensitive). Filtered rows are never charged.

## `excludeKeywords` (type: `array`):

Drop posts whose text or username contains any of these (case-insensitive).

## `maxAgeMinutes` (type: `integer`):

Only keep posts from the last N minutes. Empty or 0 = no age limit. Useful on a tight schedule.

## `incrementalMode` (type: `boolean`):

Remembers every post already delivered to you for this search and returns ONLY what it has not given you before. Schedule the run hourly or daily and you get a clean feed of new posts, with nothing repeated and nothing billed twice. Off = every run returns everything it finds.

## `stateKey` (type: `string`):

Names the memory this run reads and writes, e.g. <code>brand-watch</code>. Runs sharing a name share a history. Leave empty and a name is derived from the search itself, so the same search keeps its own history automatically.

## `emitUnchanged` (type: `boolean`):

On: unchanged posts are returned again (and billed again). Off is what you want for a monitoring feed.

## `emitExpired` (type: `boolean`):

Adds a row for a tracked post that is no longer found. Only meaningful for username runs that page a whole profile — keyword and hashtag searches show a rotating slice, so a post missing from one run has usually just rotated out.

## `skipReposts` (type: `boolean`):

When monitoring, skip a post whose text matches one already seen under a different id.

## `resetIncrementalState` (type: `boolean`):

Wipes this monitoring name's memory, so the next run treats every post as new. Use it after changing what you search for.

## `compact` (type: `boolean`):

Emit only the core fields — small payloads for AI-agent / MCP / LLM pipelines.

## `excludeEmptyFields` (type: `boolean`):

Drop null / empty-string / empty-array fields from each record.

## `descriptionMaxLength` (type: `integer`):

Truncate description fields to this many characters (0 = full text). Controls LLM prompt cost and dataset size.

## `telegramBotToken` (type: `string`):

Your bot's token from @BotFather. With Chat ID set, a summary of new posts is sent after each run.

## `telegramChatId` (type: `string`):

Chat or channel id the bot posts to (e.g. "-1001234567890").

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL (api.slack.com/messaging/webhooks).

## `discordWebhookUrl` (type: `string`):

Discord incoming-webhook URL (Server Settings → Integrations → Webhooks).

## `whatsappAccessToken` (type: `string`):

WhatsApp Cloud API token (Meta Business system user). The recipient must have messaged your business number within the last 24h — Cloud API rule.

## `whatsappPhoneNumberId` (type: `string`):

Your WhatsApp Business phone-number id (numeric, from the Meta dashboard).

## `whatsappTo` (type: `string`):

Recipient phone in E.164 without + (e.g. "14165551234").

## `webhookUrl` (type: `string`):

Receives one JSON POST with { metadata, items } after the run — the universal escape hatch for n8n / Make / Zapier / custom backends.

## `webhookHeaders` (type: `object`):

Optional custom headers for the generic webhook (e.g. {"Authorization": "Bearer …"}).

## `notificationLimit` (type: `integer`):

How many post lines each chat notification includes (1–20). The rest are summarised as a count.

## `notifyOnlyChanges` (type: `boolean`):

With monitoring on, notify only about posts that are new, updated or back.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.threads.com/@zuck"
    }
  ],
  "usernames": [
    "zuck"
  ],
  "mode": "posts",
  "includeReplies": true,
  "expandQueries": false,
  "searchSortType": "top",
  "postedAfter": "2026-01-01",
  "postedBefore": "2026-08-14",
  "minLikes": 0,
  "minReplies": 0,
  "maxItems": 100,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "skipReposts": false,
  "resetIncrementalState": false,
  "compact": false,
  "excludeEmptyFields": false,
  "notificationLimit": 5,
  "notifyOnlyChanges": false
}
```

# Actor output Schema

## `posts` (type: `string`):

One row per post with author handle, full text, like/reply/repost/quote counts, media URLs and publish time.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.threads.com/@zuck"
        }
    ],
    "usernames": [
        "zuck"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/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 = {
    "startUrls": [{ "url": "https://www.threads.com/@zuck" }],
    "usernames": ["zuck"],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/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 '{
  "startUrls": [
    {
      "url": "https://www.threads.com/@zuck"
    }
  ],
  "usernames": [
    "zuck"
  ],
  "maxItems": 100
}' |
apify call memo23/threads-scraper --silent --output-dataset

```

## MCP server setup

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