Twitter/X Scraper - Tweets, Profiles & Trends
Pricing
from $10.00 / 1,000 tweet scrapeds
Twitter/X Scraper - Tweets, Profiles & Trends
Scrape Twitter/X: tweets, user profiles, followers, hashtags, and trending topics.
Pricing
from $10.00 / 1,000 tweet scrapeds
Rating
5.0
(4)
Developer
viralanalyzer
Maintained by CommunityActor stats
0
Bookmarked
116
Total users
5
Monthly active users
6 days ago
Last modified
Categories
Share
Twitter/X Scraper 🐦
🔗 View on Apify Store | 🇺🇸 English | 🇧🇷 Português
Scrape tweets, profiles, and engagement metrics from Twitter/X. Bring your own X API v2 Bearer Token for reliable access (recommended — X blocks anonymous timeline access), or use the anonymous fallback with configurable proxies.
🇺🇸 English
What does it do?
This actor extracts public tweets and engagement metrics from any Twitter/X profile or search query. Get real data for social media analysis, brand monitoring, and competitive intelligence.
Features
- Profile scraping — Get latest tweets from any public profile
- Search scraping — Find tweets matching any keyword or hashtag
- Full metrics — Views, likes, retweets, replies, quotes, bookmarks
- Media extraction — Each attachment as
{ type, url }, from the anonymous strategies - Thread detection — Identifies if a tweet is part of a thread
- Author info — Username, display name, follower count, verification status
- Date filtering —
dateFrom/dateTorestrict results to a date range (UTC, both bounds inclusive), applied to each tweet'screated_atbefore billing - Reply/Retweet filters — Include or exclude replies and retweets
Capabilities & Limits
Built here: the anonymous GraphQL path bootstraps itself at runtime. It loads x.com, pulls up to 5 client-web JS bundles from abs.twimg.com and regex-extracts the current queryId for UserByScreenName and UserTweets before calling /i/api/graphql/. Nothing is hardcoded, so the actor survives X rotating its query IDs - and aborts that strategy rather than returning stale data if the bundles change shape.
What this actor can and cannot accept as a seed, based on the real input schema:
| Discover by | Supported | Notes |
|---|---|---|
| Handle / username | ✅ Yes | profiles array (without @) |
| Hashtag | ⚠️ Partial | No dedicated field — pass it inside searchQuery (e.g. #tech); search mode needs the X API Bearer Token |
| Keyword / search | ⚠️ Partial | searchQuery works only with an X API v2 Bearer Token (X removed anonymous search); recent tweets only |
| URL | ❌ No | No tweet/profile URL input field in the schema |
| Subreddit | ❌ N/A | Not a Reddit actor |
Output includes: tweet text ✅, views ✅, likes ✅, retweets ✅, replies count ✅, quotes ✅, bookmarks ✅, hashtags ✅, media ✅, author (username, displayName, followers, verified) ✅, created_at (ISO 8601) ✅, language ✅, is_thread / is_reply / is_retweet ✅.
| Not in the output | Why | |
|---|---|---|
| Reply / comment text | ❌ | only the reply count is returned, never the text of individual replies |
thumbnail on media items | ❌ | a media entry is { type, url } — X's own media URL. No separate thumbnail or :small variant is emitted |
| Media on the Bearer Token path | ❌ | the official X API v2 strategy returns media: []. Attachments come only from the anonymous strategies (syndication / GraphQL) |
Input
| Field | Type | Default | Description |
|---|---|---|---|
profiles | string[] | ["elikifreitasdev"] | Twitter/X usernames (without @) |
searchQuery | string | — | Search term (alternative to profiles) |
maxTweets | integer | 20 | Max tweets per profile/search (1-100) |
includeReplies | boolean | false | Include reply tweets |
includeRetweets | boolean | false | Include retweets |
dateFrom | string | — | Inclusive lower bound on created_at. YYYY-MM-DD (= 00:00:00.000Z UTC) or full ISO-8601 |
dateTo | string | — | Inclusive upper bound on created_at. YYYY-MM-DD (= 23:59:59.999Z UTC, whole day included) or full ISO-8601 |
Date range (dateFrom / dateTo) - exact behavior
Both fields are optional and independent; leaving one empty leaves that side unbounded, and leaving both empty disables the filter entirely.
- Where it runs. The bounds are not sent to any remote API or URL parameter. The actor fetches the most recent tweets each strategy exposes and then compares each tweet's
created_atlocally. A narrow or old range can therefore return fewer items thanmaxTweets, or nothing at all, even for an active profile. - Inclusive, UTC. A tweet is kept when
dateFrom <= created_at <= dateTo.YYYY-MM-DDindateFrommeans00:00:00.000Zof that day; indateToit means23:59:59.999Z, sodateFrom = dateTo = 2026-01-20returns that whole day. A full ISO-8601 timestamp is used exactly as given. - Billing. The filter runs before the tweet is stored and before the Pay Per Event counter is incremented. You are never charged for a tweet the date filter discards.
- Tweets with no date. A few anonymous fallback paths return a tweet whose
created_atisnull. While any bound is set, such a tweet is dropped - its membership in the range cannot be verified, so it is neither returned nor charged. The run log reports how many were dropped for this reason. - Invalid input. An unreadable
dateFrom/dateTo, or a range wheredateFromis afterdateTo, stops the run with a labeled_dataQuality: "diagnostic"item explaining the problem, and charges nothing. The filter is never silently ignored. - Nothing in range. If tweets were found but all fell outside the range, the run succeeds with a diagnostic item stating how many were discarded - again with no charge.
Output Example
{"tweet_id": "1891234567890123456","url": "https://x.com/elikifreitasdev/status/1891234567890123456","text": "🚀 Launched the new version! Performance 3x better #tech #automation","author": {"username": "elikifreitasdev","displayName": "Eliki Freitas | Dev","followers": 12500,"verified": false},"created_at": "2026-01-20T14:30:00.000Z","views": 45200,"likes": 892,"retweets": 156,"replies": 43,"quotes": 12,"bookmarks": 234,"hashtags": ["tech", "automation"],"media": [{"type": "image","url": "https://pbs.twimg.com/media/example.jpg"}],"is_thread": false,"is_reply": false,"is_retweet": false,"language": "en"}
Use Cases
- Brand Monitoring — Track mentions and sentiment about your brand
- Competitor Analysis — Monitor competitor tweet performance
- Influencer Research — Evaluate engagement rates before partnerships
- Trend Detection — Discover viral topics and hashtags
- Content Strategy — Analyze what tweet formats get the most engagement
FAQ
Does it require a Twitter API key?
Recommended. X blocks anonymous (guest) access to timelines, so for reliable results provide your own twitterBearerToken (X API v2 — your own plan/quota at https://developer.x.com). Search/keyword mode (searchQuery) requires the Bearer Token (X removed anonymous search). Without a token, the actor tries anonymous strategies (subject to blocking) and, if nothing is extracted, returns a diagnostic guide without charging PPE.
Why did dateFrom / dateTo return fewer tweets than maxTweets?
Because the range is applied locally, to the tweets the actor was able to fetch (the most recent ones a strategy exposes), not as a remote query parameter. Tweets outside the range — and, while a bound is set, tweets with no readable created_at — are dropped before being stored, and are not charged. See "Date range — exact behavior" above.
Can it scrape protected/private accounts? No. Only public profiles and public tweets are accessible.
What about rate limits? The actor handles rate limiting automatically with built-in delays and retries.
How many tweets can I get per run? Up to 100 tweets per profile or search query per run.
🇧🇷 Português
O que faz?
Este actor extrai tweets públicos e métricas de engajamento de qualquer perfil ou busca no Twitter/X. Dados reais para análise de redes sociais, monitoramento de marca e inteligência competitiva.
Funcionalidades
- Scraping de perfil — Últimos tweets de qualquer perfil público
- Scraping de busca — Encontre tweets por palavra-chave ou hashtag
- Métricas completas — Visualizações, curtidas, retweets, respostas, citações, bookmarks
- Extração de mídia — Cada anexo como
{ type, url }, vindo das estratégias anônimas - Detecção de thread — Identifica se o tweet faz parte de uma thread
- Info do autor — Username, nome, seguidores, verificação
- Filtro por data —
dateFrom/dateTorestringem os resultados a um período (UTC, ambos os limites inclusivos), aplicados aocreated_atde cada tweet antes da cobrança - Filtros de resposta/retweet — Inclua ou exclua respostas e retweets
Capacidades e Limites
O que este actor aceita ou não como semente, conforme o input schema real:
| Descobre por | Suportado | Observações |
|---|---|---|
| Handle / username | ✅ Sim | Array profiles (sem @) |
| Hashtag | ⚠️ Parcial | Sem campo dedicado — passe dentro de searchQuery (ex.: #tech); o modo de busca exige o Bearer Token da API do X |
| Palavra-chave / busca | ⚠️ Parcial | searchQuery funciona apenas com Bearer Token da API X v2 (o X removeu a busca anônima); somente tweets recentes |
| URL | ❌ Não | Não há campo de URL de tweet/perfil no schema |
| Subreddit | ❌ N/A | Não é um actor de Reddit |
A saída inclui: texto do tweet ✅, visualizações ✅, curtidas ✅, retweets ✅, contagem de respostas ✅, citações ✅, bookmarks ✅, hashtags ✅, mídia ✅, autor (username, displayName, seguidores, verificado) ✅, created_at (ISO 8601) ✅, idioma ✅, is_thread / is_reply / is_retweet ✅.
| Não sai na saída | Motivo | |
|---|---|---|
| TEXTO das respostas/comentários | ❌ | só a contagem de respostas é retornada, nunca o texto de cada resposta |
thumbnail nos itens de mídia | ❌ | cada anexo é { type, url } — a própria URL de mídia do X. Não há thumbnail separado nem variante :small |
| Mídia no caminho com Bearer Token | ❌ | a estratégia oficial da API X v2 devolve media: []. Os anexos vêm apenas das estratégias anônimas (syndication / GraphQL) |
Entrada
| Campo | Tipo | Padrão | Descrição |
|---|---|---|---|
profiles | string[] | ["elikifreitasdev"] | Usernames do Twitter/X (sem @) |
searchQuery | string | — | Termo de busca (alternativa aos perfis) |
maxTweets | integer | 20 | Máx tweets por perfil/busca (1-100) |
includeReplies | boolean | false | Incluir tweets de resposta |
includeRetweets | boolean | false | Incluir retweets |
dateFrom | string | — | Limite inferior inclusivo sobre created_at. YYYY-MM-DD (= 00:00:00.000Z UTC) ou ISO-8601 completo |
dateTo | string | — | Limite superior inclusivo sobre created_at. YYYY-MM-DD (= 23:59:59.999Z UTC, dia inteiro incluído) ou ISO-8601 completo |
Intervalo de datas (dateFrom / dateTo) - comportamento exato
Os dois campos são opcionais e independentes: deixar um vazio deixa aquele lado sem limite, e deixar os dois vazios desliga o filtro.
- Onde roda. Os limites não são enviados a nenhuma API ou parâmetro de URL. O actor busca os tweets mais recentes que cada estratégia expõe e compara o
created_atde cada um localmente. Por isso um intervalo estreito ou antigo pode devolver menos itens quemaxTweets, ou nenhum, mesmo em um perfil ativo. - Inclusivo, em UTC. O tweet é mantido quando
dateFrom <= created_at <= dateTo.YYYY-MM-DDemdateFromsignifica00:00:00.000Zdaquele dia; emdateTosignifica23:59:59.999Z, entãodateFrom = dateTo = 2026-01-20devolve o dia inteiro. Um timestamp ISO-8601 completo é usado exatamente como informado. - Cobrança. O filtro roda antes de o tweet ser gravado e antes de o contador do Pay Per Event ser incrementado. Você nunca é cobrado por um tweet descartado pelo filtro de data.
- Tweets sem data. Alguns caminhos anônimos de fallback devolvem tweet com
created_atigual anull. Com qualquer limite ativo, esse tweet é descartado - não dá para verificar se ele pertence ao intervalo, então ele não é devolvido nem cobrado. O log do run informa quantos caíram por esse motivo. - Entrada inválida.
dateFrom/dateToilegível, ou intervalo em quedateFromé posterior adateTo, interrompe o run com um item_dataQuality: "diagnostic"explicando o problema, sem cobrar nada. O filtro nunca é ignorado em silêncio. - Nada no intervalo. Se tweets foram encontrados mas todos ficaram fora do intervalo, o run termina com sucesso e um item de diagnóstico dizendo quantos foram descartados - também sem cobrança.
Exemplo de Saída
{"tweet_id": "1891234567890123456","url": "https://x.com/elikifreitasdev/status/1891234567890123456","text": "🚀 Lançamos a nova versão! Performance 3x melhor #tech #automation","author": {"username": "elikifreitasdev","displayName": "Eliki Freitas | Dev","followers": 12500,"verified": false},"created_at": "2026-01-20T14:30:00.000Z","views": 45200,"likes": 892,"retweets": 156,"replies": 43,"quotes": 12,"bookmarks": 234,"hashtags": ["tech", "automation"],"media": [{"type": "image","url": "https://pbs.twimg.com/media/example.jpg"}],"is_thread": false,"is_reply": false,"is_retweet": false,"language": "pt"}
Casos de Uso
- Monitoramento de Marca — Acompanhe menções e sentimento sobre sua marca
- Análise de Concorrência — Monitore performance de tweets de concorrentes
- Pesquisa de Influenciadores — Avalie taxas de engajamento antes de parcerias
- Detecção de Tendências — Descubra tópicos virais e hashtags
- Estratégia de Conteúdo — Analise quais formatos de tweet geram mais engajamento
FAQ
Precisa de chave de API do Twitter?
Recomendado. O X bloqueia acesso anônimo a timelines; informe seu twitterBearerToken (X API v2, plano/quota próprios — https://developer.x.com) para extração confiável. Sem token, o actor tenta estratégias anônimas (sujeitas a bloqueio) e, se nada for extraído, devolve um guia de diagnóstico sem cobrar PPE.
Por que dateFrom / dateTo devolveram menos tweets que maxTweets?
Porque o intervalo é aplicado localmente, sobre os tweets que o actor conseguiu buscar (os mais recentes que a estratégia expõe), e não como parâmetro remoto de consulta. Tweets fora do intervalo — e, com um limite ativo, tweets sem created_at legível — são descartados antes de serem gravados, e não são cobrados. Veja "Intervalo de datas — comportamento exato" acima.
Pode scraper contas protegidas/privadas? Não. Apenas perfis públicos e tweets públicos são acessíveis.
E sobre limites de requisição? O actor gerencia rate limiting automaticamente com delays e retentativas.
Quantos tweets posso obter por execução? Até 100 tweets por perfil ou busca por execução.
💰 Pricing
This actor uses Pay Per Event (PPE) pricing. The rate depends on your Apify plan tier:
| Plan tier | Per tweet | Per 1,000 tweets |
|---|---|---|
| Free | $0.02 | $20.00 |
| Bronze | $0.0175 | $17.50 |
| Silver | $0.015 | $15.00 |
| Gold | $0.01 | $10.00 |
| Platinum | $0.0075 | $7.50 |
| Diamond | $0.005 | $5.00 |
You are never charged for a run that returned nothing. When X blocks the request and no
tweet is extracted, the actor returns a labeled _dataQuality: "diagnostic" setup guide and
charges no PPE event. The same holds for the dateFrom / dateTo filter: tweets discarded
because they fall outside the requested range — or because they carry no readable date while a
bound is set — are dropped before the Pay Per Event counter, so they are never billed.
🔗 Related Actors
✅ Available / Disponível — cross-actor upgrades
The items below were PLANNED in earlier versions and are now implemented and live in this actor. They are additive and backward-compatible: when the new input fields are omitted and
normalizeOutputisfalse, the output is byte-for-byte identical to before — paying users are unaffected.Os itens abaixo eram PLANEJADOS em versões anteriores e agora estão implementados e disponíveis neste actor. São aditivos e retrocompatíveis: quando os novos campos de input são omitidos e
normalizeOutputéfalse, a saída é byte-a-byte idêntica à anterior — usuários pagantes não são afetados.
EN
- Unified input vocabulary (#1) ✅ —
maxResults(alias ofmaxTweets),seeds+seedType(handle|url|keyword) are accepted as a cross-actor unified seed list. The existingprofiles/searchQuery/maxTweetsfields keep working exactly as before; the new ones are optional aliases. - Normalized
_normalizedoutput block (#2) ✅ — set the optional inputnormalizeOutput: trueto attach a cross-platform block to each item:{ platform, url, author, text, views, likes, comments, shares, publishedAtISO, lang, hashtags[], engagementVelocity }, alongside the existing raw fields. For Twitter/X,commentsmaps fromreplies,sharesfromretweets + quotes,viewsfrom impressions. Defaultfalse. - ISO date +
engagementVelocity(#6) ✅ — inside_normalized,publishedAtISOis the tweet date in ISO-8601 UTC, andengagementVelocity=(likes + comments + shares) / hours_since_published(ornullwhen no date is available). - Quality flag
_dataQuality(#7) ✅ — successful items carry_dataQuality: "full"(whennormalizeOutputis on); the recoverable no-results setup guide carries_dataQuality: "diagnostic"and is not charged via PPE.
PT
- Vocabulário de input unificado (#1) ✅ —
maxResults(alias demaxTweets),seeds+seedType(handle|url|keyword) são aceitos como lista de sementes unificada entre actors. Os camposprofiles/searchQuery/maxTweetscontinuam funcionando exatamente como antes; os novos são aliases opcionais. - Bloco de saída normalizado
_normalized(#2) ✅ — defina o input opcionalnormalizeOutput: truepara anexar a cada item um bloco cross-plataforma:{ platform, url, author, text, views, likes, comments, shares, publishedAtISO, lang, hashtags[], engagementVelocity }, ao lado dos campos crus. No Twitter/X,commentsvem dereplies,sharesderetweets + quotes,viewsdas impressões. Padrãofalse. - Data ISO +
engagementVelocity(#6) ✅ — dentro de_normalized,publishedAtISOé a data do tweet em ISO-8601 UTC, eengagementVelocity=(likes + comments + shares) / horas_desde_publicação(ounullquando não há data). - Flag de qualidade
_dataQuality(#7) ✅ — itens bem-sucedidos carregam_dataQuality: "full"(quandonormalizeOutputestá ligado); o guia de diagnóstico recuperável (sem resultados) carrega_dataQuality: "diagnostic"e não é cobrado via PPE.
🛣️ Roadmap / Próximas melhorias (planned)
⚠️ The items below are PLANNED, not yet available. They are not current features — do not rely on them yet. Source: internal social-scrapers improvements handoff (2026-06-19).
⚠️ Os itens abaixo são PLANEJADOS, ainda não disponíveis. Não são funcionalidades atuais — não dependa deles ainda. Fonte: handoff interno de melhorias dos scrapers sociais (2026-06-19).
EN
- Structured
_blockReasoncode (part of #7) — on a confirmed block, emit a machine-readable reason (403 | 429 | captcha) on the diagnostic item. Not yet implemented to avoid changing the current anti-bot/diagnostic gate; today blocks are surfaced as a labeled_dataQuality: "diagnostic"guide only.
PT
- Código
_blockReasonestruturado (parte do #7) — em bloqueio confirmado, emitir um motivo legível por máquina (403 | 429 | captcha) no item de diagnóstico. Ainda não implementado para não alterar o gate anti-bot/diagnóstico atual; hoje os bloqueios são expostos apenas como guia rotulado_dataQuality: "diagnostic".
📝 Changelog
- v1.1.0 (2026-08-27) —
dateFrom/dateToare now honored: the range is enforced in memory against each tweet'screated_at(UTC, both bounds inclusive) before the tweet is stored and before Pay Per Event, so filtered-out tweets are never charged. Tweets with no readable date are dropped while a bound is set, and an invalid bound stops the run with a diagnostic item instead of being silently ignored. - v1.0.0 (2026-02-12) — Initial release: profile scraping, search, full engagement metrics, thread detection, media extraction