X Keyword Search with Mention & Reply Operators
Search X (Twitter) by keyword with filters for date, language, engagement, media, verification, mentioned handle, author, reply target, and conversation thread, plus Top/Latest sort.
Input schema
Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | required | Search by keyword, collect an author's posts, fetch specific post URLs, or open a conversation thread. |
keywords | array | optional | Words, phrases or hashtags to search for. Each keyword is collected separately and every row shows the keyword that found it (searchTerm). |
authorHandles | array | optional | Used by the 'Posts by author' mode. Accepts @handle, handle, or https://x.com/handle profile URLs. |
Show all input fields
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | required | Search by keyword, collect an author's posts, fetch specific post URLs, or open a conversation thread. |
keywords | array | optional | Words, phrases or hashtags to search for. Each keyword is collected separately and every row shows the keyword that found it (searchTerm). |
authorHandles | array | optional | Used by the 'Posts by author' mode. Accepts @handle, handle, or https://x.com/handle profile URLs. |
postUrls | array | optional | Used by the 'Specific post URLs' mode. Accepts x.com or twitter.com post links and bare post IDs. |
conversationId | string | optional | Used by the 'Conversation thread' mode. Paste the root post ID or a post URL in that thread. |
maxItems | integer | optional | Stop after this many posts per keyword or author. The URL and conversation modes use it as a total cap. |
sort | string | optional | Latest is newest first. Top is ordered by likes and reposts. Top + Latest returns the top half by engagement, then the newest remaining posts. |
language | string | optional | Only keep posts in this language. The default searches every language. |
dateFrom | string | optional | Only keep posts published on or after this date (UTC). |
dateTo | string | optional | Only keep posts published on or before this date (UTC). |
excludeRetweets | boolean | optional | Drop reposts and keep original posts only. |
excludeReplies | boolean | optional | Drop replies and keep top-level posts only. |
onlyVerifiedUsers | boolean | optional | Keep posts from verified or blue-check accounts only. |
onlyImages | boolean | optional | Keep posts that contain at least one photo. |
onlyVideos | boolean | optional | Keep posts that contain at least one video or GIF. |
onlyQuotes | boolean | optional | Keep posts that quote another post. |
minimumLikes | integer | optional | Drop posts below this like count. Posts whose count is unavailable are dropped and reported in the run summary. |
minimumRetweets | integer | optional | Drop posts below this repost count. Counts are filled from the public fallback source when available. |
minimumReplies | integer | optional | Drop posts below this reply count. Posts with no available reply count are dropped and reported. |
mentioning | string | optional | Only keep posts that mention this handle (with or without @). Applied after collection. |
author | string | optional | Only keep posts written by this handle (with or without @). |
inReplyTo | string | optional | Only keep posts that are replies to this handle (with or without @). |
proxyConfiguration | object | optional | Optional. No proxy is needed. If supplied, it is used for the best-effort guest search supplement as well as page requests. |
Download the published input schema
View complete JSON
{
"properties": {
"author": {
"description": "Only keep posts written by this handle (with or without @).",
"editor": "textfield",
"nullable": true,
"title": "Posted by handle",
"type": "string"
},
"authorHandles": {
"description": "Used by the 'Posts by author' mode. Accepts @handle, handle, or https://x.com/handle profile URLs.",
"editor": "stringList",
"example": [
"@apify",
"https://x.com/OpenAI"
],
"items": {
"type": "string"
},
"title": "Author handles or profile URLs",
"type": "array"
},
"conversationId": {
"description": "Used by the 'Conversation thread' mode. Paste the root post ID or a post URL in that thread.",
"editor": "textfield",
"nullable": true,
"title": "Conversation ID or post URL",
"type": "string"
},
"dateFrom": {
"description": "Only keep posts published on or after this date (UTC).",
"editor": "datepicker",
"nullable": true,
"title": "Start date",
"type": "string"
},
"dateTo": {
"description": "Only keep posts published on or before this date (UTC).",
"editor": "datepicker",
"nullable": true,
"title": "End date",
"type": "string"
},
"excludeReplies": {
"default": false,
"description": "Drop replies and keep top-level posts only.",
"prefill": false,
"title": "Exclude replies",
"type": "boolean"
},
"excludeRetweets": {
"default": false,
"description": "Drop reposts and keep original posts only.",
"prefill": false,
"title": "Exclude reposts",
"type": "boolean"
},
"inReplyTo": {
"description": "Only keep posts that are replies to this handle (with or without @).",
"editor": "textfield",
"nullable": true,
"title": "Replying to handle",
"type": "string"
},
"keywords": {
"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",
"example": [
"web scraping",
"#AI",
"OpenAI"
],
"items": {
"type": "string"
},
"prefill": [
"apify"
],
"title": "Keywords or phrases",
"type": "array"
},
"language": {
"default": "Any language",
"description": "Only keep posts in this language. The default searches every language.",
"editor": "select",
"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"
],
"prefill": "Any language",
"title": "Language",
"type": "string"
},
"maxItems": {
"default": 20,
"description": "Stop after this many posts per keyword or author. The URL and conversation modes use it as a total cap.",
"maximum": 1000,
"minimum": 1,
"prefill": 3,
"sectionCaption": "Collection",
"sectionDescription": "Coverage and result limits.",
"title": "Maximum posts",
"type": "integer"
},
"mentioning": {
"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.",
"title": "Mentioning handle",
"type": "string"
},
"minimumLikes": {
"description": "Drop posts below this like count. Posts whose count is unavailable are dropped and reported in the run summary.",
"maximum": 100000000,
"minimum": 0,
"nullable": true,
"title": "Minimum likes",
"type": "integer"
},
"minimumReplies": {
"description": "Drop posts below this reply count. Posts with no available reply count are dropped and reported.",
"maximum": 100000000,
"minimum": 0,
"nullable": true,
"title": "Minimum replies",
"type": "integer"
},
"minimumRetweets": {
"description": "Drop posts below this repost count. Counts are filled from the public fallback source when available.",
"maximum": 100000000,
"minimum": 0,
"nullable": true,
"title": "Minimum reposts",
"type": "integer"
},
"mode": {
"default": "search",
"description": "Search by keyword, collect an author's posts, fetch specific post URLs, or open a conversation thread.",
"editor": "select",
"enum": [
"search",
"byAuthor",
"byUrls",
"conversation"
],
"enumTitles": [
"Search by keyword",
"Posts by author",
"Specific post URLs",
"Conversation thread"
],
"prefill": "search",
"sectionCaption": "Mode and targets",
"sectionDescription": "Choose one mode, then fill the target field that belongs to it.",
"title": "What do you want to collect?",
"type": "string"
},
"onlyImages": {
"default": false,
"description": "Keep posts that contain at least one photo.",
"prefill": false,
"title": "Posts with images only",
"type": "boolean"
},
"onlyQuotes": {
"default": false,
"description": "Keep posts that quote another post.",
"prefill": false,
"title": "Quote posts only",
"type": "boolean"
},
"onlyVerifiedUsers": {
"default": false,
"description": "Keep posts from verified or blue-check accounts only.",
"prefill": false,
"title": "Verified accounts only",
"type": "boolean"
},
"onlyVideos": {
"default": false,
"description": "Keep posts that contain at least one video or GIF.",
"prefill": false,
"title": "Posts with videos only",
"type": "boolean"
},
"postUrls": {
"description": "Used by the 'Specific post URLs' mode. Accepts x.com or twitter.com post links and bare post IDs.",
"editor": "stringList",
"example": [
"https://x.com/apify/status/2118015298603274372"
],
"items": {
"type": "string"
},
"title": "Post URLs or IDs",
"type": "array"
},
"proxyConfiguration": {
"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.",
"title": "Proxy configuration",
"type": "object"
},
"sort": {
"default": "Top",
"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",
"enum": [
"Top",
"Latest",
"Top + Latest"
],
"enumTitles": [
"Top - most engagement first",
"Latest - newest first",
"Top + Latest - both"
],
"prefill": "Latest",
"title": "Result order",
"type": "string"
}
},
"required": [
"mode"
],
"schemaVersion": 1,
"title": "X Keyword Search with Mention & Reply Operators",
"type": "object"
}
Output schema
Published result links and storage locations. This schema is not an exhaustive contract for every field in a dataset record.
| Field | Type | Required | Description |
|---|---|---|---|
tweets | string | optional | Dataset containing one row per collected X post, deduplicated by post ID. |
Download the published output schema
View complete JSON
{
"actorOutputSchemaVersion": 1,
"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": {
"description": "Dataset containing one row per collected X post, deduplicated by post ID.",
"template": "{{links.apiDefaultDatasetUrl}}/items",
"title": "Posts",
"type": "string"
}
},
"title": "X Keyword Search with Mention & Reply Operators Output"
}
Dataset schema
Published dataset views and any declared field definitions. A view can select only a subset of the returned record fields.
Download the published dataset schema
View complete JSON
{
"actorSpecification": 1,
"views": {
"tweets": {
"display": {
"columns": [
{
"format": "text",
"label": "Type"
},
{
"format": "text",
"label": "Keyword"
},
{
"format": "text",
"label": "Post"
},
{
"format": "text",
"label": "Author"
},
{
"format": "text",
"label": "Date"
},
{
"format": "text",
"label": "Language"
},
{
"format": "number",
"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": "text",
"label": "Repost?"
},
{
"format": "text",
"label": "Quote?"
},
{
"format": "text",
"label": "Reply?"
},
{
"format": "text",
"label": "Reply to"
},
{
"format": "text",
"label": "Quoted post ID"
},
{
"format": "link",
"label": "URL"
},
{
"format": "text",
"label": "Media"
},
{
"format": "text",
"label": "Data collected at"
}
],
"component": "table"
},
"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"
]
}
}
}
}
Key-value schema
Published key-value store definitions, when provided by this build.
This definition is not present in the default published build. See the published README for available documentation.
Published README
Read the full published documentation
Twitter Keywords Scraper Pro
Collect public X (Twitter) posts without logging in, without cookies and without an API key. Search by keyword, walk an author's recent timeline, fetch exact post URLs, or open a conversation thread — then export clean rows with the author, engagement counts, media, quoted post and reply context already filled in.
Coverage note: X puts its own full search behind a login. This actor uses the public Bing News x.com index plus public post pages, so it returns a real subset of public X posts, not X's complete search index. That hard limit is explained below.
What you get
Every dataset row is one post (type: "post") with:
- Post:
id,url,text,createdAt,language,conversationId - Engagement:
likeCount,replyCount,retweetCount,quoteCount,bookmarkCount,viewCount,engagementRate - Flags:
isReply,isRetweet,isQuote,isNoteTweet,possiblySensitive - Reply context:
inReplyToTweetId,inReplyToUserId,inReplyToUsername,parentTweet - Quote context:
quotedTweetId, nestedquotedTweet - Entities:
hashtags,mentions,urls,cashtags - Media: photo, video or GIF with
url,previewImageUrl,width,height,variants,durationSeconds,altText - Author:
id,username,name,bio,followers,following,location,website,profileImageUrl,bannerUrl,createdAt,postCount,mediaCount,verified,isBlueVerified - Attribution:
searchTerm(keyword, handle, URL or conversation ID) andcollectedAt
Empty values are omitted at every depth. Missing counters are omitted, never invented as
zero. An empty run writes a RUN_SUMMARY to the key-value store and leaves the dataset
empty — there are no status or sentinel rows.
Four modes
| Mode | Input | What it collects |
|---|---|---|
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. |
byAuthor |
authorHandles |
The profile page's metadata and recent posts, plus the public syndication timeline (up to ~21 posts per author). |
byUrls |
postUrls |
Exact posts from URLs or IDs, using the post page, syndication, FxTwitter and oEmbed fallbacks. |
conversation |
conversationId |
The focal post plus the reply previews X renders publicly, with the focal post kept first. |
Quick start
Keyword search
{
"mode": "search",
"keywords": ["apify", "#AI", "OpenAI"],
"maxItems": 50,
"sort": "Latest",
"language": "en"
}
Posts by author
{
"mode": "byAuthor",
"authorHandles": ["@apify", "https://x.com/OpenAI"],
"maxItems": 20
}
Specific post URLs
{
"mode": "byUrls",
"postUrls": [
"https://x.com/apify/status/2118015298603274372",
"2117931222320259247"
]
}
Conversation thread
{
"mode": "conversation",
"conversationId": "https://x.com/apify/status/2118015298603274372",
"maxItems": 20
}
Inputs
| Input | Type | Default | Notes |
|---|---|---|---|
mode |
select | search |
search, byAuthor, byUrls or conversation. Required. |
keywords |
string list | – | Used by search. A single string is also accepted. |
authorHandles |
string list | – | Used by byAuthor. Accepts @handle, handle or a profile URL. |
postUrls |
string list | – | Used by byUrls. Accepts post URLs and bare IDs. |
conversationId |
text | – | Used by conversation. Accepts an ID or a post URL. |
maxItems |
integer 1–1000 | 20 |
Per keyword/author in search and author modes; total cap in URL and conversation modes. |
sort |
select | Top |
Top (engagement), Latest (newest), Top + Latest (top half by engagement, then the newest remaining posts). |
language |
select | Any language |
Any language or an ISO-639-1 code. Applied after collection. |
dateFrom, dateTo |
date pickers | – | Inclusive UTC date bounds. |
excludeRetweets, excludeReplies |
boolean | false |
Drop reposts or replies. |
onlyVerifiedUsers |
boolean | false |
Keep verified or blue-check accounts. |
onlyImages, onlyVideos, onlyQuotes |
boolean | false |
Keep photo posts, video/GIF posts, or quote posts. |
minimumLikes, minimumRetweets, minimumReplies |
integer | – | Drop rows below the threshold; rows whose count is unavailable are dropped and reported. |
mentioning, author, inReplyTo |
text | – | Client-side operator filters: mention handle, author handle, reply target handle. |
proxyConfiguration |
proxy | – | Optional. Nothing needs a proxy; when supplied it is also used for the best-effort guest search supplement. |
No cookie, token, API key or proxy field is required. Legacy saved inputs that use
maxTweets, searchType, startDate, endDate or tweetLanguage keep working: the actor
maps those keys in code even though they no longer appear in the form.
How collection works
- Discovery (
search) — queries Bing News RSS forsite:x.com <keyword>with plain variants (the keyword, quoted phrase,x.com,twitter,news,today,2026,update,announcement) and collects unique post IDs. A small job stops after one request; large jobs page throughfirst=13,26,39,52with a roughly 460-ID ceiling. - Hydration — fetches each ID from the public syndication CDN in parallel. Deleted, protected and tombstoned posts are skipped and counted in the summary. Local probes hydrated 197 of 202 IDs (97.5%) and 193 of 199 (97.0%).
- Profile and post pages —
byAuthorreads the logged-outx.com/<handle>page (exact profile metadata and recent posts) and falls back to the syndication profile timeline.byUrlsandconversationread the logged-out post page, which embeds the focal post, quoted post and visible reply previews. - Fallback enrichment — FxTwitter fills missing view/bookmark/retweet/quote counters and author profile fields. oEmbed is the last resort for a known post ID. A mirror outage never fails a run; missing fields stay omitted.
- Client-side filters — X-style operators (
mentioning,author,inReplyTo) and every date/language/engagement/media/verification/flag filter are applied locally after hydration. The index never receives opaque operator text. - Deterministic output — dedupe by post ID, sort, cap, recompute
engagementRateand emit omit-empty rows.
Coverage and honest limits
- Full X search requires a login. X's search page redirects logged-out visitors to a login wall, and the guest SearchTimeline endpoint answers only a minority of requests and virtually never from datacenter IPs. This actor therefore uses the public index as its primary discovery path. Building full search coverage would require a logged-in account pool or a paid provider, which this actor deliberately does not use.
- The index is smaller than X search. A keyword usually yields tens to a few hundred public posts, weighted toward newsworthy and recently linked posts. Broad one-word keywords can hit the roughly 460-candidate discovery ceiling; narrow keywords may yield only a handful.
Topis an engagement sort. It orders by likes and reposts; it is not X's private ranking model.Top + Latestcombines an engagement half with the newest remaining posts.- Conversation depth is a preview. Logged-out X renders the focal post plus a few visible replies, so a thread returns those posts, not every reply.
- Not covered: geo/place filters, People/Lists tabs, follower/following lists, sentiment/AI scoring and full-text search beyond the index. These need endpoints that are not public without a login.
FAQ
Do I need cookies, a login or an API key? No. The actor is cookieless and keyless. A proxy is optional; the default run works without one and never creates a paid proxy group on its own.
Why do I get fewer posts than the X search box shows? X's full search is login-gated. The actor reads the public Bing News x.com index and public post pages, which cover a real but smaller subset of public posts. That is the documented hard limit, not a bug.
How many posts can one keyword return?
The discovery buffer is capped at roughly 460 unique IDs, but the practical yield is usually tens
to a few hundred per keyword, depending on how many public posts the index knows. maxItems
still caps what is emitted.
How fresh are the results?
Discovery favours recently indexed and newsworthy posts, and each post's exact timestamp
comes from X's public payload. Use dateFrom/dateTo to keep only the window you need.
Does Top match X's Top tab?
No. X does not expose its ranking model publicly, so Top sorts the collected posts by
likes and reposts. Latest sorts by the real post timestamp.
Why did a run return nothing?
The dataset stays empty and the key-value store RUN_SUMMARY says why: no indexed posts,
all candidates deleted/tombstoned, every post removed by filters, or invalid input. The
status message shows the same reason. There are no placeholder rows.
Why are view or bookmark counts missing on some rows? Syndication does not expose every counter. The actor asks FxTwitter to fill the gaps, but when the mirror also lacks a value the field is omitted rather than fabricated.
Can I get replies and quotes?
Yes. Reply IDs/handles and the parent post are emitted when X exposes them, and quoted posts
are nested under quotedTweet with quotedTweetId. conversation mode adds the visible
reply previews of a thread.
Is the actor affiliated with X? No. It reads only public, logged-out pages and public mirrors. It does not bypass a login, sell account access, or require your credentials.
Output summary
The default dataset view is called Posts. For every run, the RUN_SUMMARY key in the
default key-value store records status (complete, partial or empty), mode, candidate
and hydrated counts, emitted rows, dropped-filter counts, index coverage and elapsed time.
Python quickstart
Use a schema-derived input and the Python standard library to start a run. An Apify account and token are required for execution.
Source build I7cduHm9oKbw9FGRa. Documentation is regenerated from the default published build; private drafts are not included.