# Twitter (X) Video Downloader (`parsebird/twitter-video-downloader`) Actor

Download Twitter (X) videos, GIFs and photos from tweet URLs or IDs. Get MP4 links in every quality, thumbnails, duration, plus tweet text, author, likes, retweets and views. Export JSON, CSV, Excel.

- **URL**: https://apify.com/parsebird/twitter-video-downloader.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.99 / 1,000 tweet medias

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Twitter (X) Video Downloader

Twitter (X) Video Downloader turns tweet links or IDs into direct MP4 download links for every video and GIF on [X (Twitter)](https://x.com), with all available qualities, photos in original size, and tweet details such as text, author, likes, retweets, and views.

<table><tr>
<td style="border-left:4px solid #000000;padding:12px 16px;font-weight:600">
Paste x.com or twitter.com links or numeric tweet IDs and get the best-quality MP4 plus every other resolution, the HLS stream, thumbnail, duration, aspect ratio, and 20+ tweet and author fields, with no X login or API key.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```text
Use Apify Actor parsebird/twitter-video-downloader to get download links for videos, GIFs, and photos in public tweets on X (Twitter). Example with ApifyClient (Python): client.actor("parsebird/twitter-video-downloader").call(run_input={"tweetUrls":["https://x.com/SpaceX/status/1732824684683784516","1986587629740270045"]}). Inputs: tweetUrls array of strings required (x.com, twitter.com, or mobile.twitter.com status links, or numeric tweet IDs; up to 5,000; duplicates processed once); videoOnly boolean default false (skip photos); includeAllQualities boolean default true (videoQualities list); includeMetadata boolean default true (text and author/engagement); includeQuotedMedia boolean default false (also media from the quoted tweet, rows get quotedBy). Output: one row per video or GIF, plus one row per tweet holding all its photos; tweets that fail or have no media get a free row with status failed or no_media and an error. Fields: tweetId, tweetUrl, status (success | failed | no_media), mediaType (video | gif | photo), mediaIndex, mediaCount, text, displayText, createdAt (ISO 8601), language, author {name, username, profileImage, verified, followers}, engagement {likes, retweets, replies, quotes, bookmarks, views} as formatted strings like "125.4K", engagementCounts (same as numbers), thumbnail, duration (m:ss), durationMs, width, height, aspectRatio, quality, downloadUrl (best MP4), hlsUrl, videoQualities[{url, bitrate, quality, resolution, contentType}], photos[{url, originalUrl, width, height, altText}], dataSource, timestamp, error. API docs: https://docs.apify.com/api/client/python/ and https://docs.apify.com/api/client/js/. Token: https://console.apify.com/account/integrations.
```

### What is Twitter (X) Video Downloader?

**Twitter (X) Video Downloader** is a **Twitter video downloader API** that gives you **direct MP4 links** for videos and GIFs in public tweets, in **every quality X offers**. It also returns **photos in original resolution** and optional **tweet metadata**: text, post date, language, author details with follower count, and likes, retweets, replies, quotes, bookmarks, and views.

You don't need an X account, cookies, or an API key. The easiest way to try it is to open the actor, keep the prefilled SpaceX tweet, and click **Start**. Each tweet takes about a second.

The actor returns download links. It does not store the video files for you; open `downloadUrl` in a browser or pass it to any download tool.

### What can Twitter (X) Video Downloader do?

- 🎬 **Download Twitter videos** as MP4, with the highest-bitrate version in `downloadUrl`.
- 📶 **Pick any quality**: every MP4 rendition X offers (for example 480x270 up to 2048x1536) with bitrate and resolution, plus the HLS stream.
- 🌀 **Save Twitter GIFs**: X stores GIFs as MP4 files, and you get the direct link.
- 🖼️ **Get photos in full size**: every photo in a tweet with an `originalUrl` for the full-resolution image and its alt text.
- 🧾 **Add tweet details**: text with links expanded, date, language, author, followers, likes, retweets, replies, quotes, bookmarks, and views.
- 🔁 **Follow quoted tweets**: optionally include the video or photos from the tweet being quoted.
- 🔗 **Paste links as you find them**: x.com, twitter.com, mobile.twitter.com, `/i/web/status/` links, links ending in `/video/1`, or bare tweet IDs.
- ⏱️ **Automate** with [Apify schedules](https://docs.apify.com/platform/schedules), the [Apify API](https://docs.apify.com/api/v2), webhooks, and [integrations](https://apify.com/integrations) such as Google Sheets, Make, Zapier, and Slack.
- 📁 **Export** results as JSON, CSV, Excel, HTML, or XML.

### What data can you extract from X (Twitter)?

| Field | Description |
|-------|-------------|
| `downloadUrl` | Direct link to the best-quality MP4 |
| `videoQualities` | Every MP4 quality with `bitrate`, `quality` (for example `10368kbps`), and `resolution` (for example `1920x1080`) |
| `hlsUrl` | HLS (m3u8) stream for the video |
| `photos` | Photo URLs, `originalUrl` for full size, dimensions, and alt text |
| `mediaType`, `thumbnail`, `duration`, `durationMs`, `width`, `height`, `aspectRatio` | Media type (`video`, `gif`, `photo`) and video details |
| `text`, `displayText`, `createdAt`, `language` | Tweet text as posted and as displayed (expanded links, media links removed), post time, and language |
| `author` | Display name, username, profile image, blue check, and followers |
| `engagement`, `engagementCounts` | Likes, retweets, replies, quotes, bookmarks, and views, formatted (`125.4K`) and as numbers |
| `status`, `error` | `success`, `failed` (deleted, private, or unavailable), or `no_media`, with the reason |

### How to download Twitter videos

1. Open [Twitter (X) Video Downloader](https://apify.com/parsebird/twitter-video-downloader) and click **Try for free** or **Start**.
2. In **Tweet URLs or IDs**, paste one tweet link or ID per line. Copy links with **Share → Copy link** on X.
3. Optionally turn on **Videos and GIFs only**, turn off **Include all qualities** or **Include tweet details**, or turn on **Include media from quoted tweets**.
4. Click **Start**.
5. Open the **Output** tab and click a `downloadUrl` to save the MP4, or export the results as JSON, CSV, or Excel.

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `tweetUrls` | array of strings | **Yes** | — | Tweet links from x.com or twitter.com, or numeric tweet IDs. Up to 5,000 per run. |
| `videoOnly` | boolean | No | `false` | Skip photos. Photo-only tweets get a free `no_media` row. |
| `includeAllQualities` | boolean | No | `true` | Add `videoQualities` with every MP4 quality. |
| `includeMetadata` | boolean | No | `true` | Add tweet text, date, language, author, and engagement. |
| `includeQuotedMedia` | boolean | No | `false` | Also return media from the quoted tweet (`quotedBy` is set on those rows). |
| `proxyConfiguration` | object | No | none | Not needed for most runs; the actor switches to Apify Proxy if X limits requests. |

### Input / Output

Example input with a URL and an ID:

```json
{
  "tweetUrls": [
    "https://x.com/katyperry/status/1986587629740270045",
    "1732824684683784516"
  ],
  "videoOnly": false,
  "includeAllQualities": true,
  "includeMetadata": true
}
```

A real output row for the first tweet (`videoQualities` shortened to two of five):

```json
{
  "tweetId": "1986587629740270045",
  "tweetUrl": "https://x.com/katyperry/status/1986587629740270045",
  "status": "success",
  "mediaType": "video",
  "mediaIndex": 1,
  "mediaCount": 1,
  "text": "bandaids\nout now\nhttps://t.co/21WmKj8jlL https://t.co/ZqOQjRHGDD",
  "displayText": "bandaids\nout now\nkaty.lnk.to/BandaidsVideo",
  "createdAt": "2025-11-07T00:12:54Z",
  "language": "en",
  "author": {
    "name": "KATY PERRY",
    "username": "katyperry",
    "profileImage": "https://pbs.twimg.com/profile_images/2070301938965508096/naJYT_MY_normal.jpg",
    "verified": true,
    "followers": 90024005
  },
  "engagement": {
    "likes": "125.4K",
    "retweets": "17.4K",
    "replies": "7.2K",
    "quotes": "4.4K",
    "bookmarks": "5.6K",
    "views": "11.4M"
  },
  "engagementCounts": {
    "likes": 125398,
    "retweets": 17372,
    "replies": 7205,
    "quotes": 4373,
    "bookmarks": 5586,
    "views": 11356289
  },
  "thumbnail": "https://pbs.twimg.com/amplify_video_thumb/1986587308167208962/img/w4dQka5ShDarBqu9.jpg",
  "duration": "0:29",
  "durationMs": 29496,
  "width": 2048,
  "height": 1536,
  "aspectRatio": "4:3",
  "quality": "25128kbps",
  "downloadUrl": "https://video.twimg.com/amplify_video/1986587308167208962/vid/avc1/2048x1536/KjM04BYtvGe3XYO9.mp4?tag=21",
  "hlsUrl": "https://video.twimg.com/amplify_video/1986587308167208962/pl/diWbychXzbmsARjY.m3u8?tag=21&v=e90",
  "videoQualities": [
    {
      "url": "https://video.twimg.com/amplify_video/1986587308167208962/vid/avc1/2048x1536/KjM04BYtvGe3XYO9.mp4?tag=21",
      "bitrate": 25128000,
      "quality": "25128kbps",
      "resolution": "2048x1536",
      "contentType": "video/mp4"
    },
    {
      "url": "https://video.twimg.com/amplify_video/1986587308167208962/vid/avc1/1440x1080/XCv1kDR6cKT9YT0C.mp4?tag=21",
      "bitrate": 10368000,
      "quality": "10368kbps",
      "resolution": "1440x1080",
      "contentType": "video/mp4"
    }
  ],
  "dataSource": "graphql",
  "timestamp": "2026-09-30T23:21:05.799Z"
}
```

Photo rows carry `photos` instead of the video fields. Rows for tweets that couldn't be loaded look like `{"tweetId": "1", "status": "failed", "error": "Tweet not found or deleted"}`. Download results in JSON, CSV, Excel, HTML, or XML.

### Python API example

```python
from apify_client import ApifyClient
import urllib.request

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("parsebird/twitter-video-downloader").call(run_input={
    "tweetUrls": ["https://x.com/SpaceX/status/1732824684683784516"],
    "videoOnly": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["status"] == "success":
        urllib.request.urlretrieve(item["downloadUrl"], f"{item['tweetId']}-{item['mediaIndex']}.mp4")
        print("saved", item["tweetUrl"], item["quality"])
```

### JavaScript API example

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('parsebird/twitter-video-downloader').call({
    tweetUrls: ['1986587629740270045', 'https://twitter.com/NASA/status/2046969982131507400'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    if (item.mediaType === 'photo') console.log(item.photos.map((p) => p.originalUrl));
    else if (item.status === 'success') console.log(item.downloadUrl, item.engagement?.views);
}
```

See the [Python client](https://docs.apify.com/api/client/python/) and [JavaScript client](https://docs.apify.com/api/client/js/) docs for more options.

### Use cases

- **Social media teams**: save your brand's or partners' X videos in the best quality for reposting and archiving.
- **Researchers and journalists**: archive videos and their context (text, date, author, views) before they are deleted.
- **Content creators**: collect reference clips and GIFs with their engagement numbers.
- **Data pipelines**: feed MP4 links into transcription, moderation, or AI video tools, such as our [Video & Audio Transcriber](https://apify.com/parsebird/video-audio-transcriber).
- **Monitoring**: schedule runs over a list of tweets to track views and likes over time.

### How it works

1. The actor reads each tweet the way x.com does for logged-out visitors and collects its media, text, author, and counts.
2. If that source is unavailable, it falls back to X's public embed data. Those rows have `dataSource: "embed"`, and retweets, quotes, bookmarks, views, and followers are empty because embeds don't include them.
3. It saves one row per video or GIF, sorted qualities with the best one in `downloadUrl`, and one row per tweet for its photos.

### How much does it cost to download Twitter videos?

**What is the price per Twitter video?**

The actor uses pay-per-event pricing: you pay per media row saved, and platform usage is included.

| Event | Free plan | Bronze | Silver | Gold |
|-------|-----------|--------|--------|------|
| `media-extracted` | $0.00599 (**$5.99 / 1,000**) | $0.00499 (**$4.99 / 1,000**) | $0.00449 (**$4.49 / 1,000**) | $0.00399 (**$3.99 / 1,000**) |

One `media-extracted` event is one successful row: a video, a GIF, or a tweet's photo set. Rows with `failed` or `no_media` status are free. The prefilled one-tweet test costs about $0.006 on the Free plan, and 1,000 videos cost $5.99. Apify's free plan includes monthly platform credits you can use to try the actor.

### Is it legal to download videos from Twitter?

**Is downloading X (Twitter) videos legal?**

The actor only reads public tweets that X shows to anyone without logging in. Downloading public data is generally legal in many jurisdictions, but videos and photos belong to their creators and are protected by copyright, and profiles contain personal data covered by laws such as GDPR and CCPA. Get permission before reusing someone else's media, respect [X's Terms of Service](https://x.com/en/tos), and consult your lawyer if unsure. Read more in Apify's guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

### Other video downloaders and related Actors

| Actor | Best for |
|-------|----------|
| [X/Twitter Article Markdown API](https://apify.com/parsebird/x-twitter-article-markdown) | X Articles and long posts as clean Markdown |
| [Video & Audio Transcriber](https://apify.com/parsebird/video-audio-transcriber) | Transcribing the videos you download |
| [YouTube Shorts Downloader](https://apify.com/parsebird/youtube-shorts-downloader) | YouTube Shorts download links |
| [Telegram Media Downloader](https://apify.com/parsebird/telegram-media-downloader) | Media from public Telegram channels |
| [Kick Video Downloader](https://apify.com/parsebird/kick-video-downloader) | Kick clips and VODs |
| [TikTok Slideshow Downloader](https://apify.com/parsebird/tiktok-slideshow-downloader) | Every photo from TikTok photo-mode posts |

### FAQ

**Which links work?**
Status links from x.com, twitter.com, and mobile.twitter.com (with or without `?s=20` or `/video/1` at the end), `x.com/i/web/status/` links, and numeric tweet IDs. Profile links and other pages are skipped with a warning in the log.

**Why did a tweet fail?**
The tweet was deleted, is from a protected account, or is otherwise unavailable to logged-out visitors. The `error` field says what X returned. Failed rows are free.

**What quality do I get?**
`downloadUrl` is the highest-bitrate MP4 X has for that video, which depends on what was uploaded (for example 1280x720 at 2176 kbps or 2048x1536 at 25128 kbps). `videoQualities` lists every MP4 version, highest first.

**Do GIFs have a quality?**
X stores GIFs as a single MP4 without a bitrate, so `quality` shows the GIF's size (for example `480x270`) and `duration` is empty.

**Why are views empty for some tweets?**
X only started counting views in December 2022, so older tweets have no view count. Rows with `dataSource: "embed"` also have no views, retweets, quotes, bookmarks, or followers.

**How long do the download links work?**
Video and photo links from `video.twimg.com` and `pbs.twimg.com` opened without X cookies in our tests. X can remove media when a tweet is deleted, so download what you need soon after the run.

**Can I download videos from private accounts?**
No. The actor only reads tweets X shows to logged-out visitors.

**Where can I report issues?**
Open the **Issues** tab on the actor page with your input and run ID.

# Changelog

This Actor's version history is a separate document: https://apify.com/parsebird/twitter-video-downloader/changelog.md

# Actor input Schema

## `tweetUrls` (type: `array`):

Add one tweet per line: an x.com or twitter.com status link, or a numeric tweet ID. Duplicates are processed once.

## `videoOnly` (type: `boolean`):

Turn on to skip photos. Tweets with only photos get a free 'no\_media' row instead.

## `includeAllQualities` (type: `boolean`):

Add every MP4 quality X offers (for example 480x270 to 1920x1080) in 'videoQualities'. The best quality is always in 'downloadUrl'.

## `includeMetadata` (type: `boolean`):

Add tweet text, date, language, author (name, handle, avatar, verified, followers) and engagement (likes, retweets, replies, quotes, bookmarks, views).

## `includeQuotedMedia` (type: `boolean`):

Also return videos, GIFs and photos from the tweet it quotes. Those rows have 'quotedBy' set to your tweet's ID.

## `proxyConfiguration` (type: `object`):

No proxy is needed for most runs. If X limits requests, the actor switches to Apify Proxy on its own.

## Actor input object example

```json
{
  "tweetUrls": [
    "https://x.com/SpaceX/status/1732824684683784516"
  ],
  "videoOnly": false,
  "includeAllQualities": true,
  "includeMetadata": true,
  "includeQuotedMedia": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "tweetUrls": [
        "https://x.com/SpaceX/status/1732824684683784516"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/twitter-video-downloader").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 = { "tweetUrls": ["https://x.com/SpaceX/status/1732824684683784516"] }

# Run the Actor and wait for it to finish
run = client.actor("parsebird/twitter-video-downloader").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "tweetUrls": [
    "https://x.com/SpaceX/status/1732824684683784516"
  ]
}' |
apify call parsebird/twitter-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/twitter-video-downloader"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/cvhokVRAfGmcFOjjN/builds/ePOC05y77a6qwoAd2/openapi.json
