# Loom Video Downloader: MP4, Transcript & Metadata (`getascraper/loom-video-downloader`) Actor

Turn any public Loom share link into a downloadable MP4 URL, full transcript, VTT captions and rich metadata in one run. No login required. Handles share links, embed links, iframe snippets and raw video IDs.

- **URL**: https://apify.com/getascraper/loom-video-downloader.md
- **Developed by:** [GetAScraper](https://apify.com/getascraper) (community)
- **Categories:** Videos, Social media, Automation
- **Stats:** 5 total users, 1 monthly users, 97.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 video records

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

## 📹 Loom Video Downloader: MP4, transcript, metadata and change events

**Turn any public Loom link into a signed MP4 URL, a full transcript, subtitles, rich video details, and source-backed knowledge-base change events.** No login, no password, no browser extension. Paste a share link, an embed link, an embed snippet, a raw video ID, or an optional public Loom folder/page for discovery.

### 🔍 What does the Loom Video Downloader do?

The Loom Video Downloader turns a [Loom](https://www.loom.com/) link into structured data and, if you want it, the actual video file. Point it at one or more Loom videos that were shared as "anyone with the link", and for each one you get:

- A direct signed video link from Loom. Its expiry is exposed when Loom publishes it, and it is not a permanent URL.
- The full transcript, both as clean readable text and as timestamped lines
- Subtitles (VTT captions) for editors and subtitle files
- Title, description, duration, resolution, view count, owner name and avatar, and thumbnails
- An honest source status for every video: downloadable, private, download disabled, unavailable, or explicit failure, never a guess
- Optional `snapshot` or stateful `changes` monitoring for a knowledge base

Because it runs on the Apify platform, you also get scheduling, ready-made integrations, run monitoring, and exports in JSON, CSV, or Excel.

### 💡 Why use the Loom Video Downloader?

Most Loom tools do only one job: either they download the video, or they pull the transcript, never both. This one does both, plus the metadata, in a single pass.

- **I am a content creator** repurposing my Loom walkthroughs into blog posts and social clips, and I need the transcript and the video file in one step.
- **I am a customer support lead** archiving every Loom recording my team sends to customers, so nothing gets lost when a workspace changes hands.
- **I am an AI or automation builder** feeding Loom transcripts into a summarizer or knowledge base, and I need clean, timestamped text without manually copying captions.
- **I am an agency or consultant** backing up client demo recordings and onboarding videos before a Loom account gets cancelled or a link expires.
- **I am a course creator** pulling subtitles and video files from a batch of recorded lessons to publish somewhere else.

### 🚀 How to use the Loom Video Downloader

1. Click **Try for free** at the top of this page.
2. Paste one or more Loom links into **Loom videos**. Share links, embed links, embed snippets, and raw video IDs all work.
3. Choose whether to include the **transcript** and **captions** (both on by default).
4. Enable **Discover from public pages** only when a supplied Loom folder/page should be scanned for visible links.
5. Choose `snapshot` for every current row, or `changes` with a stable **State key** for scheduled knowledge-base monitoring.
6. Turn on **Download and store the video file** only if you need a run-storage copy, not just the signed link. This takes longer and costs more for large videos.
7. Set **Max items** to cap how many videos you want processed, then press **Start**.
8. Download the dataset in JSON, CSV, or Excel, or connect it to Google Sheets, Make, Zapier, or your own app.

New here? Try it with a single link first to see the output shape before running a larger batch.

### 📥 Input

Set these fields in the Console form, or pass them as JSON.

| Field | Type | Required | Description |
|---|---|---|---|
| Loom videos | array of strings | Yes | Share links, embed links, embed snippets, or raw video IDs, one per line. |
| Start URLs | array | No | Alias accepting URL objects with an optional `inputId`; useful for discovery pages. |
| Discover from public pages | boolean | No | Extract visible public share/embed links from supplied Loom pages. Default `false`. |
| Monitor mode | `snapshot` or `changes` | No | `snapshot` emits current rows. `changes` emits `NEW`, `UPDATED`, `EXPIRED`, `REAPPEARED`, and failures while suppressing unchanged rows. |
| State key | string | Required for `changes` | Stable name for one monitoring scope. Keep it unchanged across scheduled runs. |
| Max items | integer | No | Maximum number of videos to process. Leave empty to process every video you listed. |
| Include full transcript | boolean | No | Attach the clean transcript text and timestamped lines. On by default. |
| Include captions (VTT) | boolean | No | Attach subtitle file content and its link. On by default. |
| Download and store the video file | boolean | No | Save the actual video file to this run's storage, not just the link. Off by default, since it takes longer and costs more for large videos. |
| Proxy configuration | object | No | Network settings. The default works for almost everyone. |

### 📤 Output

Every video becomes one row with everything about it in one place. Here is a shortened example:

```json
{
  "videoId": "230fc263c6784be7a0a4840a8c8f6216",
  "canonicalUrl": "https://www.loom.com/share/230fc263c6784be7a0a4840a8c8f6216",
  "title": "Loom 101 Webinar",
  "durationSeconds": 3224,
  "width": 2400,
  "height": 1350,
  "totalViews": 109,
  "ownerName": "Brittany Soinski",
  "thumbnailUrl": "https://cdn.loom.com/sessions/thumbnails/230fc263...jpg",
  "mediaUrl": "https://cdn.loom.com/sessions/transcoded/230fc263...mp4?Policy=...",
  "mediaUrlExpiresAt": "2026-07-03T04:14:40.000Z",
  "mediaFormat": "mp4",
  "transcriptText": "All right everybody, let's go ahead and get started...",
  "captionsUrl": "https://cdn.loom.com/mediametadata/captions/230fc263...vtt",
  "downloadable": true,
  "status": "ok",
  "changeType": "NEW",
  "changedFields": [],
  "firstSeenAt": "2026-07-03T03:59:40.417Z",
  "lastSeenAt": "2026-07-03T03:59:40.417Z",
  "retrievedAt": "2026-07-03T03:59:40.417Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. The Output tab has three ready-made views: Videos, Transcripts, and Downloads.

### 📊 Data table

Main fields returned for every video. Empty fields are dropped, so every value you see is real.

| Field | Type | Description |
|---|---|---|
| videoId | string | The Loom video ID resolved from your input. |
| sourceUrl | string | The supplied public share URL or discovery page used for this observation, when available. |
| inputId | string | Your supplied source identifier, when provided. |
| retrievedAt | string | UTC time the source was retrieved. |
| stateKey | string | The selected monitoring scope, when provided. |
| monitorMode | string | `snapshot` or `changes` for the run. |
| canonicalUrl | string | Direct share link to the video on Loom. |
| title | string | Video title. |
| description | string | Video description, when the owner added one. |
| durationSeconds | number | Video length in seconds. |
| width / height | number | Video resolution in pixels. |
| totalViews | number | Total view count, when available. |
| ownerName | string | Display name of the person who recorded the video. |
| ownerAvatarUrl | string | Link to the owner's profile picture. |
| thumbnailUrl | string | Static thumbnail image. |
| animatedThumbnailUrl | string | Animated preview thumbnail, when available. |
| mediaUrl | string | Direct, ready-to-download video link. |
| mediaUrlExpiresAt | string | Expiry decoded from Loom's signed URL policy, when available. Signed media URLs can expire. |
| mediaFormat | string | File format of the video link, typically mp4. |
| transcriptText | string | Full transcript as clean, readable text. |
| transcriptPhrases | array | Transcript broken into timestamped lines. |
| captionsVtt | string | Raw subtitle file content. |
| captionsUrl | string | Direct link to the subtitle file. |
| downloadable | boolean | Whether a video link was found for this video. |
| privacy / availability | string | Loom fields returned by the public source, only when Loom publishes them. |
| status | string | `ok`, `private`, `download_disabled`, `not_found`, `failed`, or monitor-generated `expired`. |
| statusReason | string | Plain-language explanation when status is not `ok`. |
| errorCode | string | Stable code for explicit source/input failures, when present. |
| changeType | string | `NEW`, `UPDATED`, `EXPIRED`, `REAPPEARED`, or `UNCHANGED`. |
| changedFields | array | Source fields that changed since the prior successful observation. Signed URLs are excluded. |
| firstSeenAt / lastSeenAt | string | State-backed lifecycle timestamps for the stable `videoId`. |
| savedFile | object | Stored file details, only present when file download was turned on. |
| scrapedAt | string | When this row was collected, in ISO 8601 UTC. |

### 💰 Pricing

This Actor uses **pay per result**, so you only pay for the videos you actually receive data for. Runs that return nothing cost nothing, and there are no monthly subscriptions or hidden fees. Turning on file download costs more per video since it moves the actual video file, and is billed separately from the standard result. Start with a small batch to preview the data before scaling up.

### ⭐ Enjoying Loom Video Downloader?

<table width="100%">
<tr>
<td style="padding:20px 24px 14px;background:#EEEDFD;border:1px solid #EEEDFD;border-left:5px solid #625DF5;border-radius:10px 10px 0 0">
<span style="font-size:20px;letter-spacing:4px">⭐ ⭐ ⭐ ⭐ ⭐</span><br>
<span style="font-size:17px;font-weight:800;color:#1C1917">If this is saving you from stitching together separate download and transcription tools, tell us about it.</span><br>
<span style="font-size:14px;color:#57534E">A 5-star rating takes 10 seconds and helps other content creators and support teams find this Actor. Your feedback also tells us what to build next.</span>
</td>
</tr>
<tr>
<td style="padding:0;background:#625DF5;border:1px solid #EEEDFD;border-top:none;border-radius:0 0 10px 10px;text-align:center">
<a href="https://apify.com/getascraper/loom-video-downloader/reviews" style="display:block;padding:13px 16px;color:#FFFFFF;text-decoration:none;font-weight:800;font-size:15px;letter-spacing:0.3px">★&nbsp;&nbsp;Rate this Actor on Apify</a>
</td>
</tr>
</table>

### ❓ FAQ

##### Does this work on private or password-protected videos?

No, and it should not. This Actor only resolves videos that were shared as "anyone with the link", the same access level Loom itself gives any visitor holding that link. Private, workspace-only, and password-protected videos are reported with a clear status instead of being bypassed.

##### Why does a video sometimes show no video link?

Some video owners turn off downloads, or the video may no longer be publicly shared. When that happens, the row still comes back with a clear `download_disabled`, `private`, `not_found`, or `failed` status and a plain-language reason, instead of a broken or fake link.

##### Do I need a Loom account or API key?

No. The Actor needs no login, no password, and no account connection. Just paste a link and press start.

##### Can I get both the transcript and the video file in the same run?

Yes. Every video's metadata, transcript, captions, and signed video link come back together in one row, and you can additionally turn on file storage if you want a copy in run storage. Loom signed URLs can expire, so the Actor never claims that `mediaUrl` is permanent.

##### Why is `savedFile` missing on a very long recording?

Unusually long recordings, well beyond a typical Loom clip, can be too large to safely store in one run. When that happens, you still get the full metadata, transcript, captions, and signed video link, just not a stored copy. This is a deliberate safety limit, not a bug.

### 🛟 Support

Found a bug, or need an extra field? Open an issue on the **Issues** tab of this Actor and it will be reviewed. Custom versions and larger batch runs are available on request.

### 🔗 Other actors

- [Loom Transcript Scraper](https://apify.com/getascraper/loom-transcript-scraper) ↗ - a lighter, API-fast option for pulling just Loom transcripts and metadata.
- [Streamable Video Downloader](https://apify.com/getascraper/streamable-video-downloader) ↗ - turns Streamable links into direct MP4 download URLs.
- [Twitch Scraper](https://apify.com/getascraper/twitch-scraper) ↗ - extracts channels, live streams, clips, and games from Twitch.
- [Viewstats YouTube Analytics & Rankings Scraper](https://apify.com/getascraper/viewstats-scraper) ↗ - pulls YouTube channel analytics and rankings.
- [Bulk Image Downloader](https://apify.com/getascraper/bulk-image-downloader) ↗ - downloads images in bulk with full metadata and hashes.

# Actor input Schema

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

One or more Loom videos to resolve. Paste a share link, embed link, full iframe snippet, or raw 32-character video ID. Duplicate URLs that identify the same video are emitted once.

## `startUrls` (type: `array`):

Optional alias for targets. With Discover from public pages enabled, public Loom folders or pages are scanned for visible share/embed links.

## `discoverFromPages` (type: `boolean`):

When enabled, fetches supplied public Loom folder/page URLs and extracts only visible share/embed links. It does not bypass login, password, or workspace controls.

## `monitorMode` (type: `string`):

Snapshot emits every current source-backed row. Changes compares successful scans using stateKey and suppresses unchanged rows.

## `stateKey` (type: `string`):

Stable monitoring scope name. Required for monitorMode=changes. Use the same value on scheduled runs; different keys keep independent histories.

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

Maximum number of videos to process. You are billed per video returned. Leave empty to process every target.

## `includeTranscript` (type: `boolean`):

Attach the clean, concatenated transcript text plus timestamped phrases (ready to paste into an LLM or notes) to every video. Only available when the video owner enabled transcription.

## `includeCaptions` (type: `boolean`):

Attach the raw WebVTT captions file content and its source URL, suitable for subtitle files or video editors.

## `downloadFile` (type: `boolean`):

When enabled, the actor streams the actual MP4 file into this run's key-value storage and returns run storage details in 'savedFile'. When disabled (default), the actor only returns Loom's temporary signed video URL. Signed URLs can expire; no permanent media URL is promised. Downloading large videos adds noticeable time and is billed separately.

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

Loom has no bot-detection wall, so a plain datacenter proxy (the default) works. Only switch to residential if you are running very high volume from a single location.

## Actor input object example

```json
{
  "targets": [
    "https://www.loom.com/share/230fc263c6784be7a0a4840a8c8f6216"
  ],
  "discoverFromPages": false,
  "monitorMode": "snapshot",
  "stateKey": "loom-video-downloader",
  "maxItems": 100,
  "includeTranscript": true,
  "includeCaptions": true,
  "downloadFile": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "targets": [
        "https://www.loom.com/share/230fc263c6784be7a0a4840a8c8f6216"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("getascraper/loom-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 = {
    "targets": ["https://www.loom.com/share/230fc263c6784be7a0a4840a8c8f6216"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("getascraper/loom-video-downloader").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": [
    "https://www.loom.com/share/230fc263c6784be7a0a4840a8c8f6216"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call getascraper/loom-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=getascraper/loom-video-downloader",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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