{
  "data": {
    "id": "I7cduHm9oKbw9FGRa",
    "actId": "xgRc7Nc7IkbNcF3bC",
    "userId": "NL4ThgItAwaoBlffQ",
    "startedAt": "2026-11-05T04:09:19.615Z",
    "finishedAt": "2026-11-05T04:09:23.739Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 4025,
      "runTimeSecs": 4.025,
      "computeUnits": 0.004472222222222222,
      "imageSizeBytes": 342196736
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "zifX0mkAFMHe8CatY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"X Keyword Search with Mention & Reply Operators\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"mode\": {\n      \"title\": \"What do you want to collect?\",\n      \"type\": \"string\",\n      \"description\": \"Search by keyword, collect an author's posts, fetch specific post URLs, or open a conversation thread.\",\n      \"editor\": \"select\",\n      \"default\": \"search\",\n      \"prefill\": \"search\",\n      \"enum\": [\n        \"search\",\n        \"byAuthor\",\n        \"byUrls\",\n        \"conversation\"\n      ],\n      \"enumTitles\": [\n        \"Search by keyword\",\n        \"Posts by author\",\n        \"Specific post URLs\",\n        \"Conversation thread\"\n      ],\n      \"sectionCaption\": \"Mode and targets\",\n      \"sectionDescription\": \"Choose one mode, then fill the target field that belongs to it.\"\n    },\n    \"keywords\": {\n      \"title\": \"Keywords or phrases\",\n      \"type\": \"array\",\n      \"description\": \"Words, phrases or hashtags to search for. Each keyword is collected separately and every row shows the keyword that found it (searchTerm).\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"prefill\": [\n        \"apify\"\n      ],\n      \"example\": [\n        \"web scraping\",\n        \"#AI\",\n        \"OpenAI\"\n      ]\n    },\n    \"authorHandles\": {\n      \"title\": \"Author handles or profile URLs\",\n      \"type\": \"array\",\n      \"description\": \"Used by the 'Posts by author' mode. Accepts @handle, handle, or https://x.com/handle profile URLs.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"example\": [\n        \"@apify\",\n        \"https://x.com/OpenAI\"\n      ]\n    },\n    \"postUrls\": {\n      \"title\": \"Post URLs or IDs\",\n      \"type\": \"array\",\n      \"description\": \"Used by the 'Specific post URLs' mode. Accepts x.com or twitter.com post links and bare post IDs.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"example\": [\n        \"https://x.com/apify/status/2118015298603274372\"\n      ]\n    },\n    \"conversationId\": {\n      \"title\": \"Conversation ID or post URL\",\n      \"type\": \"string\",\n      \"description\": \"Used by the 'Conversation thread' mode. Paste the root post ID or a post URL in that thread.\",\n      \"editor\": \"textfield\",\n      \"nullable\": true\n    },\n    \"maxItems\": {\n      \"title\": \"Maximum posts\",\n      \"type\": \"integer\",\n      \"description\": \"Stop after this many posts per keyword or author. The URL and conversation modes use it as a total cap.\",\n      \"default\": 20,\n      \"prefill\": 3,\n      \"minimum\": 1,\n      \"maximum\": 1000,\n      \"sectionCaption\": \"Collection\",\n      \"sectionDescription\": \"Coverage and result limits.\"\n    },\n    \"sort\": {\n      \"title\": \"Result order\",\n      \"type\": \"string\",\n      \"description\": \"Latest is newest first. Top is ordered by likes and reposts. Top + Latest returns the top half by engagement, then the newest remaining posts.\",\n      \"editor\": \"select\",\n      \"default\": \"Top\",\n      \"prefill\": \"Latest\",\n      \"enum\": [\n        \"Top\",\n        \"Latest\",\n        \"Top + Latest\"\n      ],\n      \"enumTitles\": [\n        \"Top - most engagement first\",\n        \"Latest - newest first\",\n        \"Top + Latest - both\"\n      ]\n    },\n    \"language\": {\n      \"title\": \"Language\",\n      \"type\": \"string\",\n      \"description\": \"Only keep posts in this language. The default searches every language.\",\n      \"editor\": \"select\",\n      \"default\": \"Any language\",\n      \"prefill\": \"Any language\",\n      \"enum\": [\n        \"Any language\",\n        \"en\",\n        \"es\",\n        \"zh\",\n        \"hi\",\n        \"ar\",\n        \"bn\",\n        \"pt\",\n        \"ru\",\n        \"ja\",\n        \"de\",\n        \"fr\",\n        \"ko\",\n        \"tr\",\n        \"vi\",\n        \"te\",\n        \"mr\",\n        \"ta\",\n        \"ur\",\n        \"it\",\n        \"th\",\n        \"gu\",\n        \"fa\",\n        \"pl\",\n        \"uk\",\n        \"ml\",\n        \"kn\",\n        \"id\",\n        \"ms\",\n        \"sw\",\n        \"ha\",\n        \"am\",\n        \"my\",\n        \"pa\",\n        \"nl\",\n        \"ro\",\n        \"el\",\n        \"he\",\n        \"sv\",\n        \"hu\",\n        \"cs\"\n      ],\n      \"enumTitles\": [\n        \"Any language\",\n        \"English\",\n        \"Spanish\",\n        \"Chinese\",\n        \"Hindi\",\n        \"Arabic\",\n        \"Bengali\",\n        \"Portuguese\",\n        \"Russian\",\n        \"Japanese\",\n        \"German\",\n        \"French\",\n        \"Korean\",\n        \"Turkish\",\n        \"Vietnamese\",\n        \"Telugu\",\n        \"Marathi\",\n        \"Tamil\",\n        \"Urdu\",\n        \"Italian\",\n        \"Thai\",\n        \"Gujarati\",\n        \"Persian\",\n        \"Polish\",\n        \"Ukrainian\",\n        \"Malayalam\",\n        \"Kannada\",\n        \"Indonesian\",\n        \"Malay\",\n        \"Swahili\",\n        \"Hausa\",\n        \"Amharic\",\n        \"Burmese\",\n        \"Punjabi\",\n        \"Dutch\",\n        \"Romanian\",\n        \"Greek\",\n        \"Hebrew\",\n        \"Swedish\",\n        \"Hungarian\",\n        \"Czech\"\n      ]\n    },\n    \"dateFrom\": {\n      \"title\": \"Start date\",\n      \"type\": \"string\",\n      \"description\": \"Only keep posts published on or after this date (UTC).\",\n      \"editor\": \"datepicker\",\n      \"nullable\": true\n    },\n    \"dateTo\": {\n      \"title\": \"End date\",\n      \"type\": \"string\",\n      \"description\": \"Only keep posts published on or before this date (UTC).\",\n      \"editor\": \"datepicker\",\n      \"nullable\": true\n    },\n    \"excludeRetweets\": {\n      \"title\": \"Exclude reposts\",\n      \"type\": \"boolean\",\n      \"description\": \"Drop reposts and keep original posts only.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"excludeReplies\": {\n      \"title\": \"Exclude replies\",\n      \"type\": \"boolean\",\n      \"description\": \"Drop replies and keep top-level posts only.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"onlyVerifiedUsers\": {\n      \"title\": \"Verified accounts only\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep posts from verified or blue-check accounts only.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"onlyImages\": {\n      \"title\": \"Posts with images only\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep posts that contain at least one photo.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"onlyVideos\": {\n      \"title\": \"Posts with videos only\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep posts that contain at least one video or GIF.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"onlyQuotes\": {\n      \"title\": \"Quote posts only\",\n      \"type\": \"boolean\",\n      \"description\": \"Keep posts that quote another post.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"minimumLikes\": {\n      \"title\": \"Minimum likes\",\n      \"type\": \"integer\",\n      \"description\": \"Drop posts below this like count. Posts whose count is unavailable are dropped and reported in the run summary.\",\n      \"minimum\": 0,\n      \"maximum\": 100000000,\n      \"nullable\": true\n    },\n    \"minimumRetweets\": {\n      \"title\": \"Minimum reposts\",\n      \"type\": \"integer\",\n      \"description\": \"Drop posts below this repost count. Counts are filled from the public fallback source when available.\",\n      \"minimum\": 0,\n      \"maximum\": 100000000,\n      \"nullable\": true\n    },\n    \"minimumReplies\": {\n      \"title\": \"Minimum replies\",\n      \"type\": \"integer\",\n      \"description\": \"Drop posts below this reply count. Posts with no available reply count are dropped and reported.\",\n      \"minimum\": 0,\n      \"maximum\": 100000000,\n      \"nullable\": true\n    },\n    \"mentioning\": {\n      \"title\": \"Mentioning handle\",\n      \"type\": \"string\",\n      \"description\": \"Only keep posts that mention this handle (with or without @). Applied after collection.\",\n      \"editor\": \"textfield\",\n      \"nullable\": true,\n      \"sectionCaption\": \"Post filters\",\n      \"sectionDescription\": \"These are applied to collected posts, never sent as opaque search operators.\"\n    },\n    \"author\": {\n      \"title\": \"Posted by handle\",\n      \"type\": \"string\",\n      \"description\": \"Only keep posts written by this handle (with or without @).\",\n      \"editor\": \"textfield\",\n      \"nullable\": true\n    },\n    \"inReplyTo\": {\n      \"title\": \"Replying to handle\",\n      \"type\": \"string\",\n      \"description\": \"Only keep posts that are replies to this handle (with or without @).\",\n      \"editor\": \"textfield\",\n      \"nullable\": true\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy configuration\",\n      \"type\": \"object\",\n      \"description\": \"Optional. No proxy is needed. If supplied, it is used for the best-effort guest search supplement as well as page requests.\",\n      \"editor\": \"proxy\",\n      \"nullable\": true,\n      \"sectionCaption\": \"Advanced\",\n      \"sectionDescription\": \"Optional settings for special network environments.\"\n    }\n  },\n  \"required\": [\n    \"mode\"\n  ]\n}",
    "readme": "# Twitter Keywords Scraper Pro\n\nCollect public X (Twitter) posts without logging in, without cookies and without an API key.\nSearch by keyword, walk an author's recent timeline, fetch exact post URLs, or open a\nconversation thread — then export clean rows with the author, engagement counts, media,\nquoted post and reply context already filled in.\n\n> **Coverage note:** X puts its own full search behind a login. This actor uses the public\n> Bing News x.com index plus public post pages, so it returns a real subset of public X\n> posts, not X's complete search index. That hard limit is explained below.\n\n## What you get\n\nEvery dataset row is one post (`type: \"post\"`) with:\n\n- **Post**: `id`, `url`, `text`, `createdAt`, `language`, `conversationId`\n- **Engagement**: `likeCount`, `replyCount`, `retweetCount`, `quoteCount`, `bookmarkCount`,\n  `viewCount`, `engagementRate`\n- **Flags**: `isReply`, `isRetweet`, `isQuote`, `isNoteTweet`, `possiblySensitive`\n- **Reply context**: `inReplyToTweetId`, `inReplyToUserId`, `inReplyToUsername`, `parentTweet`\n- **Quote context**: `quotedTweetId`, nested `quotedTweet`\n- **Entities**: `hashtags`, `mentions`, `urls`, `cashtags`\n- **Media**: photo, video or GIF with `url`, `previewImageUrl`, `width`, `height`,\n  `variants`, `durationSeconds`, `altText`\n- **Author**: `id`, `username`, `name`, `bio`, `followers`, `following`, `location`,\n  `website`, `profileImageUrl`, `bannerUrl`, `createdAt`, `postCount`, `mediaCount`,\n  `verified`, `isBlueVerified`\n- **Attribution**: `searchTerm` (keyword, handle, URL or conversation ID) and `collectedAt`\n\nEmpty values are omitted at every depth. Missing counters are omitted, never invented as\nzero. An empty run writes a `RUN_SUMMARY` to the key-value store and leaves the dataset\nempty — there are no status or sentinel rows.\n\n## Four modes\n\n| Mode | Input | What it collects |\n|---|---|---|\n| `search` | `keywords` | Public posts found for each keyword through the Bing News x.com index, optionally supplemented by X guest search when you supply a proxy. |\n| `byAuthor` | `authorHandles` | The profile page's metadata and recent posts, plus the public syndication timeline (up to ~21 posts per author). |\n| `byUrls` | `postUrls` | Exact posts from URLs or IDs, using the post page, syndication, FxTwitter and oEmbed fallbacks. |\n| `conversation` | `conversationId` | The focal post plus the reply previews X renders publicly, with the focal post kept first. |\n\n## Quick start\n\n### Keyword search\n\n```json\n{\n  \"mode\": \"search\",\n  \"keywords\": [\"apify\", \"#AI\", \"OpenAI\"],\n  \"maxItems\": 50,\n  \"sort\": \"Latest\",\n  \"language\": \"en\"\n}\n```\n\n### Posts by author\n\n```json\n{\n  \"mode\": \"byAuthor\",\n  \"authorHandles\": [\"@apify\", \"https://x.com/OpenAI\"],\n  \"maxItems\": 20\n}\n```\n\n### Specific post URLs\n\n```json\n{\n  \"mode\": \"byUrls\",\n  \"postUrls\": [\n    \"https://x.com/apify/status/2118015298603274372\",\n    \"2117931222320259247\"\n  ]\n}\n```\n\n### Conversation thread\n\n```json\n{\n  \"mode\": \"conversation\",\n  \"conversationId\": \"https://x.com/apify/status/2118015298603274372\",\n  \"maxItems\": 20\n}\n```\n\n## Inputs\n\n| Input | Type | Default | Notes |\n|---|---|---|---|\n| `mode` | select | `search` | `search`, `byAuthor`, `byUrls` or `conversation`. Required. |\n| `keywords` | string list | – | Used by `search`. A single string is also accepted. |\n| `authorHandles` | string list | – | Used by `byAuthor`. Accepts `@handle`, `handle` or a profile URL. |\n| `postUrls` | string list | – | Used by `byUrls`. Accepts post URLs and bare IDs. |\n| `conversationId` | text | – | Used by `conversation`. Accepts an ID or a post URL. |\n| `maxItems` | integer 1–1000 | `20` | Per keyword/author in search and author modes; total cap in URL and conversation modes. |\n| `sort` | select | `Top` | `Top` (engagement), `Latest` (newest), `Top + Latest` (top half by engagement, then the newest remaining posts). |\n| `language` | select | `Any language` | Any language or an ISO-639-1 code. Applied after collection. |\n| `dateFrom`, `dateTo` | date pickers | – | Inclusive UTC date bounds. |\n| `excludeRetweets`, `excludeReplies` | boolean | `false` | Drop reposts or replies. |\n| `onlyVerifiedUsers` | boolean | `false` | Keep verified or blue-check accounts. |\n| `onlyImages`, `onlyVideos`, `onlyQuotes` | boolean | `false` | Keep photo posts, video/GIF posts, or quote posts. |\n| `minimumLikes`, `minimumRetweets`, `minimumReplies` | integer | – | Drop rows below the threshold; rows whose count is unavailable are dropped and reported. |\n| `mentioning`, `author`, `inReplyTo` | text | – | Client-side operator filters: mention handle, author handle, reply target handle. |\n| `proxyConfiguration` | proxy | – | Optional. Nothing needs a proxy; when supplied it is also used for the best-effort guest search supplement. |\n\nNo cookie, token, API key or proxy field is required. Legacy saved inputs that use\n`maxTweets`, `searchType`, `startDate`, `endDate` or `tweetLanguage` keep working: the actor\nmaps those keys in code even though they no longer appear in the form.\n\n## How collection works\n\n1. **Discovery (`search`)** — queries Bing News RSS for `site:x.com <keyword>` with plain\n   variants (the keyword, quoted phrase, `x.com`, `twitter`, `news`, `today`, `2026`,\n   `update`, `announcement`) and collects unique post IDs. A small job stops after one\n   request; large jobs page through `first=13,26,39,52` with a roughly 460-ID ceiling.\n2. **Hydration** — fetches each ID from the public syndication CDN in parallel. Deleted,\n   protected and tombstoned posts are skipped and counted in the summary. Local probes\n   hydrated 197 of 202 IDs (97.5%) and 193 of 199 (97.0%).\n3. **Profile and post pages** — `byAuthor` reads the logged-out `x.com/<handle>` page (exact\n   profile metadata and recent posts) and falls back to the syndication profile timeline.\n   `byUrls` and `conversation` read the logged-out post page, which embeds the focal post,\n   quoted post and visible reply previews.\n4. **Fallback enrichment** — FxTwitter fills missing view/bookmark/retweet/quote counters\n   and author profile fields. oEmbed is the last resort for a known post ID. A mirror\n   outage never fails a run; missing fields stay omitted.\n5. **Client-side filters** — X-style operators (`mentioning`, `author`, `inReplyTo`) and\n   every date/language/engagement/media/verification/flag filter are applied locally after\n   hydration. The index never receives opaque operator text.\n6. **Deterministic output** — dedupe by post ID, sort, cap, recompute `engagementRate` and\n   emit omit-empty rows.\n\n## Coverage and honest limits\n\n- **Full X search requires a login.** X's search page redirects logged-out visitors to a\n  login wall, and the guest SearchTimeline endpoint answers only a minority of requests\n  and virtually never from datacenter IPs. This actor therefore uses the public index as\n  its primary discovery path. Building full search coverage would require a logged-in\n  account pool or a paid provider, which this actor deliberately does not use.\n- **The index is smaller than X search.** A keyword usually yields tens to a few hundred\n  public posts, weighted toward newsworthy and recently linked posts. Broad one-word\n  keywords can hit the roughly 460-candidate discovery ceiling; narrow keywords may yield only a\n  handful.\n- **`Top` is an engagement sort.** It orders by likes and reposts; it is not X's private\n  ranking model. `Top + Latest` combines an engagement half with the newest remaining posts.\n- **Conversation depth is a preview.** Logged-out X renders the focal post plus a few\n  visible replies, so a thread returns those posts, not every reply.\n- **Not covered:** geo/place filters, People/Lists tabs, follower/following lists,\n  sentiment/AI scoring and full-text search beyond the index. These need endpoints that\n  are not public without a login.\n\n## FAQ\n\n**Do I need cookies, a login or an API key?**\nNo. The actor is cookieless and keyless. A proxy is optional; the default run works without\none and never creates a paid proxy group on its own.\n\n**Why do I get fewer posts than the X search box shows?**\nX's full search is login-gated. The actor reads the public Bing News x.com index and public\npost pages, which cover a real but smaller subset of public posts. That is the documented\nhard limit, not a bug.\n\n**How many posts can one keyword return?**\nThe discovery buffer is capped at roughly 460 unique IDs, but the practical yield is usually tens\nto a few hundred per keyword, depending on how many public posts the index knows. `maxItems`\nstill caps what is emitted.\n\n**How fresh are the results?**\nDiscovery favours recently indexed and newsworthy posts, and each post's exact timestamp\ncomes from X's public payload. Use `dateFrom`/`dateTo` to keep only the window you need.\n\n**Does `Top` match X's Top tab?**\nNo. X does not expose its ranking model publicly, so `Top` sorts the collected posts by\nlikes and reposts. `Latest` sorts by the real post timestamp.\n\n**Why did a run return nothing?**\nThe dataset stays empty and the key-value store `RUN_SUMMARY` says why: no indexed posts,\nall candidates deleted/tombstoned, every post removed by filters, or invalid input. The\nstatus message shows the same reason. There are no placeholder rows.\n\n**Why are view or bookmark counts missing on some rows?**\nSyndication does not expose every counter. The actor asks FxTwitter to fill the gaps, but\nwhen the mirror also lacks a value the field is omitted rather than fabricated.\n\n**Can I get replies and quotes?**\nYes. Reply IDs/handles and the parent post are emitted when X exposes them, and quoted posts\nare nested under `quotedTweet` with `quotedTweetId`. `conversation` mode adds the visible\nreply previews of a thread.\n\n**Is the actor affiliated with X?**\nNo. It reads only public, logged-out pages and public mirrors. It does not bypass a login,\nsell account access, or require your credentials.\n\n## Output summary\n\nThe default dataset view is called **Posts**. For every run, the `RUN_SUMMARY` key in the\ndefault key-value store records `status` (`complete`, `partial` or `empty`), mode, candidate\nand hydrated counts, emitted rows, dropped-filter counts, index coverage and elapsed time.\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "x-keyword-search-with-mention-and-reply-operators",
      "version": "2.0",
      "buildTag": "latest",
      "defaultMemoryMbytes": 1024,
      "minMemoryMbytes": 1024,
      "dockerfile": "./Dockerfile",
      "input": {
        "title": "X Keyword Search with Mention & Reply Operators",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "mode": {
            "title": "What do you want to collect?",
            "type": "string",
            "description": "Search by keyword, collect an author's posts, fetch specific post URLs, or open a conversation thread.",
            "editor": "select",
            "default": "search",
            "prefill": "search",
            "enum": [
              "search",
              "byAuthor",
              "byUrls",
              "conversation"
            ],
            "enumTitles": [
              "Search by keyword",
              "Posts by author",
              "Specific post URLs",
              "Conversation thread"
            ],
            "sectionCaption": "Mode and targets",
            "sectionDescription": "Choose one mode, then fill the target field that belongs to it."
          },
          "keywords": {
            "title": "Keywords or phrases",
            "type": "array",
            "description": "Words, phrases or hashtags to search for. Each keyword is collected separately and every row shows the keyword that found it (searchTerm).",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "prefill": [
              "apify"
            ],
            "example": [
              "web scraping",
              "#AI",
              "OpenAI"
            ]
          },
          "authorHandles": {
            "title": "Author handles or profile URLs",
            "type": "array",
            "description": "Used by the 'Posts by author' mode. Accepts @handle, handle, or https://x.com/handle profile URLs.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "example": [
              "@apify",
              "https://x.com/OpenAI"
            ]
          },
          "postUrls": {
            "title": "Post URLs or IDs",
            "type": "array",
            "description": "Used by the 'Specific post URLs' mode. Accepts x.com or twitter.com post links and bare post IDs.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "example": [
              "https://x.com/apify/status/2118015298603274372"
            ]
          },
          "conversationId": {
            "title": "Conversation ID or post URL",
            "type": "string",
            "description": "Used by the 'Conversation thread' mode. Paste the root post ID or a post URL in that thread.",
            "editor": "textfield",
            "nullable": true
          },
          "maxItems": {
            "title": "Maximum posts",
            "type": "integer",
            "description": "Stop after this many posts per keyword or author. The URL and conversation modes use it as a total cap.",
            "default": 20,
            "prefill": 3,
            "minimum": 1,
            "maximum": 1000,
            "sectionCaption": "Collection",
            "sectionDescription": "Coverage and result limits."
          },
          "sort": {
            "title": "Result order",
            "type": "string",
            "description": "Latest is newest first. Top is ordered by likes and reposts. Top + Latest returns the top half by engagement, then the newest remaining posts.",
            "editor": "select",
            "default": "Top",
            "prefill": "Latest",
            "enum": [
              "Top",
              "Latest",
              "Top + Latest"
            ],
            "enumTitles": [
              "Top - most engagement first",
              "Latest - newest first",
              "Top + Latest - both"
            ]
          },
          "language": {
            "title": "Language",
            "type": "string",
            "description": "Only keep posts in this language. The default searches every language.",
            "editor": "select",
            "default": "Any language",
            "prefill": "Any language",
            "enum": [
              "Any language",
              "en",
              "es",
              "zh",
              "hi",
              "ar",
              "bn",
              "pt",
              "ru",
              "ja",
              "de",
              "fr",
              "ko",
              "tr",
              "vi",
              "te",
              "mr",
              "ta",
              "ur",
              "it",
              "th",
              "gu",
              "fa",
              "pl",
              "uk",
              "ml",
              "kn",
              "id",
              "ms",
              "sw",
              "ha",
              "am",
              "my",
              "pa",
              "nl",
              "ro",
              "el",
              "he",
              "sv",
              "hu",
              "cs"
            ],
            "enumTitles": [
              "Any language",
              "English",
              "Spanish",
              "Chinese",
              "Hindi",
              "Arabic",
              "Bengali",
              "Portuguese",
              "Russian",
              "Japanese",
              "German",
              "French",
              "Korean",
              "Turkish",
              "Vietnamese",
              "Telugu",
              "Marathi",
              "Tamil",
              "Urdu",
              "Italian",
              "Thai",
              "Gujarati",
              "Persian",
              "Polish",
              "Ukrainian",
              "Malayalam",
              "Kannada",
              "Indonesian",
              "Malay",
              "Swahili",
              "Hausa",
              "Amharic",
              "Burmese",
              "Punjabi",
              "Dutch",
              "Romanian",
              "Greek",
              "Hebrew",
              "Swedish",
              "Hungarian",
              "Czech"
            ]
          },
          "dateFrom": {
            "title": "Start date",
            "type": "string",
            "description": "Only keep posts published on or after this date (UTC).",
            "editor": "datepicker",
            "nullable": true
          },
          "dateTo": {
            "title": "End date",
            "type": "string",
            "description": "Only keep posts published on or before this date (UTC).",
            "editor": "datepicker",
            "nullable": true
          },
          "excludeRetweets": {
            "title": "Exclude reposts",
            "type": "boolean",
            "description": "Drop reposts and keep original posts only.",
            "default": false,
            "prefill": false
          },
          "excludeReplies": {
            "title": "Exclude replies",
            "type": "boolean",
            "description": "Drop replies and keep top-level posts only.",
            "default": false,
            "prefill": false
          },
          "onlyVerifiedUsers": {
            "title": "Verified accounts only",
            "type": "boolean",
            "description": "Keep posts from verified or blue-check accounts only.",
            "default": false,
            "prefill": false
          },
          "onlyImages": {
            "title": "Posts with images only",
            "type": "boolean",
            "description": "Keep posts that contain at least one photo.",
            "default": false,
            "prefill": false
          },
          "onlyVideos": {
            "title": "Posts with videos only",
            "type": "boolean",
            "description": "Keep posts that contain at least one video or GIF.",
            "default": false,
            "prefill": false
          },
          "onlyQuotes": {
            "title": "Quote posts only",
            "type": "boolean",
            "description": "Keep posts that quote another post.",
            "default": false,
            "prefill": false
          },
          "minimumLikes": {
            "title": "Minimum likes",
            "type": "integer",
            "description": "Drop posts below this like count. Posts whose count is unavailable are dropped and reported in the run summary.",
            "minimum": 0,
            "maximum": 100000000,
            "nullable": true
          },
          "minimumRetweets": {
            "title": "Minimum reposts",
            "type": "integer",
            "description": "Drop posts below this repost count. Counts are filled from the public fallback source when available.",
            "minimum": 0,
            "maximum": 100000000,
            "nullable": true
          },
          "minimumReplies": {
            "title": "Minimum replies",
            "type": "integer",
            "description": "Drop posts below this reply count. Posts with no available reply count are dropped and reported.",
            "minimum": 0,
            "maximum": 100000000,
            "nullable": true
          },
          "mentioning": {
            "title": "Mentioning handle",
            "type": "string",
            "description": "Only keep posts that mention this handle (with or without @). Applied after collection.",
            "editor": "textfield",
            "nullable": true,
            "sectionCaption": "Post filters",
            "sectionDescription": "These are applied to collected posts, never sent as opaque search operators."
          },
          "author": {
            "title": "Posted by handle",
            "type": "string",
            "description": "Only keep posts written by this handle (with or without @).",
            "editor": "textfield",
            "nullable": true
          },
          "inReplyTo": {
            "title": "Replying to handle",
            "type": "string",
            "description": "Only keep posts that are replies to this handle (with or without @).",
            "editor": "textfield",
            "nullable": true
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Optional. No proxy is needed. If supplied, it is used for the best-effort guest search supplement as well as page requests.",
            "editor": "proxy",
            "nullable": true,
            "sectionCaption": "Advanced",
            "sectionDescription": "Optional settings for special network environments."
          }
        },
        "required": [
          "mode"
        ]
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "X Keyword Search with Mention & Reply Operators Output",
        "description": "X posts with full text, author profile, engagement counters, media, quoted post and reply context. Empty runs write a RUN_SUMMARY to the key-value store instead of a status row.",
        "properties": {
          "tweets": {
            "type": "string",
            "title": "Posts",
            "description": "Dataset containing one row per collected X post, deduplicated by post ID.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "readme": "# Twitter Keywords Scraper Pro\n\nCollect public X (Twitter) posts without logging in, without cookies and without an API key.\nSearch by keyword, walk an author's recent timeline, fetch exact post URLs, or open a\nconversation thread — then export clean rows with the author, engagement counts, media,\nquoted post and reply context already filled in.\n\n> **Coverage note:** X puts its own full search behind a login. This actor uses the public\n> Bing News x.com index plus public post pages, so it returns a real subset of public X\n> posts, not X's complete search index. That hard limit is explained below.\n\n## What you get\n\nEvery dataset row is one post (`type: \"post\"`) with:\n\n- **Post**: `id`, `url`, `text`, `createdAt`, `language`, `conversationId`\n- **Engagement**: `likeCount`, `replyCount`, `retweetCount`, `quoteCount`, `bookmarkCount`,\n  `viewCount`, `engagementRate`\n- **Flags**: `isReply`, `isRetweet`, `isQuote`, `isNoteTweet`, `possiblySensitive`\n- **Reply context**: `inReplyToTweetId`, `inReplyToUserId`, `inReplyToUsername`, `parentTweet`\n- **Quote context**: `quotedTweetId`, nested `quotedTweet`\n- **Entities**: `hashtags`, `mentions`, `urls`, `cashtags`\n- **Media**: photo, video or GIF with `url`, `previewImageUrl`, `width`, `height`,\n  `variants`, `durationSeconds`, `altText`\n- **Author**: `id`, `username`, `name`, `bio`, `followers`, `following`, `location`,\n  `website`, `profileImageUrl`, `bannerUrl`, `createdAt`, `postCount`, `mediaCount`,\n  `verified`, `isBlueVerified`\n- **Attribution**: `searchTerm` (keyword, handle, URL or conversation ID) and `collectedAt`\n\nEmpty values are omitted at every depth. Missing counters are omitted, never invented as\nzero. An empty run writes a `RUN_SUMMARY` to the key-value store and leaves the dataset\nempty — there are no status or sentinel rows.\n\n## Four modes\n\n| Mode | Input | What it collects |\n|---|---|---|\n| `search` | `keywords` | Public posts found for each keyword through the Bing News x.com index, optionally supplemented by X guest search when you supply a proxy. |\n| `byAuthor` | `authorHandles` | The profile page's metadata and recent posts, plus the public syndication timeline (up to ~21 posts per author). |\n| `byUrls` | `postUrls` | Exact posts from URLs or IDs, using the post page, syndication, FxTwitter and oEmbed fallbacks. |\n| `conversation` | `conversationId` | The focal post plus the reply previews X renders publicly, with the focal post kept first. |\n\n## Quick start\n\n### Keyword search\n\n```json\n{\n  \"mode\": \"search\",\n  \"keywords\": [\"apify\", \"#AI\", \"OpenAI\"],\n  \"maxItems\": 50,\n  \"sort\": \"Latest\",\n  \"language\": \"en\"\n}\n```\n\n### Posts by author\n\n```json\n{\n  \"mode\": \"byAuthor\",\n  \"authorHandles\": [\"@apify\", \"https://x.com/OpenAI\"],\n  \"maxItems\": 20\n}\n```\n\n### Specific post URLs\n\n```json\n{\n  \"mode\": \"byUrls\",\n  \"postUrls\": [\n    \"https://x.com/apify/status/2118015298603274372\",\n    \"2117931222320259247\"\n  ]\n}\n```\n\n### Conversation thread\n\n```json\n{\n  \"mode\": \"conversation\",\n  \"conversationId\": \"https://x.com/apify/status/2118015298603274372\",\n  \"maxItems\": 20\n}\n```\n\n## Inputs\n\n| Input | Type | Default | Notes |\n|---|---|---|---|\n| `mode` | select | `search` | `search`, `byAuthor`, `byUrls` or `conversation`. Required. |\n| `keywords` | string list | – | Used by `search`. A single string is also accepted. |\n| `authorHandles` | string list | – | Used by `byAuthor`. Accepts `@handle`, `handle` or a profile URL. |\n| `postUrls` | string list | – | Used by `byUrls`. Accepts post URLs and bare IDs. |\n| `conversationId` | text | – | Used by `conversation`. Accepts an ID or a post URL. |\n| `maxItems` | integer 1–1000 | `20` | Per keyword/author in search and author modes; total cap in URL and conversation modes. |\n| `sort` | select | `Top` | `Top` (engagement), `Latest` (newest), `Top + Latest` (top half by engagement, then the newest remaining posts). |\n| `language` | select | `Any language` | Any language or an ISO-639-1 code. Applied after collection. |\n| `dateFrom`, `dateTo` | date pickers | – | Inclusive UTC date bounds. |\n| `excludeRetweets`, `excludeReplies` | boolean | `false` | Drop reposts or replies. |\n| `onlyVerifiedUsers` | boolean | `false` | Keep verified or blue-check accounts. |\n| `onlyImages`, `onlyVideos`, `onlyQuotes` | boolean | `false` | Keep photo posts, video/GIF posts, or quote posts. |\n| `minimumLikes`, `minimumRetweets`, `minimumReplies` | integer | – | Drop rows below the threshold; rows whose count is unavailable are dropped and reported. |\n| `mentioning`, `author`, `inReplyTo` | text | – | Client-side operator filters: mention handle, author handle, reply target handle. |\n| `proxyConfiguration` | proxy | – | Optional. Nothing needs a proxy; when supplied it is also used for the best-effort guest search supplement. |\n\nNo cookie, token, API key or proxy field is required. Legacy saved inputs that use\n`maxTweets`, `searchType`, `startDate`, `endDate` or `tweetLanguage` keep working: the actor\nmaps those keys in code even though they no longer appear in the form.\n\n## How collection works\n\n1. **Discovery (`search`)** — queries Bing News RSS for `site:x.com <keyword>` with plain\n   variants (the keyword, quoted phrase, `x.com`, `twitter`, `news`, `today`, `2026`,\n   `update`, `announcement`) and collects unique post IDs. A small job stops after one\n   request; large jobs page through `first=13,26,39,52` with a roughly 460-ID ceiling.\n2. **Hydration** — fetches each ID from the public syndication CDN in parallel. Deleted,\n   protected and tombstoned posts are skipped and counted in the summary. Local probes\n   hydrated 197 of 202 IDs (97.5%) and 193 of 199 (97.0%).\n3. **Profile and post pages** — `byAuthor` reads the logged-out `x.com/<handle>` page (exact\n   profile metadata and recent posts) and falls back to the syndication profile timeline.\n   `byUrls` and `conversation` read the logged-out post page, which embeds the focal post,\n   quoted post and visible reply previews.\n4. **Fallback enrichment** — FxTwitter fills missing view/bookmark/retweet/quote counters\n   and author profile fields. oEmbed is the last resort for a known post ID. A mirror\n   outage never fails a run; missing fields stay omitted.\n5. **Client-side filters** — X-style operators (`mentioning`, `author`, `inReplyTo`) and\n   every date/language/engagement/media/verification/flag filter are applied locally after\n   hydration. The index never receives opaque operator text.\n6. **Deterministic output** — dedupe by post ID, sort, cap, recompute `engagementRate` and\n   emit omit-empty rows.\n\n## Coverage and honest limits\n\n- **Full X search requires a login.** X's search page redirects logged-out visitors to a\n  login wall, and the guest SearchTimeline endpoint answers only a minority of requests\n  and virtually never from datacenter IPs. This actor therefore uses the public index as\n  its primary discovery path. Building full search coverage would require a logged-in\n  account pool or a paid provider, which this actor deliberately does not use.\n- **The index is smaller than X search.** A keyword usually yields tens to a few hundred\n  public posts, weighted toward newsworthy and recently linked posts. Broad one-word\n  keywords can hit the roughly 460-candidate discovery ceiling; narrow keywords may yield only a\n  handful.\n- **`Top` is an engagement sort.** It orders by likes and reposts; it is not X's private\n  ranking model. `Top + Latest` combines an engagement half with the newest remaining posts.\n- **Conversation depth is a preview.** Logged-out X renders the focal post plus a few\n  visible replies, so a thread returns those posts, not every reply.\n- **Not covered:** geo/place filters, People/Lists tabs, follower/following lists,\n  sentiment/AI scoring and full-text search beyond the index. These need endpoints that\n  are not public without a login.\n\n## FAQ\n\n**Do I need cookies, a login or an API key?**\nNo. The actor is cookieless and keyless. A proxy is optional; the default run works without\none and never creates a paid proxy group on its own.\n\n**Why do I get fewer posts than the X search box shows?**\nX's full search is login-gated. The actor reads the public Bing News x.com index and public\npost pages, which cover a real but smaller subset of public posts. That is the documented\nhard limit, not a bug.\n\n**How many posts can one keyword return?**\nThe discovery buffer is capped at roughly 460 unique IDs, but the practical yield is usually tens\nto a few hundred per keyword, depending on how many public posts the index knows. `maxItems`\nstill caps what is emitted.\n\n**How fresh are the results?**\nDiscovery favours recently indexed and newsworthy posts, and each post's exact timestamp\ncomes from X's public payload. Use `dateFrom`/`dateTo` to keep only the window you need.\n\n**Does `Top` match X's Top tab?**\nNo. X does not expose its ranking model publicly, so `Top` sorts the collected posts by\nlikes and reposts. `Latest` sorts by the real post timestamp.\n\n**Why did a run return nothing?**\nThe dataset stays empty and the key-value store `RUN_SUMMARY` says why: no indexed posts,\nall candidates deleted/tombstoned, every post removed by filters, or invalid input. The\nstatus message shows the same reason. There are no placeholder rows.\n\n**Why are view or bookmark counts missing on some rows?**\nSyndication does not expose every counter. The actor asks FxTwitter to fill the gaps, but\nwhen the mirror also lacks a value the field is omitted rather than fabricated.\n\n**Can I get replies and quotes?**\nYes. Reply IDs/handles and the parent post are emitted when X exposes them, and quoted posts\nare nested under `quotedTweet` with `quotedTweetId`. `conversation` mode adds the visible\nreply previews of a thread.\n\n**Is the actor affiliated with X?**\nNo. It reads only public, logged-out pages and public mirrors. It does not bypass a login,\nsell account access, or require your credentials.\n\n## Output summary\n\nThe default dataset view is called **Posts**. For every run, the `RUN_SUMMARY` key in the\ndefault key-value store records `status` (`complete`, `partial` or `empty`), mode, candidate\nand hydrated counts, emitted rows, dropped-filter counts, index coverage and elapsed time.\n",
      "title": "X Keyword Search with Mention & Reply Operators",
      "description": "Search X (Twitter) by keyword, author, post URL or conversation without login. Get posts with authors, engagement, media, quotes and replies, plus date, language, engagement and media filters.",
      "seoTitle": "X Keyword Search with Mention & Reply Operators",
      "seoDescription": "Search X (Twitter) by keyword, author, post URL or conversation without login. Get posts with authors, engagement, media, quotes and replies, plus date, language, engagement and media filters.",
      "categories": [
        "SOCIAL_MEDIA"
      ],
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "views": {
            "tweets": {
              "title": "Tweets",
              "transformation": {
                "fields": [
                  "type",
                  "searchTerm",
                  "text",
                  "author.username",
                  "createdAt",
                  "language",
                  "replyCount",
                  "retweetCount",
                  "likeCount",
                  "quoteCount",
                  "bookmarkCount",
                  "viewCount",
                  "engagementRate",
                  "isRetweet",
                  "isQuote",
                  "isReply",
                  "inReplyToUsername",
                  "quotedTweetId",
                  "url",
                  "media",
                  "collectedAt"
                ]
              },
              "display": {
                "component": "table",
                "columns": [
                  {
                    "label": "Type",
                    "format": "text"
                  },
                  {
                    "label": "Keyword",
                    "format": "text"
                  },
                  {
                    "label": "Post",
                    "format": "text"
                  },
                  {
                    "label": "Author",
                    "format": "text"
                  },
                  {
                    "label": "Date",
                    "format": "text"
                  },
                  {
                    "label": "Language",
                    "format": "text"
                  },
                  {
                    "label": "Replies",
                    "format": "number"
                  },
                  {
                    "label": "Reposts",
                    "format": "number"
                  },
                  {
                    "label": "Likes",
                    "format": "number"
                  },
                  {
                    "label": "Quotes",
                    "format": "number"
                  },
                  {
                    "label": "Bookmarks",
                    "format": "number"
                  },
                  {
                    "label": "Views",
                    "format": "number"
                  },
                  {
                    "label": "Engagement rate",
                    "format": "number"
                  },
                  {
                    "label": "Repost?",
                    "format": "text"
                  },
                  {
                    "label": "Quote?",
                    "format": "text"
                  },
                  {
                    "label": "Reply?",
                    "format": "text"
                  },
                  {
                    "label": "Reply to",
                    "format": "text"
                  },
                  {
                    "label": "Quoted post ID",
                    "format": "text"
                  },
                  {
                    "label": "URL",
                    "format": "link"
                  },
                  {
                    "label": "Media",
                    "format": "text"
                  },
                  {
                    "label": "Data collected at",
                    "format": "text"
                  }
                ]
              }
            }
          }
        }
      },
      "environmentVariables": {}
    },
    "buildNumber": "2.0.2",
    "imageDigest": "66328d0bcc93c4feb7bdb4d38a303f23ee3b760c3f6f9ac7f0686302e1b0e95c",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "2.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.004472222222222222
    }
  }
}