{
  "openapi": "3.0.1",
  "info": {
    "title": "Twitter X Tweets Scraper Scraper By Keyword & Hashtag",
    "description": "Scrape X Twitter tweets reliably for structured data. Capture tweet content, engagement metrics, author profiles, and posting times. Filter by search terms, usernames, or date ranges. Useful for market research, social listening, and audience analysis.",
    "version": "0.1",
    "x-build-id": "PX9iQBZvzDCERO8TR"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/simpleapi~Twitter-X-Tweets-Scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-simpleapi-Twitter-X-Tweets-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/simpleapi~Twitter-X-Tweets-Scraper/runs": {
      "post": {
        "operationId": "runs-sync-simpleapi-Twitter-X-Tweets-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/simpleapi~Twitter-X-Tweets-Scraper/run-sync": {
      "post": {
        "operationId": "run-sync-simpleapi-Twitter-X-Tweets-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": {
          "searchTerms": {
            "title": "🔎 Keywords and hashtags to search",
            "type": "array",
            "description": "One search per line. Plain words (`product recall`), a hashtag (`#Artemis`), or a quoted phrase (`\"battery fire\"`) for an exact match. X's own operators (`OR`, `-exclusion`, `from:`) work here too and are passed through as typed.\n\nEach line is searched separately and returned as ordinary post rows, tagged with `matched_search_term`. Leave this empty and the actor behaves exactly like the base actor, scraping only the profiles below.\n\nYou can also leave this empty and set only a filter in step 3 — the run then searches on the compiled operators alone (for example “every post quoting this post”, or “every reply in this thread”).\n\n⚠️ Needs the X session cookies (last section). Deliberately EMPTY by default so that pressing Start with the stock settings runs the keyless profile scrape and finishes green - fill this box only together with the cookies.",
            "items": {
              "type": "string"
            }
          },
          "searchProduct": {
            "title": "🗂️ Which search tab",
            "enum": [
              "Latest",
              "Top",
              "Media",
              "People"
            ],
            "type": "string",
            "description": "X serves four different result sets for the same query, and they are NOT comparable with each other:\n\n• Latest — reverse-chronological, what you want while something is unfolding.\n• Top — X's own relevance ranking, surfaces the posts that actually travelled.\n• Media — only posts carrying a photo or video. X over-delivers here (48 posts came back for a 20-request), so the post limit below is what caps it.\n• People — ACCOUNTS instead of posts. Returns `type: \"user\"` rows (handle, name, bio, followers, location, account age) in the “People results” view, and no post rows at all.\n\nDefault: Latest.",
            "default": "Latest"
          },
          "includeSearchTerms": {
            "title": "🏷️ Record which term matched each row",
            "type": "boolean",
            "description": "On: every search row carries `matched_search_term`, the term that found it. A run over eight keywords produces one merged table, and without this column there is no way to tell which keyword found what. Costs nothing.\n\nOff: `matched_search_term` is left empty. `resolved_query` (the compiled query) is written either way — it is what makes the run auditable.",
            "default": true
          },
          "startUrls": {
            "title": "🔗 Profiles or post URLs (optional here)",
            "type": "array",
            "description": "Optional in this actor — you can run on keywords alone. One target per line. Accepted forms:\n\n• https://x.com/NASA  or  https://twitter.com/NASA\n• NASA  or  @NASA\n• a numeric user ID, e.g. 11348282\n• a single post: https://x.com/NASA/status/2083317461269598348\n\nThese run KEYLESS — no session needed. A post URL returns exactly one row for that post and ignores the post limit. Every target that returns nothing gets its own uncharged row explaining why.",
            "items": {
              "type": "string"
            }
          },
          "fromHandle": {
            "title": "✍️ Only posts written by this account",
            "type": "string",
            "description": "Compiles to `from:<handle>`. Example: `NASA` → only NASA's posts match the keyword. Applied by X server-side, so it narrows what X sends instead of being thrown away after you paid for it.\n\nNote: a repost row reports the ORIGINAL author (that is the base contract), so a repost by this account shows the original poster in `user_posted` and this account in `reposted_by`."
          },
          "toHandle": {
            "title": "↩️ Only replies addressed to this account",
            "type": "string",
            "description": "Compiles to `to:<handle>`. Example: `NASA` → only posts replying to @NASA. Measured 20/20: every returned row carried `in_reply_to_user` = NASA."
          },
          "conversationId": {
            "title": "🧵 Only posts in one thread",
            "type": "string",
            "description": "Compiles to `conversation_id:<id>`. Paste the numeric ID of the post that started the thread (it is the `conversation_id` column on any row, or the number at the end of the post URL). Returns the replies in that conversation. Measured 20/20 rows carrying the same thread ID."
          },
          "quotedPostId": {
            "title": "💬 Only posts quoting one specific post",
            "type": "string",
            "description": "Compiles to `quoted_tweet_id:<id>`. Paste a numeric post ID and you get the posts that quote-tweeted it. Exact — a known quote was returned 1-of-1 on the deterministic test target."
          },
          "postedAfter": {
            "title": "📅 Posted on or after",
            "type": "string",
            "description": "Compiles to `since_time:<utc epoch seconds>`, which X applies exactly to the second, and is re-checked locally in UTC as a net.\n\nThe day form `since:YYYY-MM-DD` is NOT exact - X applies it on the session's own local day boundary (measured ~UTC+6), which leaked rows 5.5 hours outside the requested window - so this actor does not use it. Anything the local re-check removes is counted in `results_dropped_by_filter`.\n\nAbsolute (`2026-07-01`, or a full timestamp) or relative (`7 days`)."
          },
          "postedBefore": {
            "title": "📅 Posted before",
            "type": "string",
            "description": "Compiles to `until_time:<utc epoch seconds>`, exact to the second, and re-checked locally in UTC. Exclusive: a post timestamped exactly at this instant is NOT returned.\n\nThe day form `until:YYYY-MM-DD` is inclusive of the named day in X's own timezone, which is why it is not used here.\n\nAbsolute (`2026-07-05`, or a full timestamp) or relative (`1 day`)."
          },
          "minLikes": {
            "title": "❤️ Minimum likes",
            "minimum": 0,
            "type": "integer",
            "description": "Compiles to `min_faves:<n>`. X applies it server-side, so you do not pay for rows that are then thrown away. Every returned row is re-checked against the number X published for it.\n\n0 keeps everything (default). A floor also removes brand-new posts that have not had time to gather likes — on a breaking topic those are the ones you are watching for.",
            "default": 0
          },
          "minRetweets": {
            "title": "🔁 Minimum reposts",
            "minimum": 0,
            "type": "integer",
            "description": "Compiles to `min_retweets:<n>`, applied by X server-side and re-checked locally. 0 keeps everything (default).",
            "default": 0
          },
          "minReplies": {
            "title": "💬 Minimum replies",
            "minimum": 0,
            "type": "integer",
            "description": "Compiles to `min_replies:<n>`, applied by X server-side and re-checked locally. 0 keeps everything (default).",
            "default": 0
          },
          "searchLanguage": {
            "title": "🌍 Post language",
            "enum": [
              "any",
              "en",
              "es",
              "pt",
              "fr",
              "de",
              "it",
              "nl",
              "pl",
              "sv",
              "tr",
              "ru",
              "uk",
              "ar",
              "fa",
              "hi",
              "id",
              "th",
              "vi",
              "ja",
              "ko",
              "zh"
            ],
            "type": "string",
            "description": "Compiles to `lang:<code>` — X's own per-post language detection, applied server-side. Measured 20/20 on `lang:ja`. “Any language” (default) sends no language operator at all.",
            "default": "any"
          },
          "mediaFilter": {
            "title": "🖼️ Media",
            "enum": [
              "any",
              "with_media",
              "without_media"
            ],
            "type": "string",
            "description": "Compiles to `filter:media` or `-filter:media` and is re-checked against the row's own photo/video lists. One control rather than two toggles, because “only with media” and “exclude media” cannot both be true.\n\nMeasured 20/20 in both directions. This is separate from the Media search tab: the tab changes which result set X ranks, this filter changes the query.",
            "default": "any"
          },
          "onlyWithLinks": {
            "title": "🔗 Only posts containing a link",
            "type": "boolean",
            "description": "Compiles to `filter:links`. Applied by X server-side ONLY — the row does not expose X's raw link entities, so there is no local re-check for this one and it is not counted in `results_dropped_by_filter`. Measured 20/20 server-side.",
            "default": false
          },
          "maxTweets": {
            "title": "🔢 Rows per profile and per search term",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "How many rows to collect from EACH profile and from EACH search term (1–1000). Every row counts — the pinned post, and the extra posts X over-delivers on the Media tab — and duplicates are removed before anything is charged, so you never get more rows than you asked for.\n\nSingle post URLs are not affected by this setting. Default: 10.",
            "default": 10
          },
          "sortOrder": {
            "title": "↕️ Row order",
            "enum": [
              "recent",
              "oldest",
              "popular"
            ],
            "type": "string",
            "description": "Re-orders the rows collected in this run. It does not search further back than what was already fetched, and it does not change what X ranked — `result_rank` records the position X returned each search row at, before any sorting or filtering.",
            "default": "recent"
          },
          "includeReplies": {
            "title": "💬 Include a profile's own replies",
            "type": "boolean",
            "description": "Applies to the profiles in step 2, not to search.\n\nOff: the profile's posts, reposts and quotes (the “Posts” tab) — no login needed.\n\nOn: also the replies that profile wrote to other people (the “Posts and replies” tab). That surface is available only to a logged-in caller, so it REQUIRES the X session below. Without it the run fails immediately with an explanation rather than quietly returning a partial timeline.",
            "default": false
          },
          "auth_token": {
            "title": "🔑 X session — auth_token cookie",
            "type": "string",
            "description": "REQUIRED for keyword/hashtag search, and for “Include a profile's own replies”. Copy the value of the `auth_token` cookie from an x.com browser session (DevTools → Application → Cookies → x.com).\n\nStored encrypted, sent only to api.x.com, and never written to the dataset or the run log. Profiles and post URLs work with no session at all."
          },
          "ct0": {
            "title": "🔑 X session — ct0 cookie",
            "type": "string",
            "description": "Required together with `auth_token`. Copy the value of the `ct0` cookie from the same x.com browser session; it is the CSRF token X checks on every authenticated request.\n\nStored encrypted, sent only to api.x.com, and never written to the dataset or the run log."
          },
          "proxyConfiguration": {
            "title": "🌐 Proxy",
            "type": "object",
            "description": "Off by default. X was measured serving this data to a bare Apify datacenter exit, so a proxy is optional. Turn Apify Proxy on if you want a different exit or run at high volume; the actor rotates to a fresh exit once if a profile request fails before any row was saved.",
            "default": {
              "useApifyProxy": 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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}