Twitter Video Downloader avatar

Twitter Video Downloader

Pricing

from $5.00 / 1,000 results

Go to Apify Store
Twitter Video Downloader

Twitter Video Downloader

Download videos from Twitter/X posts. Supports direct post URLs and username-based scraping.

Pricing

from $5.00 / 1,000 results

Rating

5.0

(5)

Developer

Crawler Bros

Crawler Bros

Maintained by Community

Actor stats

2

Bookmarked

13

Total users

5

Monthly active users

8 days ago

Last modified

Share

Twitter/X Media Downloader

Download videos, photos, and GIFs from any public Twitter/X post — no login required.

Just paste the post link, hit run, and get your files with direct download links. You can also provide a username to automatically collect media from their recent posts.


What Can This Tool Do?

  • Download videos from any public tweet (including quoted tweets and CMAF/fMP4 streaming videos)
  • Download photos in original quality (PNG/JPG)
  • Download GIFs as MP4 files
  • Scrape by username — automatically find and download media from a user's recent posts
  • Detect retweets and quote tweets — correctly attributes media to the original author
  • Get media details — resolution, duration, file size, codec, bitrate, and more
  • Cloud storage — every file is uploaded and given a direct download link that works anywhere

Getting Started

Option 1: Download from specific posts

Paste one or more tweet/post URLs:

{
"postUrls": [
"https://x.com/NASA/status/123456789",
"https://x.com/SpaceX/status/987654321"
]
}

Option 2: Download from a user's profile

Provide usernames (without the @) and the tool will find their recent posts with media:

{
"usernames": ["NASA", "SpaceX"],
"maxPostsPerUser": 10
}

You can also combine both — provide post URLs and usernames at the same time.


Input Settings

SettingWhat it doesDefault
Post URLsList of tweet URLs to download media fromEmpty
UsernamesList of Twitter usernames to scrape (without @)Empty
Max Posts Per UserHow many recent posts to check per username (1-100)10
Browser CookiesYour Twitter cookies in JSON format (optional — built-in defaults are used if not provided)Not set

What You Get Back

Every downloaded file produces a result like this:

Video example

{
"tweet_url": "https://x.com/username/status/123456789",
"tweet_id": "123456789",
"scraped_from": "username",
"uploader": "username",
"is_retweet": false,
"is_quote_tweet": false,
"media_origin": "self",
"media_type": "video",
"filename": "123456789_video_1.mp4",
"filesize_bytes": 28640256,
"storage_key": "123456789_video_1.mp4",
"download_url": "https://api.apify.com/v2/key-value-stores/{STORE_ID}/records/123456789_video_1.mp4",
"download_status": "finished",
"downloaded_at": "2026-03-06T08:15:44.708281",
"media_stats": {
"width": 1920,
"height": 1080,
"fps": 30.0,
"duration": 45.23,
"video_codec": "h264",
"ext": "mp4",
"filesize_bytes": 28640256,
"total_bitrate_kbps": 5064.12,
"aspect_ratio": 1.78
}
}

Photo example

{
"tweet_url": "https://x.com/username/status/123456789",
"tweet_id": "123456789",
"scraped_from": null,
"uploader": "username",
"is_retweet": false,
"is_quote_tweet": false,
"media_origin": "self",
"media_type": "photo",
"filename": "123456789_photo_1.png",
"filesize_bytes": 29387,
"storage_key": "123456789_photo_1.png",
"download_url": "https://api.apify.com/v2/key-value-stores/{STORE_ID}/records/123456789_photo_1.png",
"download_status": "finished",
"downloaded_at": "2026-03-06T08:15:44.708281",
"media_stats": {
"width": 1200,
"height": 675,
"ext": "png",
"filesize_bytes": 29387,
"aspect_ratio": 1.78
}
}

Output fields explained

FieldWhat it means
tweet_urlThe original post URL you provided
tweet_idThe numeric ID of the tweet
scraped_fromThe username whose profile this post was scraped from (null if provided as a direct URL)
uploaderThe Twitter username of whoever posted the media
is_retweettrue if the post is a retweet of someone else's content
is_quote_tweettrue if the post quotes another tweet
media_origin"self" = media from the tweet itself, "quoted" = media from a quoted tweet inside it
media_type"video", "photo", or "gif"
filenameName of the saved file
filesize_bytesFile size in bytes
storage_keyThe key used to store the file (use this for API access)
download_urlA direct link to download the file — works in any browser
download_status"finished" if successful, "failed" if something went wrong
errorError message (only present when download_status is "failed")
downloaded_atWhen the file was downloaded (ISO 8601 timestamp)
media_statsTechnical details about the file (resolution, duration, codec, etc.)

How It Works

The actor uses a multi-strategy approach to reliably fetch media from Twitter/X:

  1. Syndication API — First attempts to get media URLs via Twitter's public syndication endpoint (fastest, most reliable for direct video URLs)
  2. HLS/m3u8 interception — For videos delivered as CMAF/fMP4 streams (common for high-profile accounts), intercepts m3u8 manifests via Playwright network monitoring, selects the highest-quality variant, and downloads all segments (init + media segments) into a single file
  3. DOM scraping — Always extracts tweet metadata (retweet/quote detection, author attribution, image URLs) from the page DOM
  4. Network interception — Falls back to intercepting direct mp4 URLs from browser network traffic when other methods don't apply

For username-based scraping, the actor:

  • Opens the user's profile with authenticated cookies
  • Automatically switches to the "Posts" tab (avoiding Twitter's "Highlights" tab which shows old popular tweets)
  • Scrolls and collects post URLs with deduplication
  • Sorts results by tweet ID (newest first) as a safety net

Using the API

You can run this tool programmatically from your own code using the Apify API.

Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
# Start a run
run = client.actor("YOUR_ACTOR_ID").call(run_input={
"postUrls": ["https://x.com/NASA/status/123456789"]
})
# Get results
items = client.dataset(run["defaultDatasetId"]).list_items().items
for item in items:
print(f"File: {item['filename']}")
print(f"Download: {item['download_url']}")
print(f"Type: {item['media_type']}")
print()

JavaScript / Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('YOUR_ACTOR_ID').call({
postUrls: ['https://x.com/NASA/status/123456789'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
console.log(`File: ${item.filename}`);
console.log(`Download: ${item.download_url}`);
}

cURL — download a file directly

Once you have the download_url from the results, you can download the file with any tool:

$curl -o video.mp4 "https://api.apify.com/v2/key-value-stores/{STORE_ID}/records/{STORAGE_KEY}"

Where do I find my API token?

Go to Apify Console > Settings > Integrations and copy your Personal API Token.


Frequently Asked Questions

Do I need a Twitter account to use this?

No. The tool downloads media from public tweets without requiring you to log in. The actor includes built-in cookies for profile scraping. You only need to provide your own cookies if the built-in ones expire or you hit rate limits.

What media types are supported?

Videos, photos, and GIFs. The tool detects the type automatically and downloads everything it finds in a tweet. If a tweet has 3 photos and 1 video, you'll get all 4 files.

What about streaming videos (CMAF/fMP4)?

Twitter delivers some videos as fragmented MP4 streams (CMAF) using HLS m3u8 playlists instead of single MP4 files. The actor automatically detects this and downloads all segments (init + media), concatenating them into a single playable MP4 file.

What does "media_origin" mean?

  • "self" — The media belongs to the tweet you linked. This is the most common case.
  • "quoted" — The tweet you linked quotes another tweet, and this media comes from that quoted tweet.

For example, if User A quotes User B's video tweet, you'll get User B's video with media_origin: "quoted" and uploader: "UserB".

What does "scraped_from" mean?

When you use username-based scraping, scraped_from tells you which profile the post was found on. This is useful when the post is a retweet — uploader shows the original author, while scraped_from shows whose profile it appeared on. For direct post URLs, this field is null.

Does it download the best quality available?

Yes. Videos are downloaded at the highest quality Twitter provides. For HLS streams, the actor selects the highest-resolution variant. Photos are fetched at original resolution (?name=orig).

Can I download from private/protected accounts?

Not directly. The tool only works with public tweets. If you provide authenticated browser cookies, you may be able to access some restricted content, but this depends on Twitter's access controls.

How do I download media from a user's profile?

Use the Usernames input field. Enter one or more usernames (without the @), and the tool will open their profile, scroll through their recent posts, and collect all the media it finds. You can control how many posts to check with the Max Posts Per User setting (up to 100).

Why does username scraping need cookies?

When scraping by username, the tool needs to browse the profile page like a real user. Twitter may block or rate-limit unauthenticated browsing. The tool includes built-in default cookies, but for heavy usage or if the defaults expire, provide your own.

How do I get my browser cookies?

  1. Log into Twitter/X in your browser
  2. Open DevTools (F12) > Application > Cookies > https://x.com
  3. Use a browser extension like "Cookie-Editor" to export cookies as JSON
  4. Paste the JSON string into the Browser Cookies input field

What if a download fails?

Failed downloads still appear in the results with download_status: "failed" and an error field explaining what went wrong. Common reasons:

  • The tweet was deleted or made private
  • Twitter temporarily rate-limited the request
  • The media URL expired before the download completed

Is there a limit on how many posts I can process?

There's no hard limit from the tool side. However, Twitter has its own rate limits. For best results:

  • Use cookies for runs with more than ~50 posts
  • The tool automatically adds delays between requests to avoid blocks

The download_url links point to Apify's Key-Value Store and remain available as long as your Apify storage retention allows (depends on your plan — typically 7 days on the free tier, longer on paid plans).

Can I use this tool on a schedule?

Yes. On the Apify platform, you can set up scheduled runs to automatically download new media from specific users at regular intervals (daily, hourly, etc.). Go to your Actor's page and click "Schedules" to set it up.

What's the media_stats field?

It contains technical metadata extracted from the downloaded file:

StatApplies toExample
width / heightAll media1920 / 1080
fpsVideos, GIFs30.0
durationVideos, GIFs45.23 (seconds)
video_codecVideos, GIFs"h264"
extAll media"mp4", "png", "jpg"
filesize_bytesAll media28640256
total_bitrate_kbpsVideos5064.12
aspect_ratioAll media1.78

Local Development

Prerequisites

  • Python 3.12+
  • Apify CLI (npm install -g apify-cli)

Setup

  1. Navigate to the project:
$cd Twitter/twitter-video-downloader-cli
  1. Install dependencies:
pip install -r requirements.txt
playwright install chromium firefox
  1. Create input file storage/key_value_stores/default/INPUT.json:
{
"postUrls": ["https://x.com/username/status/123456"]
}
  1. Run locally:
$apify run

Local output

Results are saved in ./storage/:

  • datasets/default/ — JSON files with metadata and download links
  • key_value_stores/default/ — The actual downloaded media files

Deployment

Deploy to Apify Platform

apify login
apify push

Deploy from GitHub

  1. Go to Apify Console
  2. Click "Link Git Repository"
  3. Connect your GitHub repository
  4. Set Dockerfile path to ./Dockerfile

Support

License

This project is for educational and personal use. Respect Twitter's Terms of Service. Always ensure you have the rights to download and use the content.


Built with love by Crawler Bros