# Audio & Video Transcriber — any file or link, no API key (`soboljem/audio-transcriber`) Actor

Transcribes any audio or video you can link to: a podcast MP3, a file on S3 or your own server, a Vimeo video, a recorded call. Speech recognition is included in the price — no OpenAI or Deepgram key to set up.

- **URL**: https://apify.com/soboljem/audio-transcriber.md
- **Developed by:** [Luboš Benetka](https://apify.com/soboljem) (community)
- **Categories:** AI, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 audio minute transcribeds

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

## Audio & Video Transcriber — any file or link, no API key

Give it a URL to a sound, get the words back. A podcast episode, a file sitting on S3 or your own
server, a recorded interview, a Vimeo video, a lecture — anything you can link to.

**Speech recognition is included in the price.** No OpenAI key, no Deepgram key, no second bill
to reconcile.

```
in:   https://example.com/episode-142.mp3
out:  full text · timed segments · a ready-to-use .vtt subtitle file
```

### Why "no API key" is the whole point

Most transcription actors on the store are **BYOK** — bring your own key. To use one you sign up
with an AI provider, put a card on file, generate a key, paste it into the actor input, and then
watch two bills instead of one. If you are evaluating three tools, that is three signups before
you learn whether any of them works.

Here you paste a URL.

### What it handles

| input | what happens |
|---|---|
| direct `.mp3`, `.wav`, `.m4a`, `.mp4` | transcribed. A direct file has no metadata page, so the duration is **measured from the file** rather than refused |
| Vimeo, YouTube, Twitch, SoundCloud (~1800 sites) | if real subtitles already exist they are read **for free**; otherwise the audio is transcribed |
| a two-hour recording | cut into overlapping windows, transcribed, reassembled onto the original clock — timings stay correct at the end |
| a playlist or channel URL | **refused**, with the reason. It could be thousands of files and you would be billed for all of them |

### What you get, per file

```json
{
  "url": "https://example.com/episode-142.mp3",
  "durationSeconds": 3612,
  "source": "whisper",
  "isAiGenerated": true,
  "language": "en",
  "text": "the full transcript…",
  "wordCount": 8213,
  "segments": [{ "start": 0.2, "end": 3.1, "text": "…" }],
  "vtt": "WEBVTT…",
  "lowConfidence": false,
  "warning": null,
  "hallucinationsRemoved": 0
}
```

### Three things it refuses to do, on purpose

**1. It never returns a partial transcript.** Long audio is cut into windows and reassembled, and
if any window goes missing the file fails with an error rather than returning text with a silent
hole in the middle. A transcript with a gap reads perfectly and is undetectable by you — which is
exactly what makes it the one output worth failing to avoid.

**2. It never bills you for work it did not do.** If a page already has real subtitles, they are
read and **no transcription minutes are charged**. A failed file writes a row explaining which URL
failed and why, and is charged nothing at all — one dead link in a batch of 200 never costs you
the other 199.

**3. It tells you when it could not really hear anything.** Speech models trained on subtitle
files invent subtitle furniture over silence and music — translator credits, "thanks for
watching". Those are stripped and counted in `hallucinationsRemoved`, and if little real speech is
left the row comes back `lowConfidence: true` with a reason. **An honest "we could not hear speech
in this" is more useful than a fluent invention**, and you can filter on it.

### Input

```json
{
  "videoUrls": ["https://download.samplelib.com/mp3/sample-15s.mp3"],
  "language": "en",
  "includeSubtitles": true,
  "includeCutList": false
}
```

`includeCutList` returns the spans of dead air, for editors cutting long footage.

### Pricing

Per result, plus per minute actually transcribed — so a short clip costs like a short clip, and
you are never charged transcription minutes for subtitles that already existed.

# Actor input Schema

## `videoUrls` (type: `array`):

One URL per line. A direct link to an .mp3, .wav, .m4a or .mp4 — a podcast episode, a file on S3 or your own server, a recorded call — or a page on Vimeo, YouTube, Twitch, SoundCloud and ~1800 other sites. Playlists and channels are refused: they can be thousands of files and you would be billed for all of them.

## `language` (type: `string`):

Two-letter code of the language you expect, e.g. en, cs, de. Leave empty to let speech recognition detect it.

## `forceTranscription` (type: `boolean`):

A direct audio file is always transcribed — there is nothing else to read. This only matters for pages that may already carry subtitles (Vimeo, YouTube): those are read for free by default. Turn this on to transcribe the audio regardless.

## `includeSubtitles` (type: `boolean`):

Return a ready-to-use .vtt subtitle file alongside the plain text.

## `includeCutList` (type: `boolean`):

Return the spans of dead air — where nobody is speaking — so an editor can cut them. Nothing else on the store returns this.

## Actor input object example

```json
{
  "videoUrls": [
    "https://download.samplelib.com/mp3/sample-15s.mp3"
  ],
  "forceTranscription": false,
  "includeSubtitles": true,
  "includeCutList": false
}
```

# Actor output Schema

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

One row per video: the full text, timed segments, ready-made WebVTT subtitles, and whether the text came from existing captions or from speech recognition. Rows flagged lowConfidence are ones where little or no real speech was found — filter on it rather than trusting every row equally.

# 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 = {
    "videoUrls": [
        "https://download.samplelib.com/mp3/sample-15s.mp3"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("soboljem/audio-transcriber").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 = { "videoUrls": ["https://download.samplelib.com/mp3/sample-15s.mp3"] }

# Run the Actor and wait for it to finish
run = client.actor("soboljem/audio-transcriber").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 '{
  "videoUrls": [
    "https://download.samplelib.com/mp3/sample-15s.mp3"
  ]
}' |
apify call soboljem/audio-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,soboljem/audio-transcriber"
        }
    }
}

```

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/wmp7SoxgiAhKn1ggh/builds/6WGhQaJjlAerpKEYN/openapi.json
