oTranscribe is a keyboard driven player and editor for interview transcripts
A free & open tool for transcribing audio interviews
At a glance
- What is it?
- oTranscribe is a free web app for transcribing recorded interviews, and it does not transcribe anything by itself. It pairs a media player with a rich text editor, saves the transcript to local storage every second, and exports a small JSON file that carries the text and the last playback position. The whole thing is plain JavaScript, Webpack and a static build you can host yourself.
- Who is it for?
- oTranscribe fits a journalist, researcher or student who has hours of recorded conversation to type out, and who wants a player and an editor in one window with no account and no upload. It is the wrong tool if you need automatic speech to text, because nothing here recognises speech, and it is the wrong tool for a long project if you need version history, since the save target is the browser's local storage.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 74 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It plays and it saves, but it does not transcribe
oTranscribe is described as a free web app designed to take the pain out of transcribing recorded interviews, and the name of the project and the file format both come from that framing. It is a workbench for a human who is doing the typing.
The feature list makes that clear. You can pause with ESC, rewind with F1 and fast forward with F2 without taking your hands off the keyboard, and you can adjust playback speed with a slider or with F3 and F4. Your transcript is automatically saved to the browser's localStorage every second. Rich text support uses contentEditable, and there is YouTube and video file support.
So the app removes the friction of a transcription session rather than the work. The audio is played back with keyboard control so that you never have to find a mouse, the speed control lets you slow down a passage without losing your place, and the autosave means a crash costs you at most a second of typing rather than the whole transcript. You are still transcribing, and the app is a good surface for doing it.
The project was built by Elliot Bentley and is hosted and maintained by the MuckRock Foundation, which is a newsroom non profit, and the README asks for donations to keep it running. That origin explains the emphasis: this is a tool for someone with a recording and a deadline, and the hosted version at otranscribe.com is the primary way to use it.
The keyboard is the interface, and the shortcuts are few
The whole design of the input handling is in those five keys, and it is worth reading them as a set rather than a list.
ESC pauses, F1 rewinds and F2 fast forwards. F3 and F4 adjust the playback speed. The reason the app can be operated without a mouse is that these are the only controls you need while transcribing, and they are bound through the mousetrap library, which is in the dependency list, so the shortcuts work regardless of what has focus in the page. The keycode library is there as well, and jquery and preact are the rendering layer, with mustache for templating and turndown and sanitize-html for handling rich text.
The speed control is the one that changes the work rather than the interaction. A slider is not much use while your hands are on the keyboard, so the F3 and F4 bindings are the practical path, and a reviewer who has never used the app will find that the same keys work in a recording that is hard to follow.
The other half of the design is that the text is a rich text field rather than a plain textarea. contentEditable is what allows a transcript to carry emphasis without a markdown syntax, and turndown and sanitize-html are the two libraries that make that safe, one converting and the other cleaning.
It is a small set of choices, and each of them is a decision about where the friction of transcription actually lives.
The save target is localStorage, and the export is a four field JSON file
The persistence story is the part to understand before you rely on it. The transcript is written to the browser's localStorage every second, which means it survives a refresh and a crash, and it also means it lives in one browser profile on one machine. There is no account, no sync and no server, which is also why the README stresses that the web version is free and open.
The export format is documented as a first class part of the project. oTranscribe has its own file format, .otr, which is just a JSON file with four parameters: text, which is the raw HTML of the transcript, media, the name of the last media used if available, media-source, a link to the last media used if available, and media-time, the playtime of the last media used if available.
The media fields are the interesting part. Because the export records where you were in the recording, an .otr file is not only a transcript but a bookmark. Open it later, load the same media, and the player knows the position you had reached, which for a two hour interview that you will return to over three days is the difference between a usable draft and a lost one.
The storage is also the main limitation of the design. localStorage is per browser and per origin, so a transcript does not follow you to another machine, and there is no history of the previous versions.
Self-hosting means compiling the source and uploading a dist folder
Although a web version is available, the README explains how to install oTranscribe anywhere, and the steps are a small static site build.
You download the current ZIP archive, compile the CSS and the JavaScript with Webpack, and upload the files in the newly generated dist folder to a server of your choice. The src folder in the repository only includes the raw JavaScript and CSS, so the build step is not optional.
The compilation section gives the requirements and the commands. You need Node.js and NPM, requiring Node v24 and npm v10, and the project is verified to work on npm 11.12.1 with node v24.14.1. Then you run npm install to install the dependencies, and npm run build to compile the dist folder.
Two npm scripts cover the rest of the workflow. npm run serve serves the production build locally and includes the Workbox service worker for offline caching support, while npm run dev starts the local dev server with watch for changes enabled, at http://localhost:8080/. There is a caveat about the service worker: it is only included in production builds, so offline caching support is not enabled in the dev server.
One browser caveat is worth repeating. In Chrome, local copies of oTranscribe may not run correctly because of the browser's privacy settings around access to the local file system, and the README links the discussion of that behaviour.
The Makefile does the static half of the build. The compile_static target clears the dist folder, concatenates the localisation files from src/l10n into dist/data.ini, copies the images and the static pages, and moves help.htm, privacy.htm and opensource.htm into directories with index.html files so that they work as clean URLs.
The test script is a placeholder that fails on purpose
There is a small detail in package.json that tells you more about the state of the project than any badge would. The test script is set to echo a message and exit with a non zero status.
"test": "echo \"No tests configured\" && exit 1"So npm test fails on purpose, because no tests are configured. Meanwhile the development dependencies include karma, karma-mocha, karma-chrome-launcher, karma-webpack, mocha and chai, which is a complete browser test stack that is not wired up. The src/ folder is still raw JavaScript with a .babelrc and babel-loader in the Webpack config, and the tests/ directory exists in the repository, so the infrastructure for tests is partly there and the runner is not.
That combination tells you what to expect from contributing. The build works, the dev server works, and the test command will stop your pipeline until somebody fills in the suite. The README does not describe a test workflow, so the assumption is that changes are verified by running the app.
The rest of the toolchain is a conventional Webpack 5 setup with SASS, ESLint and a Prettier configuration, and the repository has a .node-version and .nvmrc for the runtime. The version in package.json is 2.0.0, the project is MIT licensed with the file at the repository root, the last push was on 2026-08-10, and the project is not archived.
Translations and the question of who runs the instance
The README carries a long list of translation credits, which is a good indicator of who uses the tool. Catalan, Chinese, Danish, Dutch, Filipino, French, German, Indonesian, Italian, Japanese, Norwegian, Polish, Portuguese and Brazilian Portuguese, Romanian, Russian, Spanish, Swedish, Turkish, Ukrainian, Vietnamese and Greek are all represented, with named contributors and a link to a wiki page about how to help translate oTranscribe.
The localisation is built into the static pipeline rather than being a runtime feature. The compile_static target reads the .ini files from src/l10n and concatenates them into a single dist/data.ini, and the webl10n library in the dependencies is the client side half of that. A translator contributes a file, and the build turns the set into one data file the app fetches.
The other axis is who operates the service. The hosted version is free and maintained by a non profit foundation, and the self hosted route exists for people who cannot or do not want to send their audio and their transcript to somebody else's server. For a newsroom handling sensitive interviews, or a legal team, or anyone whose source material is confidential, the fact that the whole application is static files and a JSON file format means self hosting is a genuine option rather than a workaround.
What the self hosted copy does not give you is the hosted instance's continuity. The MuckRock Foundation runs the site and takes the donations, and a local copy is your server's problem, which is a trade most people are happy to make and some are not.
Editorial conclusion
oTranscribe fits a journalist, researcher or student who has hours of recorded conversation to type out, and who wants a player and an editor in one window with no account and no upload. It is the wrong tool if you need automatic speech to text, because nothing here recognises speech, and it is the wrong tool for a long project if you need version history, since the save target is the browser's local storage. Verify first that a self-hosted copy behaves in the browser you use, because the README warns that Chrome privacy settings can block a local copy from running correctly.
Frequently asked questions
Does oTranscribe do speech recognition?
No. It is a free web app designed to take the pain out of transcribing recorded interviews, and its features are playback control with the keyboard, playback speed, autosave to localStorage every second, rich text through contentEditable, and YouTube and video file support. You do the typing.
How do I run a local copy of oTranscribe?
Download the current ZIP archive, install Node v24 and npm v10, run npm install and then npm run build to compile the dist folder, and upload that folder to your server. Locally you can use npm run serve for the production build, which includes the Workbox service worker, or npm run dev for the dev server on http://localhost:8080/.
What is the .otr file and what does it contain?
It is oTranscribe's own file format, which is just a JSON file with four parameters: text, the raw HTML of the transcript, media, the name of the last media used, media-source, a link to the last media used, and media-time, the playtime of the last media used. The last three are optional.
Is there a test suite in the oTranscribe repository?
Not one that is wired up. The test script in package.json is set to echo No tests configured and exit 1, so npm test fails deliberately, even though karma, mocha and chai are present in the dev dependencies. The README does not describe a test workflow.
Who maintains oTranscribe and is it free?
It was built by Elliot Bentley and is hosted and maintained by the MuckRock Foundation, which asks for donations to keep it running. The project is MIT licensed, the hosted version is at otranscribe.com, and the last push to the repository was on 2026-08-10.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/otranscribe-otranscribe)Was this useful?