Direct answer — How do you automate file transcription on a Mac? Three routes exist. Wire a shell script around whisper.cpp and ffmpeg, wrap it in a Shortcut, and maintain it yourself. Send files to a cloud transcription API and accept that the audio leaves your Mac. Or call a local HTTP API inside a transcription app, which keeps every file on the machine and needs no scripting to maintain.
If you want to automate transcription on a Mac, the hard part is rarely the speech recognition — local models have been good enough for years. It is the plumbing: the trigger, the format conversion, the queue, the export, and the thing that breaks after a Homebrew upgrade.
This guide compares the three routes — DIY scripts, macOS Shortcuts, and a transcription API local to your machine — with the code you would actually run for each.
What does automating transcription on a Mac actually involve?
Three layers, and only one of them is speech recognition. Confusing them is why most automation attempts stall halfway.
- The trigger — a Finder Quick Action, a watched folder, a cron job or a node in an orchestrator.
- The engine — the model that turns audio into text, plus whatever preparation it demands.
- The output — a file, a clipboard, a database row, a subtitle track, a Markdown note.
A cloud API collapses all three into one HTTP call, at the cost of uploading the audio. A DIY script gives you total control and all three layers to maintain. A local API keeps engine and audio on your Mac while still collapsing the call into one line.
Can macOS Shortcuts transcribe files on its own?
Not with a local engine, no. Shortcuts is excellent at triggers and plumbing — Apple describes a shortcut as “a quick way to get one or more tasks done with your apps” — but it ships no general-purpose offline transcription action you can point at an arbitrary MP4.
The community projects show the workaround. The shared mac shortcuts audio transcription repositories all work the same way: the Shortcut supplies the trigger and the file path, then a Run Shell Script action hands the work to an external engine.
One wraps a zsh script around the MacWhisper command line tool, falling back to whisper.cpp from Homebrew. Another imports a .shortcut calling a shell script that combines whisper.cpp with ffmpeg. Both make the same point: Shortcuts is the trigger, never the engine.
What does the DIY whisper.cpp route involve?
Setup and upkeep. The engine is free and excellent; the maintenance is the price, and it is not zero.
A minimal transcription automation script mac setup looks like this:
# 1. Install the engine and the converter
brew install ffmpeg
brew install whisper-cpp
# 2. Fetch a model file by hand (e.g. ggml-large-v3-turbo.bin)
# 3. Convert first — whisper.cpp's CLI reads 16-bit WAV only
ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav
# 4. Then transcribe
whisper-cli -m ~/.cache/whisper.cpp/models/ggml-large-v3-turbo.bin -f output.wav
Step 3 is not optional. The official whisper.cpp README is explicit: “the whisper-cli example currently runs only with 16-bit WAV files, so make sure to convert your input before running the tool”, and it publishes the ffmpeg command above.
That constraint is where most whisper.cpp automation mac chains break: every new format, stereo interview and video container must be converted first, and the failure is silent until you read an empty transcript.
Add the other moving parts — renamed model files, a Homebrew upgrade, no job queue, no progress, no history — and an afternoon’s script becomes a small internal tool you now own. Our whisper.cpp setup guide covers that path in detail.
What is a local transcription API, and why does it change the workflow?
A local transcription API is an HTTP server running inside a desktop app on your own machine, so other programs can send it a file and get text back without any audio leaving the Mac. Same request shape as a cloud API, none of the upload.
Weesper Transcribe ships one as an optional Pro feature. It binds to the loopback address 127.0.0.1 — unreachable from your network — on a configurable port (8765 by default), it is off by default, and every endpoint except the health check requires an Authorization: Bearer token shown in Settings → Automation.
Two design details matter for automation:
- The caller uploads the audio bytes, not a file path. The App Store build is sandboxed and cannot read arbitrary paths from another process, so the bytes travel over loopback.
- Sync and async in one endpoint. A short clip blocks until done; a long recording returns a job identifier immediately and you poll for progress.
The endpoints
| Endpoint | Auth | What it does |
|---|---|---|
GET /v1/health | No | Liveness probe — status and version |
GET /v1/models | Yes | Lists model ids and which are installed |
POST /v1/transcribe | Yes | Send audio bytes, get text and timestamped segments |
GET /v1/jobs/<id> | Yes | Status, progress, then text and export path |
Options ride as query parameters and anything you omit falls back to the app’s saved settings: model, language, task (transcribe or translate), format, name, export, async.
One call, end to end
TOKEN=… # copied from Settings → Automation
# Synchronous: transcribe and write an SRT into the auto-export folder
curl -s -X POST "http://127.0.0.1:8765/v1/transcribe?format=srt&name=meeting" \
-H "Authorization: Bearer $TOKEN" \
--data-binary @meeting.m4a | jq .text
# Asynchronous: long file, poll for the result
JOB=$(curl -s -X POST "http://127.0.0.1:8765/v1/transcribe?async=true&name=lecture" \
-H "Authorization: Bearer $TOKEN" --data-binary @lecture.mp4 | jq -r .job_id)
curl -s "http://127.0.0.1:8765/v1/jobs/$JOB" -H "Authorization: Bearer $TOKEN" | jq
No conversion step, no model management, no queue to write. The response carries text and timestamped segments, and the app renders a file in the format you asked for — one of nine, including SRT and VTT when subtitles are the deliverable.
How do the three routes compare?
Match the route to what you are optimising for: control, privacy, or moving parts to own.
| Criterion | DIY scripts (whisper.cpp) | Local API (Weesper Transcribe) | Cloud transcription API |
|---|---|---|---|
| Audio leaves your Mac | ❌ Never | ❌ Never | ✅ Every file uploaded |
| Setup effort | High — Homebrew, models, conversion | Low — toggle on, copy token | Low — API key |
| Format conversion | Manual (ffmpeg, 16-bit WAV) | Handled by the app | Handled by the service |
| Job queue and progress | You build it | Built in, sync or async | Built in |
| Works offline | ✅ | ✅ | ❌ |
| Recurring cost | None | One-time Pro upgrade | Per minute or per seat |
| Who maintains it | You | The app | The vendor |
| History and search | You build it | Built in, keyword and semantic | Vendor-hosted |
In short: DIY wins on control and costs only your time, cloud wins on scale and loses on confidentiality, and a local API is the middle path when the audio must not leave the machine.
Three automation recipes worth stealing
Start with the trigger you already use. The transcription step is one line in each.
- Finder Quick Action — build a Shortcut that takes files as input, add a Run Shell Script action with the
curlcall above and--data-binary @"$1", then right-click any recording to transcribe it. Keep the token in the script or a Keychain item, never in a URL parameter. - Watched folder — point a Folder Action or a small
fswatchloop at your recordings directory and fire the same call per new file. Setexport=trueand the transcript lands in your export folder. - Orchestrator step — in n8n, an Execute Command node shells out to
curl. Its documentation is explicit that the node runs commands “on the host machine that runs n8n”, “isn’t available on n8n Cloud”, and is disabled by default from n8n 2.0. A n8n local transcription step therefore needs a self-hosted instance on the same Mac — which is the point of a loopback API.
For a batch transcribe automation workflow, you may need no orchestrator at all: queue a folder inside the app, and use the API only for what your own tooling drives.
Which route should you choose?
Pick by the constraint that will not move.
- Choose DIY scripts if you want full control over the model and enjoy owning a conversion pipeline. Cheapest in money, most expensive in attention.
- Choose a local API if the audio is confidential — client interviews, medical recordings, unreleased work — and you want automation without maintenance.
- Choose a cloud API if you transcribe at a scale no laptop can absorb and the material is not sensitive.
Still weighing apps rather than routes? Our comparison of TranscribeNext and Weesper Transcribe covers the meeting-capture side of that decision.
Frequently asked questions
How do I automate transcription on a Mac without writing scripts?
Use an app that exposes a local transcription API, then call it from whatever already runs your work: a Shortcut, a Folder Action, a scheduled job or an n8n workflow. Weesper Transcribe ships an optional HTTP server bound to 127.0.0.1 and protected by a bearer token. One curl call sends the audio bytes and returns the text, plus a rendered file in your auto-export folder.
Can macOS Shortcuts transcribe an audio file on its own?
Not for arbitrary files with a local engine. Shortcuts is very good at the trigger and the plumbing: a Quick Action in Finder, a Folder Action, a share-sheet entry. The transcription has to come from somewhere, which is why the community shortcuts on GitHub wrap a Run Shell Script action around whisper.cpp or a third-party command line tool.
What does the DIY whisper.cpp automation route actually cost you?
Setup and maintenance rather than money. The published community scripts install ffmpeg and whisper.cpp through Homebrew, download model files by hand, and convert every input first, because the whisper.cpp command line tool runs only on 16-bit WAV files. A Homebrew upgrade, a renamed model file or an unhandled input format will break the chain quietly.
Is a local transcription API safe to leave switched on?
It depends on how it is bound and authenticated. The Weesper Transcribe API is off by default, listens only on 127.0.0.1 so it is unreachable from your network, and requires a bearer token on every endpoint except the health check. Requests carrying a browser Origin header are rejected, so a web page cannot call it behind your back.
Can I run a local transcription API from n8n or another automation tool?
Yes, when the tool runs on the same Mac. n8n’s documentation states that its Execute Command node runs shell commands on the host machine that runs n8n and is not available on n8n Cloud — so a self-hosted instance can shell out to curl, while a cloud instance cannot reach 127.0.0.1 on your laptop.
Conclusion
Automating transcription on a Mac has been possible for years, but only through scripts you had to build and keep alive. The community projects prove the demand and expose the cost: Homebrew dependencies, manual model files, a conversion step before every file.
A loopback API moves that work inside the app — same one-line call as a cloud service, same automation surface for Shortcuts, folder watchers and self-hosted orchestrators, and the audio never leaves the machine.
Ready to make transcription a pipeline step? See how Weesper Transcribe handles batches, exports and the local automation API, or get it from the Mac App Store — free to download, macOS 13 or later, one-time Pro upgrade, no subscription. Setup questions are answered in the support documentation.