A Twitter scraper you call over HTTP: send an X (formerly Twitter) post or profile URL to /data and get the text, every engagement counter including views, media, and author stats back as JSON. No X developer account or API tier. Flat 15 credits per page.
2,000 free API credits · No credit card required
Send the page's normal URL to /data. The page type is detected from the URL, and the response tells you which one it was in request_parameters.type.
type: "tweet"
Full text (long posts included), likes, replies, reposts, quotes, bookmarks and views, hashtags, links, mentions, media, link cards, the quoted or parent post, the author, and the few top replies X shows logged-out visitors.
x.com/user/status/POST_ID
twitter.com/user/status/POST_ID
x.com/i/status/POST_ID
type: "profile"
Name, bio, location, website, avatar and banner, join date, verification, followers, following and post count, pinned post ids and a handful of the account's top original posts.
x.com/user
twitter.com/user
400 that isn't charged, with a message listing what is supported: search, hashtag and explore pages, lists and communities, and a profile's replies, media or likes tabs. More page types and sites are added over time, so don't validate URLs on your side — send the URL and handle the 400.
No selectors, proxies, or headless browser to run. The page-scraping options (js, proxy, headers…) don't apply; country picks the proxy country (default us).
curl -G "https://api.webscraping.ai/data" \
--data-urlencode "api_key=YOUR_API_KEY" \
--data-urlencode "url=https://x.com/jack/status/20"
# Response (excerpt):
# {
# "request_parameters": {"url": "https://x.com/jack/status/20",
# "provider": "twitter", "type": "tweet"},
# "parse_status": "ok",
# "data": {
# "id": "20",
# "url": "https://x.com/jack/status/20",
# "text": "just setting up my twttr",
# "lang": "en",
# "created_at": "2006-03-21T20:50:14.000Z",
# "like_count": 290000,
# "reply_count": 17000,
# "retweet_count": 120000,
# "quote_count": 25000,
# "bookmark_count": 3000,
# "view_count": null,
# "media": [],
# "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
# "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
# ...
# }
# }
# pip install webscraping_ai
# https://pypi.org/project/webscraping-ai/
from webscraping_ai import Client
client = Client(api_key="YOUR_API_KEY")
result = client.data("https://x.com/jack/status/20")
print(result["request_parameters"]["provider"], result["parse_status"])
print(result["data"])
# Response (excerpt):
# {
# "request_parameters": {"url": "https://x.com/jack/status/20",
# "provider": "twitter", "type": "tweet"},
# "parse_status": "ok",
# "data": {
# "id": "20",
# "url": "https://x.com/jack/status/20",
# "text": "just setting up my twttr",
# "lang": "en",
# "created_at": "2006-03-21T20:50:14.000Z",
# "like_count": 290000,
# "reply_count": 17000,
# "retweet_count": 120000,
# "quote_count": 25000,
# "bookmark_count": 3000,
# "view_count": null,
# "media": [],
# "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
# "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
# ...
# }
# }
// npm install webscraping-ai
// https://www.npmjs.com/package/webscraping-ai
import { WebScrapingAI } from 'webscraping-ai';
const client = new WebScrapingAI({ apiKey: 'YOUR_API_KEY' });
const result = await client.data({ url: 'https://x.com/jack/status/20' });
console.log(result.request_parameters.provider, result.parse_status);
console.log(result.data);
// Response (excerpt):
// {
// "request_parameters": {"url": "https://x.com/jack/status/20",
// "provider": "twitter", "type": "tweet"},
// "parse_status": "ok",
// "data": {
// "id": "20",
// "url": "https://x.com/jack/status/20",
// "text": "just setting up my twttr",
// "lang": "en",
// "created_at": "2006-03-21T20:50:14.000Z",
// "like_count": 290000,
// "reply_count": 17000,
// "retweet_count": 120000,
// "quote_count": 25000,
// "bookmark_count": 3000,
// "view_count": null,
// "media": [],
// "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
// "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
// ...
// }
// }
<?php
// composer require webscraping-ai/webscraping-ai-php
// https://packagist.org/packages/webscraping-ai/webscraping-ai-php
require 'vendor/autoload.php';
use WebScrapingAI\Client;
$client = new Client('YOUR_API_KEY');
$result = $client->data(url: 'https://x.com/jack/status/20');
echo $result['request_parameters']['provider'], ' ', $result['parse_status'], "\n";
print_r($result['data']);
// Response (excerpt):
// {
// "request_parameters": {"url": "https://x.com/jack/status/20",
// "provider": "twitter", "type": "tweet"},
// "parse_status": "ok",
// "data": {
// "id": "20",
// "url": "https://x.com/jack/status/20",
// "text": "just setting up my twttr",
// "lang": "en",
// "created_at": "2006-03-21T20:50:14.000Z",
// "like_count": 290000,
// "reply_count": 17000,
// "retweet_count": 120000,
// "quote_count": 25000,
// "bookmark_count": 3000,
// "view_count": null,
// "media": [],
// "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
// "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
// ...
// }
// }
# gem install webscraping_ai
# https://rubygems.org/gems/webscraping_ai
require 'webscraping_ai'
client = WebScrapingAI::Client.new(api_key: 'YOUR_API_KEY')
result = client.data('https://x.com/jack/status/20')
puts "#{result['request_parameters']['provider']} #{result['parse_status']}"
puts result['data'].inspect
# Response (excerpt):
# {
# "request_parameters": {"url": "https://x.com/jack/status/20",
# "provider": "twitter", "type": "tweet"},
# "parse_status": "ok",
# "data": {
# "id": "20",
# "url": "https://x.com/jack/status/20",
# "text": "just setting up my twttr",
# "lang": "en",
# "created_at": "2006-03-21T20:50:14.000Z",
# "like_count": 290000,
# "reply_count": 17000,
# "retweet_count": 120000,
# "quote_count": 25000,
# "bookmark_count": 3000,
# "view_count": null,
# "media": [],
# "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
# "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
# ...
# }
# }
// go get github.com/webscraping-ai/webscraping-ai-go/v4
// https://pkg.go.dev/github.com/webscraping-ai/webscraping-ai-go/v4
package main
import (
"context"
"fmt"
webscrapingai "github.com/webscraping-ai/webscraping-ai-go/v4"
)
func main() {
client, _ := webscrapingai.NewClient(&webscrapingai.Config{APIKey: "YOUR_API_KEY"})
res, _ := client.Data(context.Background(), &webscrapingai.DataOptions{
URL: "https://x.com/jack/status/20",
})
fmt.Println(res.RequestParameters.Provider, res.ParseStatus)
fmt.Println(string(res.Data)) // raw JSON; its shape depends on the provider and page type
}
// Response (excerpt):
// {
// "request_parameters": {"url": "https://x.com/jack/status/20",
// "provider": "twitter", "type": "tweet"},
// "parse_status": "ok",
// "data": {
// "id": "20",
// "url": "https://x.com/jack/status/20",
// "text": "just setting up my twttr",
// "lang": "en",
// "created_at": "2006-03-21T20:50:14.000Z",
// "like_count": 290000,
// "reply_count": 17000,
// "retweet_count": 120000,
// "quote_count": 25000,
// "bookmark_count": 3000,
// "view_count": null,
// "media": [],
// "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
// "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
// ...
// }
// }
// Maven: ai.webscraping:webscraping-ai:4.2.0
// https://central.sonatype.com/artifact/ai.webscraping/webscraping-ai
import ai.webscraping.Client;
import ai.webscraping.Config;
import ai.webscraping.option.DataOptions;
import ai.webscraping.result.DataResult;
Client client = new Client(Config.builder().apiKey("YOUR_API_KEY").build());
DataResult result = client.data(DataOptions.builder()
.url("https://x.com/jack/status/20")
.build());
System.out.println(result.getRequestParameters().getProvider() + " " + result.getParseStatus());
System.out.println(result.getData());
// Response (excerpt):
// {
// "request_parameters": {"url": "https://x.com/jack/status/20",
// "provider": "twitter", "type": "tweet"},
// "parse_status": "ok",
// "data": {
// "id": "20",
// "url": "https://x.com/jack/status/20",
// "text": "just setting up my twttr",
// "lang": "en",
// "created_at": "2006-03-21T20:50:14.000Z",
// "like_count": 290000,
// "reply_count": 17000,
// "retweet_count": 120000,
// "quote_count": 25000,
// "bookmark_count": 3000,
// "view_count": null,
// "media": [],
// "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
// "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
// ...
// }
// }
// dotnet add package WebScrapingAI
// https://www.nuget.org/packages/WebScrapingAI
using WebScrapingAI;
var client = new WebScrapingAIClient(new WebScrapingAIClientOptions { ApiKey = "YOUR_API_KEY" });
var result = await client.DataAsync(new DataRequest {
Url = "https://x.com/jack/status/20",
});
Console.WriteLine($"{result.RequestParameters.Provider} {result.ParseStatus}");
Console.WriteLine(result.Data);
// Response (excerpt):
// {
// "request_parameters": {"url": "https://x.com/jack/status/20",
// "provider": "twitter", "type": "tweet"},
// "parse_status": "ok",
// "data": {
// "id": "20",
// "url": "https://x.com/jack/status/20",
// "text": "just setting up my twttr",
// "lang": "en",
// "created_at": "2006-03-21T20:50:14.000Z",
// "like_count": 290000,
// "reply_count": 17000,
// "retweet_count": 120000,
// "quote_count": 25000,
// "bookmark_count": 3000,
// "view_count": null,
// "media": [],
// "author": {"id": "12", "username": "jack", "followers": 6000000, ...},
// "replies": [{"id": "...", "text": "...", "like_count": 1200, ...}, ...],
// ...
// }
// }
Trimmed, and the counts are illustrative — they change constantly. Fields a page doesn't expose come back as null, though some flags come back false and lists come back empty. data can be null when parse_status is parse_failed or not_found, so check it before reading fields.
The key fields per page type. Names are snake_case across every site; the full contract is in the API reference.
type: "tweet"| Field | What it holds |
|---|---|
id, url, text, lang, created_at | The post. text is the full text, long posts included; is_truncated is true in the rare case a long post's full text wasn't on the page. |
like_count, reply_count, retweet_count, quote_count, bookmark_count, view_count | Every counter X shows. view_count is null on posts from before X counted views (late 2022). |
is_reply, is_quote, is_retweet, is_edited | Post kind flags, plus in_reply_to_id, in_reply_to_username and conversation_id. |
quoted_tweet, parent_tweet, retweeted_tweet | The related post, one level deep: the same fields, with its own related posts null. |
hashtags, urls, user_mentions, symbols | Entities: hashtags, expanded links, mentioned accounts, cashtags. |
media | Photos and videos with type, url (the best MP4 for video), preview_url, size, duration_ms, alt_text. |
card, place | Link preview card (title, url, image_url…) and tagged place. |
author | username, name, description, is_verified, is_blue_verified, followers, following, statuses_count. |
replies | The few top replies X shows logged-out visitors under the post (usually 3–4), each with the post fields except the nested quoted_tweet/parent_tweet/retweeted_tweet (null) and no replies of its own. |
type: "profile"| Field | What it holds |
|---|---|
id, username, name, url, description | Identity and bio. |
location, external_url, profile_picture, cover_picture, created_at | Profile details and join date. |
is_verified, is_blue_verified, verified_type, is_private | Verification and protection. |
followers, following, statuses_count, affiliates_count | Account counts; affiliates_count is for organizations. |
pinned_tweet_ids, tweets | Pinned post ids, and the handful of top original posts X shows logged-out visitors (about 5, ranked by X, not newest first), with the same one-level-deep post fields as replies. |
Everything comes from what Twitter (X) shows a logged-out visitor. That sets these limits.
favourites_count, media_count and listed_count come back null./ai/fields extracts the fields you describe in plain language from any public page, and /html returns the rendered HTML for your own parser.
Every supported Twitter (X) page type costs the same, with no extra charge for proxies or retries. That's about $1.74 per 1,000 pages on the $29 plan.
| Plan | Price | Credits | Pages |
|---|---|---|---|
| Free | $0 | 2,000 | up to 133 |
| Personal | $29/mo | 250,000 | up to 16,666 |
| Plus | $99/mo | 1,000,000 | up to 66,666 |
| Startup | $249/mo | 3,000,000 | up to 200,000 |
The free plan's 2,000 credits renew monthly. All plans, including pay-as-you-go credits.
400, not charged.500, not charged.parse_status parse_failed (the page was fetched but couldn't be parsed) and not_found (the page doesn't exist) are successful requests and cost 15 credits, like ok.webscraping-ai has a data command; pass - to read URLs from stdin, one per line.
webscraping-ai data 'https://x.com/jack/status/20'Claude, Cursor and other MCP clients get a webscraping_ai_data tool from the hosted MCP server (OAuth login, no API key to paste). Ask for a Twitter (X) page's data in plain language and the agent calls it.
The WebScraping.AI n8n node has a Get Structured Data operation: feed it URLs from a sheet or a trigger and route the JSON onward, no code.
Can you still scrape data from Twitter?
Yes, from public pages. X still serves post and profile pages to logged-out visitors, and /data turns them into JSON: the full post text, every counter including views, media, the author and the top replies, or a profile with its counts and a handful of its top posts.
Do I need an X (Twitter) API plan?
No. /data reads the public post or profile page for the URL you send, so there is no X developer account, API tier or bearer token involved. You pay the same 15 credits per page whatever the post.
Does it return view counts and reposts?
Yes: like_count, reply_count, retweet_count, quote_count, bookmark_count and view_count are all returned. view_count is null only on posts older than X's view counting (late 2022) or where the count is hidden.
Can I get all posts from an account?
Not today. A profile returns the account details, pinned post ids and the handful of top original posts X shows logged-out visitors, which aren't the latest ones. For a specific post, send its URL.
Is there a free Twitter (X) scraper API?
Yes, for trying it out: the free plan includes 2,000 API credits every month, which covers 133 Twitter (X) pages at 15 credits each. No credit card is needed. Paid plans start at $29/mo for 250,000 credits, or buy pay-as-you-go credits with no subscription from a $20 top-up (100,000 credits, about 6,666 pages).
How much does the Twitter (X) Scraper API cost?
A flat 15 credits per page, for every supported Twitter (X) page type. On the $29/mo plan (250,000 credits) that is up to 16,666 pages, or about $1.74 per 1,000. Unsupported URLs return a 400 and fetch failures a 500; neither is charged. parse_failed and not_found results are successful requests and are charged.
What happens if I send a URL you don't support?
You get a 400 that isn't charged, and its message lists what is supported. For pages /data doesn't cover, /ai/fields extracts the fields you describe from any public URL, and /html returns the rendered page for your own parser.
One API key, one request format, the same response envelope.
Get started with 2,000 free API credits. No credit card required.