# Twitter Scraper (Cheap) (`data_api/twitter-scraper-cheap`) Actor

Unlimited Twitter (X.com) Scraper to extract tweets, author profiles, engagement metrics, and media directly from Twitter. Fetch raw JSON tweet data by Tweet ID with no API keys or volume limits. Ideal for social media monitoring, research, sentiment analysis, and competitor tracking.

- **URL**: https://apify.com/data\_api/twitter-scraper-cheap.md
- **Developed by:** [Data API](https://apify.com/data_api) (community)
- **Categories:** Social media, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Twitter (X) Tweet Scraper

![Twitter (X) Tweet Scraper](cover.jpg)

The official X API puts tweet data behind paid tiers, rate caps, and an approval process that can take days. If all you need are the plain facts of a tweet, that is a lot of friction. This scraper skips it. Hand it a list of tweet IDs and each post comes back as one flat row: the text, who posted it, the like and reply counts, any hashtags, and links to attached media. You don't need developer keys or a login, and there's no per-call quota to worry about.

### What you get

Every tweet ID you pass becomes one row with a steady shape, so the data drops straight into a sheet or database. Three groups of fields per tweet:

- **Post** — `postId`, `postUrl`, `postText`, `postedAt`, `languageCode`, `sensitiveMedia`, `collectedAt`
- **Author** — `authorDisplayName`, `authorHandle`, `authorUserId`, `authorAvatarUrl`, `authorVerified`
- **Engagement and content** — `likeCount`, `repostCount`, `quoteCount`, `replyCount`, `hashtagList`, `linkedUrls`, `mediaLinks`

If a tweet is deleted, protected, or the ID is malformed, you still get a row carrying `hasError`, `errorDetail`, and `removed` so nothing silently disappears from your run.

### Quick start

1. Grab the tweet IDs you want — the ID is the long number at the end of a tweet URL (`x.com/anyuser/status/1899111222333444555`).
2. Hit **Try for free** and open the input form.
3. Paste your IDs into **Tweet IDs**, one per line.
4. Press **Start**, then export the results as JSON, CSV, Excel, or XML when the run finishes.

![How it works](how-it-works.jpg)

### Use cases

- **Brand monitoring** — pull the tweets mentioning your product and read engagement at a glance
- **Academic research** — gather public posts for discourse, sentiment, or network studies
- **Competitor tracking** — collect a rival's top posts and see which ones actually landed
- **Newsroom verification** — capture a tweet's text, author, and timestamp before it gets edited or deleted
- **Model training data** — assemble labelled text and engagement signals for an NLP dataset
- **Content archiving** — keep a permanent copy of tweets that matter to your team

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `tweetIdList` | array of strings | Yes | Numeric tweet IDs to collect. Each ID is the number at the end of a tweet URL. Every ID is fetched independently. |

#### Example input

```json
{
    "tweetIdList": [
        "1899111222333444555",
        "1846200900100200300",
        "1772345678901234567",
        "1700112233445566778",
        "1623456789012345678"
    ]
}
```

### Output

Each tweet ID produces one row. Successful rows carry the full post, author, and engagement fields; rows that fail carry the error fields instead, so your dataset stays predictable.

#### Example output

```json
{
    "postId": "1899111222333444555",
    "postUrl": "https://x.com/datatrails/status/1899111222333444555",
    "postText": "Shipped a new export format today. CSV, JSON, and Excel all in one click.",
    "postedAt": "2026-02-18T09:42:11.000Z",
    "authorDisplayName": "Data Trails",
    "authorHandle": "datatrails",
    "authorUserId": "1502288841992300000",
    "authorAvatarUrl": "https://pbs.twimg.com/profile_images/1502288/avatar_normal.jpg",
    "authorVerified": true,
    "likeCount": 248,
    "repostCount": 31,
    "quoteCount": 4,
    "replyCount": 17,
    "languageCode": "en",
    "sensitiveMedia": false,
    "hashtagList": ["dataviz", "opensource"],
    "linkedUrls": ["https://t.co/9pLm2QrXyz"],
    "mediaLinks": ["https://pbs.twimg.com/media/Gx7kP2QWcAA1234.jpg"],
    "collectedAt": "2026-06-30T11:29:05.123456+00:00"
}
```

#### Output fields

| Field | Type | Description |
|-------|------|-------------|
| `postId` | string | The numeric identifier of the tweet |
| `postUrl` | string | Direct link to the tweet on x.com |
| `postText` | string | The written body of the tweet |
| `postedAt` | string | When the tweet went live |
| `authorDisplayName` | string | The public name on the author's profile |
| `authorHandle` | string | The author's @ handle on X |
| `authorUserId` | string | The numeric account ID of the author |
| `authorAvatarUrl` | string | Link to the author's profile picture |
| `authorVerified` | boolean | Whether the account carries a verified badge |
| `likeCount` | integer | How many likes the tweet has |
| `repostCount` | integer | How many times the tweet was reposted |
| `quoteCount` | integer | How many quote tweets reference this post |
| `replyCount` | integer | How many replies the tweet drew |
| `languageCode` | string | The language X detected for the tweet |
| `sensitiveMedia` | boolean | Whether the attached media is flagged sensitive |
| `hashtagList` | array | Hashtags found inside the tweet |
| `linkedUrls` | array | Outbound links shared in the tweet |
| `mediaLinks` | array | Image or video URLs attached to the tweet |
| `collectedAt` | string | When this row was captured |
| `hasError` | boolean | True when the tweet could not be collected |
| `errorDetail` | string | Explanation of why a tweet failed to load |
| `removed` | boolean | True when the tweet was deleted or is unavailable |

### Tips for best results

- **Use the ID, not the URL.** The input takes the numeric ID at the tail of a tweet link, so strip everything before the final number.
- **Run a small batch first.** Try five or ten IDs to confirm the fields match your pipeline before pushing a long list.
- **Watch the error fields.** A row with `hasError` set to true means the tweet was deleted, made private, or the ID was wrong — check `errorDetail` to see which.
- **Deleted tweets still return a row.** The `removed` flag marks posts that X has taken down, so you can filter them out cleanly.
- **No keys or login needed.** The scraper reads public tweet data directly, so there is nothing to authenticate and no quota to top up.

### How can I use Twitter (X) tweet data?

**How can I use the Twitter (X) Tweet Scraper to track how a post performed?**
Feed in the IDs of the tweets you care about and each row comes back with `likeCount`, `repostCount`, `quoteCount`, and `replyCount` alongside the text and author. Pull the same IDs again later and compare the counts to watch engagement build over time — a simple way to measure reach without the paid X analytics tier.

**How can I export tweet text and author details for research?**
Paste a batch of tweet IDs and the scraper returns `postText`, `authorHandle`, `authorDisplayName`, `postedAt`, and `languageCode` for each one. Export the dataset as CSV or JSON and you have a clean corpus ready for sentiment analysis, discourse studies, or training an NLP model — no API approval required.

**How can I archive tweets before they are deleted or edited?**
Collect the IDs of the posts you want to preserve and run them through the scraper. Each tweet is saved as a flat row with its full text, timestamp, author, and media links. Because the row is captured at scrape time, you keep a copy of what the tweet said even if it later gets edited or taken down.

**How can I pull the media and links out of a list of tweets?**
Every successful row includes `mediaLinks` for attached images and videos and `linkedUrls` for any outbound links shared in the post. Run your IDs through once and you get a tidy list of every asset and reference, ready to download or cross-check.

### Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses or private contact information. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

### Support

Questions, feature requests, or a field you'd like added? Reach out at <data.apify@proton.me> and we'll get back to you.

# Actor input Schema

## `tweetIdList` (type: `array`):

Numeric Twitter (X) post IDs to collect. The ID is the long number at the end of a tweet URL, for example x.com/anyuser/status/1899999999999999999.

## Actor input object example

```json
{
  "tweetIdList": [
    "896523232098078720",
    "440322224407314432"
  ]
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "tweetIdList": [
        "1899111222333444555",
        "1846200900100200300",
        "1772345678901234567",
        "1700112233445566778",
        "1623456789012345678"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("data_api/twitter-scraper-cheap").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "tweetIdList": [
        "1899111222333444555",
        "1846200900100200300",
        "1772345678901234567",
        "1700112233445566778",
        "1623456789012345678",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("data_api/twitter-scraper-cheap").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "tweetIdList": [
    "1899111222333444555",
    "1846200900100200300",
    "1772345678901234567",
    "1700112233445566778",
    "1623456789012345678"
  ]
}' |
apify call data_api/twitter-scraper-cheap --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=data_api/twitter-scraper-cheap",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/OHbykukX65pr9DinH/builds/EUhe5Bb6rE1xm5cRi/openapi.json
