# Loom Transcript Scraper - Captions to Text (`khadinakbar/loom-transcript-scraper`) Actor

Extract public Loom video transcripts as clean text, timestamped segments, VTT, and SRT. Use public share or embed URLs only; no login, cookies, or video download.

- **URL**: https://apify.com/khadinakbar/loom-transcript-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Videos, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 loom transcripts

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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/docs.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## Loom Transcript Scraper - Captions to Text

Extract the captions that Loom already exposes for public share and embed videos. Give the actor public Loom links and receive clean LLM-ready text, timestamped segments, and optional VTT/SRT subtitle strings. It is transcript-first: it does not download video files, bypass passwords, or access private Loom accounts.

### When to use it

Use it to turn public Loom walkthroughs, demos, training videos, or support recordings into text for RAG, documentation, summaries, accessibility captions, or content research. Do not use it for private, password-protected, folder, account, or video-download workflows.

### Output per video

| Field                                   | Description                                                                 |
| --------------------------------------- | --------------------------------------------------------------------------- |
| `transcriptText`                        | Full clean transcript, ready for prompts and embeddings.                    |
| `transcriptSegments`                    | Timestamped `{ startSeconds, endSeconds, text }` caption units.             |
| `transcriptVtt`, `transcriptSrt`        | Optional subtitle strings derived from the timestamped transcript.          |
| `title`, `ownerName`, `durationSeconds` | Public video context when metadata is enabled.                              |
| `status`, `error`                       | Honest result state; videos without captions are retained but never billed. |

### Pricing

Pay per event + platform usage is enabled.

| Event                        |           Price |
| ---------------------------- | --------------: |
| Actor start                  |        $0.00005 |
| Public Loom transcript saved | **$0.01/video** |

Videos with no transcript and upstream failures are not charged the per-video event. A run of 25 successful videos costs at most $0.25005 in actor events, plus Apify platform usage.

### Input

```json
{
    "loomUrls": [
        "https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4",
        "https://www.loom.com/embed/002508e86fde4232bb8de474eb5c65c4"
    ],
    "maxVideos": 25,
    "includeMetadata": true,
    "includeCaptionFiles": true
}
````

You may also add `startUrls` request objects in a programmatic workflow. The actor accepts share URLs, embed URLs, and raw 32-character Loom IDs, and deduplicates all supplied targets automatically.

### Example output

```json
{
    "videoId": "002508e86fde4232bb8de474eb5c65c4",
    "sourceUrl": "https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4",
    "status": "transcript_extracted",
    "title": "Product walkthrough",
    "durationSeconds": 154,
    "transcriptText": "Hello from Loom.\nThis is the second caption.",
    "transcriptSegments": [{ "startSeconds": 0.31, "endSeconds": 8.5, "text": "Hello from Loom." }],
    "transcriptVtt": "WEBVTT\n\n00:00:00.310 --> 00:00:08.500\nHello from Loom.",
    "transcriptSrt": "1\n00:00:00,310 --> 00:00:08,500\nHello from Loom.",
    "scrapedAt": "2026-07-15T10:00:00.000Z"
}
```

### How it works

1. The actor validates a public Loom share or embed URL and normalizes it to the video ID.
2. It loads the public share page over HTTP and reads the page's embedded public video state.
3. It downloads Loom's short-lived signed transcript JSON and normalizes caption phrases.
4. It writes the usable transcript row and charges the per-video event in the same SDK call.

This approach does not use browser automation, third-party transcription, cookies, or API keys. Signed caption links are not returned because they expire quickly.

### Run outcomes

`OUTPUT` and `RUN_SUMMARY` are written for every terminal path. Outcomes are `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, or `UPSTREAM_FAILED`. A public video without captions becomes a non-billable `no_transcript` dataset row; a fully unavailable upstream becomes an honest failed run only when no useful transcript was produced.

### MCP usage

Use this when an agent needs text from a known public Loom video. It returns one dataset row per input video; use `transcriptText` for concise retrieval and `transcriptSegments` for timestamp-aware answers. It is not a general Loom search, downloader, or private-account connector.

### Limits and responsible use

- Only public, non-password-protected Loom videos are supported.
- The actor extracts captions Loom has made available; it does not generate speech-to-text for videos without captions.
- Loom can change its public page data or signed-URL behavior. Failures are surfaced in `status` and the run summary.
- You are responsible for having a lawful basis to process the public content and for complying with Loom's terms and applicable privacy laws.

# Actor input Schema

## `loomUrls` (type: `array`):

Use this when you have public Loom share or embed links and need their existing captions. Add URLs such as https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4 or https://www.loom.com/embed/002508e86fde4232bb8de474eb5c65c4. The actor deduplicates links and accepts raw 32-character video IDs. It does not access password-protected, private, folder, or account URLs.

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

Optional Loom targets from another actor or API workflow, passed as request objects such as \[{"url":"https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4"}]. These are merged with the required loomUrls field and deduplicated by video ID. Use loomUrls for the primary target list in manual and agent runs. It is not a crawler instruction for folder or profile discovery.

## `maxVideos` (type: `integer`):

Maximum unique public Loom videos to process and charge in this run. Defaults to 25 and accepts 1 through 200. Lower this number to cap spend when pasting a batch. It is a run-wide cap, not a transcript-length limit.

## `includeMetadata` (type: `boolean`):

Include public title, description, owner name, duration, view count, comment count, thumbnail, creation time, and privacy label where Loom exposes them. Defaults to true so transcript records retain source context. Turn it off for smaller text-only payloads. This does not expose private analytics or account data.

## `includeCaptionFiles` (type: `boolean`):

Create WebVTT and SRT caption strings from Loom's timestamped transcript segments. Defaults to true for subtitle and accessibility workflows. Turn it off when you only need transcriptText and transcriptSegments for an LLM or RAG pipeline. This does not download the source video.

## Actor input object example

```json
{
  "loomUrls": [
    "https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4"
  ],
  "maxVideos": 25,
  "includeMetadata": true,
  "includeCaptionFiles": true
}
```

# Actor output Schema

## `transcripts` (type: `string`):

One normalized row per public Loom video.

## `summary` (type: `string`):

Terminal outcome, counts, and billable event totals.

## `runSummary` (type: `string`):

Stable duplicate summary for diagnostics and automation.

# 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 = {
    "loomUrls": [
        "https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4"
    ],
    "maxVideos": 25,
    "includeMetadata": true,
    "includeCaptionFiles": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/loom-transcript-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 = {
    "loomUrls": ["https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4"],
    "maxVideos": 25,
    "includeMetadata": True,
    "includeCaptionFiles": True,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/loom-transcript-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 '{
  "loomUrls": [
    "https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4"
  ],
  "maxVideos": 25,
  "includeMetadata": true,
  "includeCaptionFiles": true
}' |
apify call khadinakbar/loom-transcript-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Loom Transcript Scraper - Captions to Text",
        "description": "Extract public Loom video transcripts as clean text, timestamped segments, VTT, and SRT. Use public share or embed URLs only; no login, cookies, or video download.",
        "version": "1.0",
        "x-build-id": "X5sZEtUlgKudGBced"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/khadinakbar~loom-transcript-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-khadinakbar-loom-transcript-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/khadinakbar~loom-transcript-scraper/runs": {
            "post": {
                "operationId": "runs-sync-khadinakbar-loom-transcript-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/khadinakbar~loom-transcript-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-khadinakbar-loom-transcript-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": [
                    "loomUrls"
                ],
                "properties": {
                    "loomUrls": {
                        "title": "Public Loom video URLs",
                        "type": "array",
                        "description": "Use this when you have public Loom share or embed links and need their existing captions. Add URLs such as https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4 or https://www.loom.com/embed/002508e86fde4232bb8de474eb5c65c4. The actor deduplicates links and accepts raw 32-character video IDs. It does not access password-protected, private, folder, or account URLs.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Additional start URL objects",
                        "type": "array",
                        "description": "Optional Loom targets from another actor or API workflow, passed as request objects such as [{\"url\":\"https://www.loom.com/share/002508e86fde4232bb8de474eb5c65c4\"}]. These are merged with the required loomUrls field and deduplicated by video ID. Use loomUrls for the primary target list in manual and agent runs. It is not a crawler instruction for folder or profile discovery.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxVideos": {
                        "title": "Maximum videos",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Maximum unique public Loom videos to process and charge in this run. Defaults to 25 and accepts 1 through 200. Lower this number to cap spend when pasting a batch. It is a run-wide cap, not a transcript-length limit.",
                        "default": 25
                    },
                    "includeMetadata": {
                        "title": "Include video metadata",
                        "type": "boolean",
                        "description": "Include public title, description, owner name, duration, view count, comment count, thumbnail, creation time, and privacy label where Loom exposes them. Defaults to true so transcript records retain source context. Turn it off for smaller text-only payloads. This does not expose private analytics or account data.",
                        "default": true
                    },
                    "includeCaptionFiles": {
                        "title": "Include VTT and SRT",
                        "type": "boolean",
                        "description": "Create WebVTT and SRT caption strings from Loom's timestamped transcript segments. Defaults to true for subtitle and accessibility workflows. Turn it off when you only need transcriptText and transcriptSegments for an LLM or RAG pipeline. This does not download the source video.",
                        "default": true
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
