{
  "openapi": "3.0.1",
  "info": {
    "title": "Threads Scraper — Posts, Replies & Profiles, No Login",
    "description": "Threads Scraper: posts, replies and profiles from threads.com, no login or cookies. No 25-post cap: it pages through whole accounts. Usernames, post URLs, keywords or hashtags in; flat rows out with text, like/reply/repost/quote counts, media and timestamps. JSON, CSV, Excel.",
    "version": "0.1",
    "x-build-id": "ClPDTbaB1TwB6zoUh"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/memo23~threads-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-memo23-threads-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/memo23~threads-scraper/runs": {
      "post": {
        "operationId": "runs-sync-memo23-threads-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/memo23~threads-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-memo23-threads-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "startUrls": {
            "title": "Any Threads URLs",
            "type": "array",
            "description": "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.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "usernames": {
            "title": "Usernames",
            "type": "array",
            "description": "Threads usernames — a handle (zuck), @handle, or full profile URL. Each is scraped according to the Mode below.",
            "items": {
              "type": "string"
            }
          },
          "mode": {
            "title": "Mode (for usernames)",
            "enum": [
              "posts",
              "replies",
              "profile",
              "reposts"
            ],
            "type": "string",
            "description": "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.",
            "default": "posts"
          },
          "postUrls": {
            "title": "Post URLs",
            "type": "array",
            "description": "Threads post URLs (https://www.threads.com/@user/post/CODE) — pulls the post plus its reply thread. threads.net links work too.",
            "items": {
              "type": "string"
            }
          },
          "includeReplies": {
            "title": "Include reply thread (for post URLs)",
            "type": "boolean",
            "description": "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.",
            "default": true
          },
          "searchQueries": {
            "title": "Search keywords",
            "type": "array",
            "description": "Keywords/phrases to search Threads for — returns posts mentioning each term, from any author. e.g. \"climate change\", \"your brand name\".",
            "items": {
              "type": "string"
            }
          },
          "expandQueries": {
            "title": "🔁 Ask each keyword several ways",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "hashtags": {
            "title": "Hashtags",
            "type": "array",
            "description": "Hashtag feeds to pull (with or without the leading #), e.g. \"coffee\" or \"#coffee\". Returns recent/top posts under each tag.",
            "items": {
              "type": "string"
            }
          },
          "profileSearchQueries": {
            "title": "Profile search keywords",
            "type": "array",
            "description": "Find Threads accounts by keyword: username, full name, verification and avatar, 10 accounts per keyword. e.g. \"coffee\", \"your brand name\".",
            "items": {
              "type": "string"
            }
          },
          "searchSortType": {
            "title": "Search ranking",
            "enum": [
              "top",
              "recent"
            ],
            "type": "string",
            "description": "For keyword searches: 'Top' (most relevant/engaged) or 'Recent' (newest first). Hashtag feeds are unaffected.",
            "default": "top"
          },
          "postedAfter": {
            "title": "Posted after",
            "type": "string",
            "description": "Keep only posts published on or after this date. Accepts YYYY-MM-DD or a full ISO timestamp."
          },
          "postedBefore": {
            "title": "Posted before",
            "type": "string",
            "description": "Keep only posts published on or before this date. A bare YYYY-MM-DD includes the whole day."
          },
          "minLikes": {
            "title": "Minimum likes",
            "minimum": 0,
            "type": "integer",
            "description": "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.",
            "default": 0
          },
          "minReplies": {
            "title": "Minimum replies",
            "minimum": 0,
            "type": "integer",
            "description": "Drop posts with fewer replies. 0 = keep everything. Posts with no reply count are kept.",
            "default": 0
          },
          "maxItems": {
            "title": "Max results per target",
            "minimum": 1,
            "type": "integer",
            "description": "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.",
            "default": 100
          },
          "proxy": {
            "title": "Proxy",
            "type": "object",
            "description": "Optional — leave empty and the Actor picks its own route. Datacenter is plenty at normal volume; switch to RESIDENTIAL only if you hit rate limits. On paid Apify plans this Actor already routes through its own residential proxy at no extra cost, so this setting is ignored there."
          },
          "includeKeywords": {
            "title": "✅ Keep only posts containing",
            "type": "array",
            "description": "Only keep jobs whose title, company or description contains at least one of these (case-insensitive). Filtered rows are never charged.",
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "🚫 Drop posts containing",
            "type": "array",
            "description": "Drop jobs whose title, company or description contains any of these (case-insensitive).",
            "items": {
              "type": "string"
            }
          },
          "maxAgeMinutes": {
            "title": "⏱️ Max age (minutes)",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep jobs posted within the last N minutes. Empty or 0 = no age limit. Ideal for tight scheduled runs."
          },
          "incrementalMode": {
            "title": "♻️ Only new posts (monitoring mode)",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "stateKey": {
            "title": "🔑 Monitoring name",
            "type": "string",
            "description": "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": {
            "title": "♻️ Also return posts you already have",
            "type": "boolean",
            "description": "On: unchanged posts are returned again (and billed again). Off is what you want for a monitoring feed.",
            "default": false
          },
          "emitExpired": {
            "title": "⚰️ Report posts that disappeared",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "skipReposts": {
            "title": "🚫 Skip reposted content",
            "type": "boolean",
            "description": "When incremental, skip jobs whose content matches a previously-expired posting (employer re-listed the same ad under a new id).",
            "default": false
          },
          "resetIncrementalState": {
            "title": "🧨 Forget the history and start over",
            "type": "boolean",
            "description": "Wipes this monitoring name's memory, so the next run treats every post as new. Use it after changing what you search for.",
            "default": false
          },
          "compact": {
            "title": "📦 Compact output",
            "type": "boolean",
            "description": "Emit only the core fields — small payloads for AI-agent / MCP / LLM pipelines.",
            "default": false
          },
          "excludeEmptyFields": {
            "title": "🧹 Exclude empty fields",
            "type": "boolean",
            "description": "Drop null / empty-string / empty-array fields from each record.",
            "default": false
          },
          "descriptionMaxLength": {
            "title": "✂️ Truncate post text to",
            "minimum": 0,
            "type": "integer",
            "description": "Truncate description fields to this many characters (0 = full text). Controls LLM prompt cost and dataset size."
          },
          "telegramBotToken": {
            "title": "🔔 Telegram bot token",
            "type": "string",
            "description": "Your bot's token from @BotFather. With Chat ID set, a summary of new jobs is sent after each run."
          },
          "telegramChatId": {
            "title": "🔔 Telegram chat ID",
            "type": "string",
            "description": "Chat or channel id the bot posts to (e.g. \"-1001234567890\")."
          },
          "slackWebhookUrl": {
            "title": "💼 Slack webhook URL",
            "type": "string",
            "description": "Slack incoming-webhook URL (api.slack.com/messaging/webhooks)."
          },
          "discordWebhookUrl": {
            "title": "🎮 Discord webhook URL",
            "type": "string",
            "description": "Discord incoming-webhook URL (Server Settings → Integrations → Webhooks)."
          },
          "whatsappAccessToken": {
            "title": "📱 WhatsApp access token",
            "type": "string",
            "description": "WhatsApp Cloud API token (Meta Business system user). The recipient must have messaged your business number within the last 24h — Cloud API rule."
          },
          "whatsappPhoneNumberId": {
            "title": "📱 WhatsApp phone-number ID",
            "type": "string",
            "description": "Your WhatsApp Business phone-number id (numeric, from the Meta dashboard)."
          },
          "whatsappTo": {
            "title": "📱 WhatsApp recipient",
            "type": "string",
            "description": "Recipient phone in E.164 without + (e.g. \"14165551234\")."
          },
          "webhookUrl": {
            "title": "🪝 Generic webhook URL",
            "type": "string",
            "description": "Receives one JSON POST with { metadata, items } after the run — the universal escape hatch for n8n / Make / Zapier / custom backends."
          },
          "webhookHeaders": {
            "title": "🪝 Webhook headers",
            "type": "object",
            "description": "Optional custom headers for the generic webhook (e.g. {\"Authorization\": \"Bearer …\"})."
          },
          "notificationLimit": {
            "title": "🔔 Max posts per notification",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "How many job lines each chat notification includes (1–20). The rest are summarised as a count.",
            "default": 5
          },
          "notifyOnlyChanges": {
            "title": "🔔 Notify only about new posts",
            "type": "boolean",
            "description": "With Incremental mode on, notify only about NEW / UPDATED / REAPPEARED jobs.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}