# Reddit Media Downloader (`maximedupre/reddit-media-downloader`) Actor

Get source-hosted video, image, GIF, gallery, and external-media links from public Reddit URLs. Choose media types and return available media details and post context without storing the files.

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

## Pricing

from $1.75 / 1,000 media links

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?

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

### 🎬 Turn Reddit media URLs into ready-to-use links

Built for developers, researchers, and content teams, this Actor takes public Reddit post URLs, profile-post URLs, or direct Reddit media URLs and returns source-hosted links for video, image, GIF, gallery, and available external media. It also returns media details and basic post context, so you can open or download the source without storing the files here.

- Get media links from public Reddit sources with **[Reddit Downloader](https://apify.com/maximedupre/reddit-media-downloader/examples/reddit-downloader)**.
- Get a direct video link from a post with **[Reddit Video Downloader Bot](https://apify.com/maximedupre/reddit-media-downloader/examples/reddit-video-downloader-bot)**.
- Get a photo link from a public Reddit source with **[Reddit Photo Downloader](https://apify.com/maximedupre/reddit-media-downloader/examples/reddit-photo-downloader)**.
- Save a GIF link from a public Reddit source with **[Download Reddit GIF](https://apify.com/maximedupre/reddit-media-downloader/examples/download-reddit-gif)**.
- Open a video source URL with **[Reddit Video Link](https://apify.com/maximedupre/reddit-media-downloader/examples/reddit-video-link)**.

#### 📦 Reddit media results

Each successful dataset row contains one media link. It can include the submitted URL, a main download URL, media type, source host, format, dimensions, duration, quality, codec, bitrate, frame rate, file size, thumbnail, post context, classification, gallery position, external provider details, and video streams. The output also has an `errors` field for submitted sources that could not be found or loaded.

**What the rows give you**

The Actor returns source-hosted URLs. It does not download, mirror, or store the media files. A gallery item gets its own row, and a video can include several video variants, separate audio streams, and subtitle streams when the source provides them.

#### ▶️ Run from a URL list

Choose the target that matches every URL in the run. Add one or more public Reddit URLs, select the media types to return, and decide whether post targets may include external media. You can also set a media result limit. Start the run, then open the dataset link in the output.

**Run steps**

1. Set `target` to `postUrls`, `profilePostUrls`, or `mediaUrls`.
2. Add one or more public URLs under `sourceUrls`.
3. Choose `mediaTypes` and, for post or profile-post targets, whether to include external media.
4. Optionally set `maxItems`, then run the Actor.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `target` | string | Chooses the URL kind for this run: `postUrls`, `profilePostUrls`, or `mediaUrls`. Every source URL must match it. |
| `sourceUrls` | array of objects | Adds one or more public Reddit URL objects to process. |
| `sourceUrls[].url` | string | The public Reddit post, profile-post, or direct media URL to process. |
| `mediaTypes` | array of strings | Chooses `video`, `image`, `gif`, or `gallery` media. If you omit it, the Actor returns all four types when they are available. |
| `includeExternalMedia` | boolean | For post and profile-post URLs, includes usable links and provider details for media hosted outside Reddit when set to `true`. It has no effect for direct Reddit media URLs. If `false` or omitted, only Reddit-hosted media is returned. |
| `maxItems` | integer | Optionally stops after this many media results. Leave it empty to return all available results until the sources are exhausted. |

**Input example**

This is the public input from a successful current-beta run using the default example URL.

```json
{
  "target": "postUrls",
  "sourceUrls": [
    {
      "url": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/"
    }
  ],
  "mediaTypes": [
    "video",
    "image",
    "gif",
    "gallery"
  ],
  "includeExternalMedia": false,
  "maxItems": 10
}
```

#### 🧾 Output

**Run output**

| Field | Type | What it does |
| --- | --- | --- |
| `dataset` | string | Links to the dataset with successful source-hosted media links. |
| `errors` | string | Contains a JSON list of submitted sources that could not be found or loaded. Those sources are not in the dataset. |

**Complete dataset fields**

Every successful dataset row uses this field set. Nested fields use dotted paths in the table, while JSON examples keep their real nested objects.

| Field | Type | What it does |
| --- | --- | --- |
| `sourceUrl` | string | The submitted public URL that led to this media link. |
| `downloadUrl` | string | The main source-hosted URL for opening or downloading the media. |
| `mediaType` | string | The media category: `video`, `image`, `gif`, `gallery`, or `external`. |
| `format` | string | The available file format, such as `mp4`, `jpeg`, or `gif`, when provided. |
| `dimensions` | object | Groups the media width and height in pixels, when available. |
| `dimensions.width` | integer | Media width in pixels, when available. |
| `dimensions.height` | integer | Media height in pixels, when available. |
| `durationSeconds` | number | Media duration in seconds, when available. |
| `quality` | string | The source quality label, when available. |
| `codec` | string | The media codec, when available. |
| `bitrateKbps` | number | Media bitrate in kilobits per second, when available. |
| `frameRateFps` | number | Video frame rate in frames per second, when available. |
| `fileSizeBytes` | integer | Media file size in bytes when the source provides it. |
| `thumbnailUrl` | string | A preview image URL for the media, when available. |
| `sourceHost` | string | The host that serves the main media URL. |
| `post` | object | Groups available context for the Reddit post linked to the media. |
| `post.title` | string | The Reddit post title, when post context is available. |
| `post.author` | string | The Reddit account that made the post, when available. |
| `post.subreddit` | string | The subreddit where the post was published, when available. |
| `post.permalink` | string | The canonical Reddit URL for the post, when available. |
| `post.createdAt` | string | The post creation time, when available. |
| `post.score` | integer | The Reddit post score, when available. |
| `post.commentCount` | integer | The number of comments on the post, when available. |
| `post.thumbnailUrl` | string | A thumbnail URL supplied for the post, when available. |
| `classification` | object | Groups post and media labels supplied by the source. |
| `classification.isNsfw` | boolean | Whether the source marks the post as not safe for work. |
| `classification.isSpoiler` | boolean | Whether the source marks the post as a spoiler. |
| `classification.flair` | string | The Reddit post flair, when available. |
| `gallery` | object | Groups the position of a result in a Reddit gallery. |
| `gallery.itemIndex` | integer | The one-based position of this item in a gallery, when available. |
| `gallery.itemCount` | integer | The number of items in the gallery, when available. |
| `external` | object | Groups provider details for media hosted outside Reddit. |
| `external.provider` | string | The external media provider name, when available. |
| `external.pageUrl` | string | A public provider page for the external media, when available. |
| `video` | object | Groups video renditions and related streams. |
| `video.variants` | array of objects | Available progressive or adaptive video renditions. |
| `video.variants[]` | object | One downloadable video rendition. |
| `video.variants[].url` | string | The source URL for a video rendition. |
| `video.variants[].streamType` | string | Whether the rendition is `progressive` or `adaptive`. |
| `video.variants[].quality` | string | The rendition quality label, when available. |
| `video.variants[].width` | integer | Rendition width in pixels, when available. |
| `video.variants[].height` | integer | Rendition height in pixels, when available. |
| `video.variants[].format` | string | Rendition file format, when available. |
| `video.variants[].codec` | string | Rendition codec, when available. |
| `video.variants[].bitrateKbps` | number | Rendition bitrate in kilobits per second, when available. |
| `video.variants[].frameRateFps` | number | Rendition frame rate in frames per second, when available. |
| `video.audioStreams` | array of objects | Separate source audio files for a video, when available. |
| `video.audioStreams[]` | object | One downloadable audio stream. |
| `video.audioStreams[].url` | string | The source URL for an audio stream. |
| `video.audioStreams[].format` | string | Audio file format, when available. |
| `video.audioStreams[].codec` | string | Audio codec, when available. |
| `video.audioStreams[].bitrateKbps` | number | Audio bitrate in kilobits per second, when available. |
| `video.audioStreams[].sampleRateHz` | integer | Audio sample rate in hertz, when available. |
| `video.audioStreams[].channels` | integer | Number of audio channels, when available. |
| `video.audioStreams[].language` | string | Audio language, when available. |
| `video.subtitleStreams` | array of objects | Separate source subtitle or caption files for a video, when available. |
| `video.subtitleStreams[]` | object | One downloadable subtitle stream. |
| `video.subtitleStreams[].url` | string | The source URL for a subtitle stream. |
| `video.subtitleStreams[].language` | string | Subtitle language, when available. |
| `video.subtitleStreams[].format` | string | Subtitle file format, when available. |
| `video.subtitleStreams[].label` | string | The source label for a subtitle stream, when available. |

**Genuine default-input row**

```json
{
  "post": {
    "title": "14 Years Young. A little older, a little wiser but still a puppy at heart. Say hi to Sevo",
    "author": "vahep",
    "subreddit": "aww",
    "permalink": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/",
    "createdAt": "2018-11-14T23:50:54.000Z",
    "score": 6848,
    "commentCount": 43,
    "thumbnailUrl": "https://b.thumbs.redditmedia.com/I6vqj_81jDnFc5Sr2AadJGcOQAxlELyTaIGw6SVAuQs.jpg"
  },
  "classification": {
    "isNsfw": false,
    "isSpoiler": false
  },
  "thumbnailUrl": "https://b.thumbs.redditmedia.com/I6vqj_81jDnFc5Sr2AadJGcOQAxlELyTaIGw6SVAuQs.jpg",
  "sourceUrl": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/",
  "downloadUrl": "https://i.redd.it/quq0aq26wdy11.jpg",
  "mediaType": "image",
  "format": "jpeg",
  "dimensions": {
    "width": 1768,
    "height": 2048
  },
  "fileSizeBytes": 501569,
  "sourceHost": "i.redd.it"
}
```

**Direct media fields**

Direct image and GIF URLs return the common media fields below. Optional fields appear when the source provides them.

| Field | Type | What it does |
| --- | --- | --- |
| `sourceUrl` | string | The direct Reddit media URL submitted for the run. |
| `downloadUrl` | string | The source-hosted URL for opening or downloading the media. |
| `mediaType` | string | Identifies the media as `image` or `gif` in these examples. |
| `format` | string | Identifies the file format. |
| `dimensions.width` and `dimensions.height` | integers | Give the media size in pixels when available. |
| `fileSizeBytes` | integer | Gives the file size when the source provides it. |
| `sourceHost` | string | Names the host serving the media URL. |

```json
{
  "sourceUrl": "https://i.redd.it/tse4kv1cb7hh1.gif",
  "downloadUrl": "https://i.redd.it/tse4kv1cb7hh1.gif",
  "mediaType": "gif",
  "format": "gif",
  "fileSizeBytes": 765681,
  "sourceHost": "i.redd.it"
}
```

**Post context fields**

Post and profile-post URLs can add the `post` and `classification` objects to a media row. The complete nested field definitions are in the dataset table above.

| Field | Type | What it does |
| --- | --- | --- |
| `post` | object | Groups the Reddit title, author, subreddit, permalink, creation time, score, comment count, and post thumbnail. |
| `classification` | object | Groups NSFW, spoiler, and flair labels supplied by the source. |
| `thumbnailUrl` | string | Gives a preview image for the media when available. |

```json
{
  "post": {
    "title": "14 Years Young. A little older, a little wiser but still a puppy at heart. Say hi to Sevo",
    "author": "vahep",
    "subreddit": "aww",
    "permalink": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/",
    "createdAt": "2018-11-14T23:50:54.000Z",
    "score": 6848,
    "commentCount": 43,
    "thumbnailUrl": "https://b.thumbs.redditmedia.com/I6vqj_81jDnFc5Sr2AadJGcOQAxlELyTaIGw6SVAuQs.jpg"
  },
  "classification": {
    "isNsfw": false,
    "isSpoiler": false
  },
  "thumbnailUrl": "https://b.thumbs.redditmedia.com/I6vqj_81jDnFc5Sr2AadJGcOQAxlELyTaIGw6SVAuQs.jpg",
  "sourceUrl": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/",
  "downloadUrl": "https://i.redd.it/quq0aq26wdy11.jpg",
  "mediaType": "image",
  "format": "jpeg",
  "dimensions": {
    "width": 1768,
    "height": 2048
  },
  "fileSizeBytes": 501569,
  "sourceHost": "i.redd.it"
}
```

**Gallery fields**

Gallery media uses the common media fields plus the position of the saved item in the source gallery.

| Field | Type | What it does |
| --- | --- | --- |
| `gallery.itemIndex` | integer | Gives the one-based position of this gallery item. |
| `gallery.itemCount` | integer | Gives the number of items in the gallery. |

```json
{
  "post": {
    "title": "I found an awesome print and I cannot read the signature!",
    "author": "mehhgb",
    "subreddit": "Whatisthis",
    "permalink": "https://www.reddit.com/r/Whatisthis/comments/1g95lsd/i_found_an_awesome_print_and_i_cannot_read_the/",
    "createdAt": "2024-10-22T00:41:54.000Z",
    "score": 2,
    "commentCount": 1,
    "thumbnailUrl": "https://b.thumbs.redditmedia.com/ehVlWb-ee2qFWFp1CvlIASzoU2_-msPLuPlnevV3RUg.jpg"
  },
  "classification": {
    "isNsfw": false,
    "isSpoiler": false,
    "flair": "Open"
  },
  "thumbnailUrl": "https://b.thumbs.redditmedia.com/ehVlWb-ee2qFWFp1CvlIASzoU2_-msPLuPlnevV3RUg.jpg",
  "sourceUrl": "https://www.reddit.com/r/Whatisthis/comments/1g95lsd/i_found_an_awesome_print_and_i_cannot_read_the/",
  "downloadUrl": "https://i.redd.it/ml29wpa2f7wd1.jpg",
  "mediaType": "gallery",
  "format": "jpeg",
  "dimensions": {
    "width": 2798,
    "height": 1730
  },
  "fileSizeBytes": 416241,
  "sourceHost": "i.redd.it",
  "gallery": {
    "itemIndex": 1,
    "itemCount": 2
  }
}
```

**External media fields**

When external media is included for a post or profile-post target, the row can include the provider name and its public page URL.

| Field | Type | What it does |
| --- | --- | --- |
| `external.provider` | string | Names the external media provider. |
| `external.pageUrl` | string | Links to the public provider page for the media. |

```json
{
  "post": {
    "title": "Blanche now meeting Epstein survivors while trying to get confirmed is 'insulting': Oversight Rep.",
    "author": "AdSpecialist6598",
    "subreddit": "videos",
    "permalink": "https://www.reddit.com/r/videos/comments/1uz8vst/blanche_now_meeting_epstein_survivors_while/",
    "createdAt": "2026-07-17T19:01:36.000Z",
    "score": 874,
    "commentCount": 24,
    "thumbnailUrl": "https://external-preview.redd.it/lYJyOpM_ziu6qiYbXyzDug7iU7merYRJ2aUZWCw1uNM.jpeg?width=140&height=105&auto=webp&s=4a693618346467d90d2432c584b84e4c3d41aa14"
  },
  "classification": {
    "isNsfw": false,
    "isSpoiler": false
  },
  "thumbnailUrl": "https://external-preview.redd.it/lYJyOpM_ziu6qiYbXyzDug7iU7merYRJ2aUZWCw1uNM.jpeg?width=140&height=105&auto=webp&s=4a693618346467d90d2432c584b84e4c3d41aa14",
  "sourceUrl": "https://www.reddit.com/r/videos/comments/1uz8vst/blanche_now_meeting_epstein_survivors_while/",
  "downloadUrl": "https://www.youtube.com/watch?v=AMGdYH9IIGY&pp=ygUGbXMgbm93",
  "mediaType": "external",
  "sourceHost": "www.youtube.com",
  "external": {
    "provider": "www.youtube.com",
    "pageUrl": "https://www.youtube.com/watch?v=AMGdYH9IIGY&pp=ygUGbXMgbm93"
  }
}
```

**Video stream fields**

Video rows can include the main media details plus progressive or adaptive variants, separate audio, and subtitle streams.

| Field | Type | What it does |
| --- | --- | --- |
| `video.variants` | array of objects | Lists available video renditions. |
| `video.variants[].url` | string | Links to one video rendition. |
| `video.variants[].streamType` | string | Shows `progressive` or `adaptive`. |
| `video.variants[].quality` | string | Gives the rendition quality label. |
| `video.variants[].width` and `video.variants[].height` | integers | Give the rendition size in pixels. |
| `video.variants[].format` | string | Gives the rendition file format. |
| `video.variants[].codec` | string | Gives the rendition codec when available. |
| `video.variants[].bitrateKbps` | number | Gives the rendition bitrate when available. |
| `video.variants[].frameRateFps` | number | Gives the rendition frame rate when available. |
| `video.audioStreams` | array of objects | Lists separate audio files when available. |
| `video.audioStreams[].url` | string | Links to one audio stream. |
| `video.audioStreams[].format` | string | Gives the audio format when available. |
| `video.audioStreams[].codec` | string | Gives the audio codec when available. |
| `video.audioStreams[].bitrateKbps` | number | Gives the audio bitrate when available. |
| `video.audioStreams[].sampleRateHz` | integer | Gives the audio sample rate when available. |
| `video.audioStreams[].channels` | integer | Gives the number of audio channels when available. |
| `video.audioStreams[].language` | string | Gives the audio language when available. |
| `video.subtitleStreams` | array of objects | Lists subtitle or caption files when available. |
| `video.subtitleStreams[].url` | string | Links to one subtitle stream. |
| `video.subtitleStreams[].language` | string | Gives the subtitle language when available. |
| `video.subtitleStreams[].format` | string | Gives the subtitle format when available. |
| `video.subtitleStreams[].label` | string | Gives the source label when available. |

```json
{
  "sourceUrl": "https://v.redd.it/u5pu7ad5rcdh1",
  "downloadUrl": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_720.mp4",
  "mediaType": "video",
  "format": "mp4",
  "dimensions": {
    "width": 720,
    "height": 1280
  },
  "durationSeconds": 13,
  "quality": "1280p",
  "codec": "avc1.4d401f",
  "bitrateKbps": 2083.898,
  "frameRateFps": 30,
  "fileSizeBytes": 3260125,
  "sourceHost": "v.redd.it",
  "video": {
    "variants": [
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_220.mp4",
        "streamType": "adaptive",
        "quality": "392p",
        "height": 392,
        "width": 220,
        "format": "mp4",
        "codec": "avc1.4d401e",
        "bitrateKbps": 184.218,
        "frameRateFps": 30
      },
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_270.mp4",
        "streamType": "adaptive",
        "quality": "480p",
        "height": 480,
        "width": 270,
        "format": "mp4",
        "codec": "avc1.4d401e",
        "bitrateKbps": 359.506,
        "frameRateFps": 30
      },
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_360.mp4",
        "streamType": "adaptive",
        "quality": "640p",
        "height": 640,
        "width": 360,
        "format": "mp4",
        "codec": "avc1.4d401e",
        "bitrateKbps": 763.1,
        "frameRateFps": 30
      },
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_480.mp4",
        "streamType": "adaptive",
        "quality": "854p",
        "height": 854,
        "width": 480,
        "format": "mp4",
        "codec": "avc1.4d401f",
        "bitrateKbps": 1097.942,
        "frameRateFps": 30
      },
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_720.mp4",
        "streamType": "adaptive",
        "quality": "1280p",
        "height": 1280,
        "width": 720,
        "format": "mp4",
        "codec": "avc1.4d401f",
        "bitrateKbps": 2083.898,
        "frameRateFps": 30
      }
    ],
    "audioStreams": [
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_AUDIO_64.mp4",
        "format": "mp4",
        "codec": "mp4a.40.2",
        "bitrateKbps": 66.1,
        "sampleRateHz": 48000,
        "channels": 2
      },
      {
        "url": "https://v.redd.it/u5pu7ad5rcdh1/CMAF_AUDIO_128.mp4",
        "format": "mp4",
        "codec": "mp4a.40.2",
        "bitrateKbps": 129.825,
        "sampleRateHz": 48000,
        "channels": 2
      }
    ],
    "subtitleStreams": []
  }
}
```

#### 💳 Pricing

This Actor uses pay-per-event pricing. Each successful media link saved to the dataset uses one charged event. Check the Apify Console for the current price for your account and tier.

**Charged event**

| Event | What it covers |
| --- | --- |
| `Media link` | One successful source-hosted media link with available details is saved. |

#### 🔌 Integrations

Use the Apify API to start runs, read dataset results, and connect this Actor to your own workflow. You can also use Apify schedules and webhooks for repeat runs and follow-up actions.

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### What can I submit?

Set `target` to match the URLs you submit. You can use public Reddit post URLs, profile-post URLs, or direct Reddit media URLs.

##### Can I use a profile-post URL?

Yes. Set `target` to `profilePostUrls` and add public profile-post URLs under `sourceUrls`.

##### Can I use a direct Reddit media URL?

Yes. Set `target` to `mediaUrls` for a direct URL from a Reddit media host. The row can contain media details without post context.

##### How do I include media hosted outside Reddit?

Set `includeExternalMedia` to `true` for post or profile-post targets. This option has no effect for direct Reddit media URLs. When it is off, the Actor returns Reddit-hosted media only.

##### How are gallery posts returned?

Each available gallery item is saved as its own media row. Use `gallery.itemIndex` and `gallery.itemCount` to place it in the source gallery.

##### Do video rows include sound and subtitles?

When the source provides them, a video row can include several video variants, separate audio streams, and subtitle or caption streams.

##### What happens when a source cannot be loaded?

The source is listed in the `errors` output field instead of being added as a successful dataset row.

##### How does `maxItems` work?

It stops the run after the chosen number of media results. Leave it empty to return all available results until the sources are exhausted.

##### Do I need a Reddit login?

No. The Actor processes publicly accessible Reddit sources without requiring a Reddit login.

##### Does this Actor download the media files?

No. It returns source-hosted URLs that you can open or download. It does not mirror or store the media files.

### 📝 Changelog

**0.0: Initial release**

### 🆘 Support

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

### 🔗 Related Actors

- [Reddit Scraper](https://apify.com/maximedupre/reddit-scraper) - Collect broader public Reddit posts, comments, communities, and user data when media links are part of a wider Reddit dataset.
- [Reddit Post Media Downloader](https://apify.com/scrapearchitect/reddit-post-media-downloader) - Inspect individual subreddit or profile posts for direct media links, audio, and quality options.
- [Reddit Media & Images Scraper (Video, GIF, Gallery)](https://apify.com/scrapers_lat/reddit-media-scraper) - Collect media from subreddit or post pages when you need discovery beyond submitted URLs.
- [Reddit Media Downloader](https://apify.com/khadinakbar/reddit-media-downloader) - Get Reddit-hosted image, gallery, GIF, and video or audio links from public post URLs.
- [Reddit Media Search Scraper](https://apify.com/easyapi/reddit-media-search-scraper) - Find media posts by keyword before sending exact URLs to a URL-based downloader.

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

# Actor input Schema

## `target` (type: `string`):

Choose the type of URL in this run. Every source URL must match this choice.

## `sourceUrls` (type: `array`):

Add one or more public URLs that match the selected URL type. Use a Reddit post URL, profile-post URL, or direct Reddit media URL.

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

Choose the media types to return. If you omit this field, the Actor returns video, image, GIF, and gallery media when available.

## `includeExternalMedia` (type: `boolean`):

For post and profile-post URLs, set this to true to include usable links and provider details for media hosted outside Reddit. It has no effect for direct Reddit media URLs. If false or omitted, return Reddit-hosted media only.

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

Optionally stop after this many media results. Leave it empty to return all available results until the sources are exhausted.

## Actor input object example

```json
{
  "target": "postUrls",
  "sourceUrls": [
    {
      "url": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/"
    }
  ],
  "mediaTypes": [
    "video",
    "image",
    "gif",
    "gallery"
  ],
  "includeExternalMedia": false,
  "maxItems": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Open the dataset with successful source-hosted media links.

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

A JSON list of submitted sources that could not be found or loaded. These sources are not in the media dataset.

# 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 = {
    "target": "postUrls",
    "sourceUrls": [
        {
            "url": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/"
        }
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/reddit-media-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 = {
    "target": "postUrls",
    "sourceUrls": [{ "url": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/" }],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/reddit-media-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 '{
  "target": "postUrls",
  "sourceUrls": [
    {
      "url": "https://www.reddit.com/r/aww/comments/9x5mvy/14_years_young_a_little_older_a_little_wiser_but/"
    }
  ],
  "maxItems": 10
}' |
apify call maximedupre/reddit-media-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/reddit-media-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/Rw8qZz7jtALRkszXv/builds/nyvS6o9qRYW8IAn2K/openapi.json
