# Twitter Media Scraper (`maximedupre/twitter-media-scraper`) Actor

Extract public Twitter/X images, videos, and GIFs from tweet URLs, IDs, @handles, #hashtags, or keywords. Export media URLs, tweet metadata, authors, engagement, and source links.

- **URL**: https://apify.com/maximedupre/twitter-media-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 media items

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 media scraper for public X posts

Twitter Media Scraper extracts images, videos, and GIFs from public [Twitter/X](https://x.com/) posts. Paste tweet URLs, tweet IDs, `@handles`, `#hashtags`, or search keywords, then export media URLs together with tweet text, author details, engagement counts, source links, and scrape timestamps.

Use this Twitter media scraper when you need a repeatable way to collect media from X for research, content review, social listening, trend checks, reporting, archiving, or API workflows. Direct tweet targets are useful when you already know the posts. Handles, hashtags, and keywords help you discover recent public posts that contain media.

For a small first run, keep one prefilled target such as `#nasa`, leave **Media types** set to images, videos, and GIFs, and keep **Media item limit** at `25`. Once the output shape looks right, add your own targets or run the Actor on a schedule.

### ✅ What this Actor does

- Extracts media from public Twitter/X tweet URLs and raw tweet IDs.
- Discovers recent public media posts from `@handles`, `#hashtags`, and keywords.
- Saves one dataset row per extracted image, video, or GIF media asset.
- Includes tweet IDs, tweet URLs, author usernames, display names, post text, timestamps, media URLs, thumbnails, media indexes, and scrape timestamps.
- Adds public engagement counts such as likes, retweets, replies, and views when X exposes them.
- Lets you choose images only, videos only, GIFs only, or any combination.
- Stops at your media item limit so run size and spend stay predictable.
- Runs without a Twitter/X login, cookies, or a user-provided API key.

This Actor is focused on public media extraction. It does not fetch private, protected, deleted, login-only, or account-restricted content.

### 📊 Data you can export

Each output row represents one media asset from one public Twitter/X post. Core fields include:

- `target` - the input value that produced the row.
- `targetType` - `tweet`, `profile`, `hashtag`, or `keyword`.
- `tweetId` and `tweetUrl` - the source post identity.
- `authorUsername` and `authorName` - public author fields when available.
- `text` and `postedAt` - tweet text and timestamp when available.
- `mediaType` - `image`, `video`, or `gif`.
- `mediaUrl`, `thumbnailUrl`, `mediaIndex`, and `rawMediaId` - media-specific fields.
- `engagement` - likes, retweets, replies, and views when available.
- `sourceUrl`, `canonicalTweetUrl`, and `scrapedAt` - traceability fields for exports and API use.

You can open the dataset in Apify, export it as JSON, CSV, Excel, XML, RSS, or HTML, call it through the Apify API, schedule recurring runs, or connect it to webhooks and integrations.

### 🚀 How to run

1. Add one or more public Twitter/X targets in **Targets**.
2. Use tweet URLs, tweet IDs, `@handles`, `#hashtags`, or plain search keywords.
3. Keep **Media item limit** small for the first run, then raise it when the result shape fits your workflow.
4. Choose **Media types** to include images, videos, GIFs, or a subset.
5. Start the Actor and open the dataset.
6. Use `mediaUrl` for the direct media link and `tweetUrl` or `canonicalTweetUrl` to trace the media back to X.

Example input:

```json
{
	"targets": [
		"#nasa",
		"@NASA",
		"https://x.com/teslaownersSV/status/2004891561180758165"
	],
	"maxItems": 25,
	"mediaTypes": ["image", "video", "gif"]
}
````

### 📄 Output example

```json
{
	"target": "#nasa",
	"targetType": "hashtag",
	"tweetId": "2061497874714632614",
	"tweetUrl": "https://x.com/Astro_Postcard/status/2061497874714632614",
	"authorUsername": "Astro_Postcard",
	"authorName": "Astro Postcard",
	"text": "Astronomy Picture of the Day (2026-06-01)",
	"postedAt": "2026-06-01T17:19:28.000Z",
	"mediaType": "image",
	"mediaUrl": "https://pbs.twimg.com/media/HJvpZJ8WwAAbybh.jpg",
	"mediaIndex": 1,
	"thumbnailUrl": "https://pbs.twimg.com/media/HJvpZJ8WwAAbybh.jpg",
	"altText": null,
	"engagement": {
		"likes": 0,
		"retweets": 0,
		"replies": 0,
		"views": 2
	},
	"sourceUrl": "https://x.com/Astro_Postcard/status/2061497874714632614",
	"canonicalTweetUrl": "https://x.com/Astro_Postcard/status/2061497874714632614",
	"rawMediaId": null,
	"scrapedAt": "2026-06-01T17:40:35.551Z"
}
```

### 🎯 Input tips

Use direct tweet URLs or tweet IDs when you need media from known posts. Use `@handles` when you want recent public media posts from a profile. Use `#hashtags` or keywords when you want media around a topic, campaign, brand, event, or trend.

The Actor only emits rows when media is found. If a target has no public image, video, or GIF media, it is skipped and the run continues.

### 💸 Pricing

This Actor uses pay-per-event pricing. You are charged for each image, video, or GIF media item that is found and saved. Targets that are skipped because no public media is available do not create media-item events.

The default limit of `25` media items keeps first runs small. Increase **Media item limit** when you are ready to collect more.

### ⚖️ Limits and caveats

Twitter/X may hide, remove, rate-limit, or change access to public content. When a field is not exposed for a post, the Actor leaves that field empty and still saves the media item when a usable media URL is available.

The Actor does not bypass privacy controls. Protected accounts, private posts, deleted posts, login-only content, bookmarks, likes, followers, following lists, private messages, and account-only media are outside this Actor's scope.

### ❓ FAQ

#### 🔒 Can I scrape private Twitter/X media?

No. This Actor is for public Twitter/X media only. It does not fetch protected posts, private account content, private messages, or media that requires access to a specific user account.

#### 🔑 Do I need Twitter cookies or an API key?

No. You do not need to provide Twitter/X cookies, a login, or an API key.

#### 🔎 Can I search by hashtag or profile?

Yes. Add a `#hashtag`, an `@handle`, or a keyword in **Targets**. The Actor discovers recent public posts with media and emits one row per media asset.

#### 💾 Does it download files into Apify storage?

No. The Actor returns media URLs and thumbnails in the dataset. Use the exported URLs in your own downloader, API workflow, or storage pipeline if you need to save the files elsewhere.

### 📝 Changelog

- 0.1: Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~twitter-media-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Other actors

- [Twitter Scraper ↗](https://apify.com/maximedupre/twitter-scraper) - Search public X posts and trending topics.
- [Twitter Screenshot Generator ↗](https://apify.com/maximedupre/twitter-screenshot-generator) - Save clean screenshots of public X posts.
- [Facebook Media Downloader ↗](https://apify.com/maximedupre/facebook-media-downloader) - Extract public Facebook video and reel media links.
- [Instagram Downloader API ↗](https://apify.com/maximedupre/instagram-downloader-api) - Export media URLs from public Instagram posts and reels.
- [TikTok Video Downloader ↗](https://apify.com/maximedupre/tiktok-video-downloader) - Download public TikTok video or audio media files.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `targets` (type: `array`):

Paste public X/Twitter tweet URLs, raw tweet IDs, @handles, #hashtags, or search keywords. Use tweet URLs or IDs when you already know the posts; use handles, hashtags, or keywords to discover recent public posts with media.

## `maxItems` (type: `integer`):

Maximum number of image, video, and GIF media assets to save across the whole run.

## `mediaTypes` (type: `array`):

Choose whether to keep images, videos, GIFs, or any combination of those media types.

## Actor input object example

```json
{
  "targets": [
    "#nasa",
    "@NASA",
    "https://x.com/teslaownersSV/status/2004891561180758165"
  ],
  "maxItems": 25,
  "mediaTypes": [
    "image",
    "video",
    "gif"
  ]
}
```

# Actor output Schema

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

One row per extracted image, video, or GIF media asset.

# 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 = {
    "targets": [
        "#nasa",
        "@NASA",
        "https://x.com/teslaownersSV/status/2004891561180758165"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/twitter-media-scraper").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 = { "targets": [
        "#nasa",
        "@NASA",
        "https://x.com/teslaownersSV/status/2004891561180758165",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/twitter-media-scraper").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 '{
  "targets": [
    "#nasa",
    "@NASA",
    "https://x.com/teslaownersSV/status/2004891561180758165"
  ]
}' |
apify call maximedupre/twitter-media-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Twitter Media Scraper",
        "description": "Extract public Twitter/X images, videos, and GIFs from tweet URLs, IDs, @handles, #hashtags, or keywords. Export media URLs, tweet metadata, authors, engagement, and source links.",
        "version": "0.1",
        "x-build-id": "YxFOwkSLl0eeQzU2K"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/maximedupre~twitter-media-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-maximedupre-twitter-media-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/maximedupre~twitter-media-scraper/runs": {
            "post": {
                "operationId": "runs-sync-maximedupre-twitter-media-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/maximedupre~twitter-media-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-maximedupre-twitter-media-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "targets"
                ],
                "properties": {
                    "targets": {
                        "title": "Tweet URLs, IDs, handles, hashtags, or keywords",
                        "minItems": 1,
                        "maxItems": 500,
                        "type": "array",
                        "description": "Paste public X/Twitter tweet URLs, raw tweet IDs, @handles, #hashtags, or search keywords. Use tweet URLs or IDs when you already know the posts; use handles, hashtags, or keywords to discover recent public posts with media.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "maxItems": {
                        "title": "Media item limit",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of image, video, and GIF media assets to save across the whole run.",
                        "default": 25
                    },
                    "mediaTypes": {
                        "title": "Media types",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose whether to keep images, videos, GIFs, or any combination of those media types.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "image",
                                "video",
                                "gif"
                            ],
                            "enumTitles": [
                                "Images",
                                "Videos",
                                "GIFs"
                            ]
                        },
                        "default": [
                            "image",
                            "video",
                            "gif"
                        ]
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
