# X (Twitter) Video Downloader - MP4 or MP3 (`dami_studio/x-video-downloader`) Actor

Paste public X or Twitter post links and get the video as an MP4, or just its sound as an MP3. Each file is stored in the run with a direct download link. No login, no cookies. You pay per megabyte of file delivered, and links that fail cost nothing per megabyte.

- **URL**: https://apify.com/dami\_studio/x-video-downloader.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Videos, Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 1,000 megabyte downloadeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## X (Twitter) Video Downloader

Paste the link of a public X post with a video in it and you get the video as an MP4, or only its
sound as an MP3. twitter.com links work the same way. Each file is saved in the run's key-value store,
and its row in the dataset carries a direct download link.

You pay for the megabytes you receive. A link that fails, or a video over your size limit, is skipped
and not billed per megabyte.

### Input

```json
{ "urls": ["https://x.com/historyinmemes/status/1790637656616943991"] }
```

| Field | Default | What it does |
|---|---|---|
| `urls` | none | One link per line, each to a post (x.com/name/status/... or twitter.com/name/status/...). |
| `quality` | `1080` | `best`, `1080`, `720`, `480` or `360`. The number is the short side of the picture, so `720` means 1280x720 for a landscape video and 720x1280 for a vertical one. If a video doesn't come in that quality, you get the closest one it has. |
| `audioOnly` | `false` | Only the video's sound, as a 128 kbit/s MP3. |
| `maxMegabytes` | `500` | Your limit per video. A bigger video is skipped before anything is downloaded. |

A post with several videos gives you the first one. Pick another by ending the link with `/video/2`,
`/video/3` and so on.

This actor takes X links only. A TikTok or Facebook link is refused before anything is fetched, with a
pointer to our [TikTok Video Downloader](https://apify.com/dami_studio/tiktok-video-downloader) or
[Facebook Video Downloader](https://apify.com/dami_studio/facebook-video-downloader). YouTube links go
in our [YouTube Downloader](https://apify.com/dami_studio/youtube-video-downloader).

### What you get

One dataset row per delivered file:

```json
{
  "url": "https://x.com/historyinmemes/status/1790637656616943991",
  "host": "x",
  "title": "Historic Vids - One of the most intense moments in history",
  "author": "Historic Vids",
  "durationSeconds": 15.56,
  "resolution": "728x720",
  "format": "mp4",
  "fileSizeBytes": 1404023,
  "billedMegabytes": 2,
  "mediaKey": "x-1790637589910654976.mp4",
  "mediaUrl": "https://api.apify.com/v2/key-value-stores/.../records/x-1790637589910654976.mp4"
}
```

The title is the account name followed by the post's text. `resolution` and `durationSeconds` are
measured on the file you receive, not copied from the page. `billedMegabytes` is the file size rounded
up to whole megabytes, where a megabyte is 1,000,000 bytes. X serves H.264 video with AAC sound, which
every player opens.

Links that don't work out are listed in the `ERRORS` record of the same key-value store, each with a
plain reason such as "This post is gone, or its video was removed." They never show up in the dataset.
If not one link could be downloaded, the run ends as Failed instead of Succeeded, so a scheduled job
or an integration notices.

### Billing

Each delivered file is charged once, for its size in megabytes rounded up: the 1.4 MB clip above
counts as 2 MB. The price per megabyte for your Apify plan is on the Pricing tab.

A link that fails, a video over your `maxMegabytes`, or one that doesn't fit the run costs nothing per
megabyte. If you set a maximum charge for the run, the actor checks it before each download and skips
a video it can't pay for rather than going over.

### Big files

One run holds files up to about 70% of its memory, so 716 MB at the default 1024 MB. A bigger video
is refused before it is downloaded, with a message that names the memory to use. A five-minute 720p
video came to 18 MB in testing, so few X videos come close.

### What it doesn't do

- **Other sites.** X only; see the links above for TikTok, Facebook and YouTube. Instagram and Vimeo
  are not supported by any of them.
- **Protected accounts, or posts you have to sign in to see.** There's no account and no cookies
  behind this.
- **t.co short links.** Open the post and paste its own x.com link instead.
- **Photos and GIF-only posts without a video stream.**
- **Spaces, broadcasts and whole profiles.** One link, one video.

### Copyright

The videos belong to the people who posted them. Download only what you own or have permission to
use, and stay within X's terms.

### FAQ

**Do I need an account, cookies or an API key?** No. The link is the whole input.

**Can I send lots of links in one run?** Yes. They are downloaded one after another, and a short clip
takes 5 to 10 seconds. The default run timeout is 30 minutes, so give a very big batch more.

**Will a smaller memory setting save money?** No. It doesn't change the price, and at 512 MB the same
batch took about 75% longer in testing.

**Where are the files?** In the run's key-value store. `mediaUrl` in each row is a direct link, and
`mediaKey` is the key if you'd rather fetch it through the API. How long the store is kept depends on
your Apify plan, so download what you need.

# Actor input Schema

## `urls` (type: `array`):

One link per line, each to an X post with a video in it (x.com/name/status/...); twitter.com links work the same. A post holding several videos gives the first one; end the link with /video/2 for the second. Links from other sites are refused, with a pointer to the downloader that takes them.

## `quality` (type: `string`):

Measured on the short side of the picture, so 1080 means 1920x1080 for a landscape video and 1080x1920 for a vertical one. If a video doesn't come in that quality you get the closest one it has. You pay per megabyte, so a higher quality costs more.

## `audioOnly` (type: `boolean`):

Save just the video's sound, as a 128 kbit/s MP3, instead of the video.

## `maxMegabytes` (type: `integer`):

A video bigger than this is skipped before it is downloaded, and you are not charged for it. One run can hold files up to about 70% of its memory (716 MB at the default 1024 MB), so for anything bigger raise the run's memory as well.

## Actor input object example

```json
{
  "urls": [
    "https://x.com/historyinmemes/status/1790637656616943991"
  ],
  "quality": "1080",
  "audioOnly": false,
  "maxMegabytes": 500
}
```

# Actor output Schema

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

One row per delivered file: the link, title, author, duration, measured resolution, size, megabytes billed and a direct link to the file.

## `files` (type: `string`):

The MP4 and MP3 files themselves, in the run's key-value store.

## `errors` (type: `string`):

Each failed or refused link with the reason. These are not billed per megabyte.

# 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 = {
    "urls": [
        "https://x.com/historyinmemes/status/1790637656616943991"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/x-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 = { "urls": ["https://x.com/historyinmemes/status/1790637656616943991"] }

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/x-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 '{
  "urls": [
    "https://x.com/historyinmemes/status/1790637656616943991"
  ]
}' |
apify call dami_studio/x-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/x-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/fahCBE4k2h5MEKY4C/builds/zIUJq0iO81HAPzanE/openapi.json
