---
title: "Twitter Scraper API - Scrape Tweets & X Profiles"
description: "Twitter scraper API for X: send a tweet or profile URL, get text, likes, reposts, views, media and author stats as JSON. No X API plan. 15 credits a page."
url: https://webscraping.ai/twitter-scraper-api
markdown_index: https://webscraping.ai/llms.txt
---
STRUCTURED DATA API

# Twitter (X) Scraper API

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.

[Start Free Trial](https://webscraping.ai/auth/sign_up)[View Documentation](https://webscraping.ai/docs#data)

2,000 free API credits · No credit card required

## Scrape tweets and X profiles

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`.

### Post (tweet)

`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`

### Profile

`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`

 These URLs return a `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.

## How to scrape Twitter (X) with one API call

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**

```bash
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, ...}, ...],
# ...
# }
# }
```

**Python**

```python
# 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, ...}, ...],
# ...
# }
# }
```

**JavaScript**

```javascript
// 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**

```php
<?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, ...}, ...],
// ...
// }
// }
```

**Ruby**

```ruby
# 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**

```go
// 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, ...}, ...],
// ...
// }
// }
```

**Java**

```java
// 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, ...}, ...],
// ...
// }
// }
```

**C#**

```csharp
// 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.

## What the Twitter (X) scraper returns

The key fields per page type. Names are snake\_case across every site; the full contract is in the [API reference](https://webscraping.ai/docs#data).

### `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`. |

## What's not included

Everything comes from what Twitter (X) shows a logged-out visitor. That sets these limits.

**Short timelines.** A profile carries only the handful of top original posts X picks for logged-out visitors, not the full or latest history; replies under a post are the few top replies X shows, not the whole thread.

**Some profile counts aren't public.** `favourites_count`, `media_count` and `listed_count` come back `null`.

**No search.** Search, hashtag, list and community pages return the free 400.

**Need a page type or site that isn't supported?** [`/ai/fields`](https://webscraping.ai/docs#ai-fields) extracts the fields you describe in plain language from any public page, and [`/html`](https://webscraping.ai/docs#html) returns the rendered HTML for your own parser.

## Flat pricing: 15 credits per page

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](https://webscraping.ai/#pricing), including pay-as-you-go credits.

### What's charged

**Unsupported URL or page type:** a `400`, not charged.

**Page couldn't be fetched:** a `500`, not charged.

**Charged even without data:** `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`.

## Also from the terminal, AI agents, and n8n

### CLI

[webscraping-ai](https://github.com/webscraping-ai/webscraping-ai-cli) has a `data` command; pass `-` to read URLs from stdin, one per line.

```bash
webscraping-ai data 'https://x.com/jack/status/20'
```

### MCP server

Claude, Cursor and other MCP clients get a `webscraping_ai_data` tool from the [hosted MCP server](https://webscraping.ai/integrations/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.

### n8n

The [WebScraping.AI n8n node](https://webscraping.ai/integrations/n8n) has a **Get Structured Data** operation: feed it URLs from a sheet or a trigger and route the JSON onward, no code.

## Frequently asked questions

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.

## Other sites on the same endpoint

One API key, one request format, the same response envelope.

[YouTube Scraper API](https://webscraping.ai/youtube-scraper-api)[TikTok Scraper API](https://webscraping.ai/tiktok-scraper-api)[LinkedIn Scraper API](https://webscraping.ai/linkedin-scraper-api)[Instagram Scraper API](https://webscraping.ai/instagram-scraper-api)[Reddit Scraper API](https://webscraping.ai/reddit-scraper-api)[All social media sites](https://webscraping.ai/social-media-scraper-api)[Google SERP API](https://webscraping.ai/google-serp-api)

[Social media monitoring](https://webscraping.ai/use-cases/social-media-monitoring): Track brand mentions and posts across sites.

[Brand sentiment tracking](https://webscraping.ai/use-cases/brand-sentiment-tracking): Feed post text into sentiment analysis.

[API reference](https://webscraping.ai/docs#data): Parameters, response envelope and parse\_status values.

## Get Twitter (X) data as JSON today

Get started with 2,000 free API credits. No credit card required.

[Start Free Trial](https://webscraping.ai/auth/sign_up)[View API Documentation](https://webscraping.ai/docs#data)
