Self-hosted service
attendee-labs/attendee avatar
attendee-labs/attendee

Attendee: a self-hostable API for running meeting bots

The universal Meeting Bot API

770 stars299 forksPythonNOASSERTION

At a glance

What is it?
Attendee is an open source API that runs meeting bots on Zoom and Google Meet and returns transcripts and recordings, packaged as a Django application in a single Docker image with Postgres and Redis. It saves a product team the work of driving the meeting SDKs, but it needs Zoom OAuth credentials and a Deepgram key.
Who is it for?
Attendee suits a product team that needs meeting transcripts and recordings in its own application and would rather run a service than sign up for a closed-source vendor, since the README claims self-hosting cuts cost by ten times. It does not suit a team without a Zoom developer account, because OAuth credentials for the Meeting SDK are a hard prerequisite.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, 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

The problem Attendee solves

Attendee is an open source API for managing meeting bots on platforms like Zoom or Google Meet, and the pitch is that you can bring meeting transcripts and recordings into your product in days instead of months.

The README explains why meeting bots are worth building and why they are painful. A bot has access to the same audio and video streams as a human user of meeting software, which is the capability behind products like Gong or Otter.ai. But building one across platforms is hard, and the platform support is uneven. Zoom provides a powerful SDK, but it is low-level and advanced features such as per-participant audio streams are only available in the C++ variants. Google Meet provides no support at all, so you have to run a full instance of Google Meet in Chrome.

Attendee abstracts that away into a single developer-friendly REST API that manages the state and media streams from these bots. The claim is that a developer building functionality that requires meeting bots can save months of work.

The state model is small and worth reading carefully, because it is what a client has to poll. A bot object carries an id, the meeting_url, a state and a transcription_state. The state moves through things like joining and ended. The transcription_state starts at not_started and reaches complete when the meeting recording has been transcribed. Those two fields are the whole contract for a client polling for results, and they are distinct because a meeting can end before its transcript is ready.

Joining a meeting, polling and fetching the transcript

The API is a set of three calls. The first creates a bot by POSTing to the bots path, with the meeting URL and a bot name, authenticated with a token header.

bash
curl -X POST https://app.attendee.dev/api/v1/bots \
-H 'Authorization: Token <YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{"meeting_url": "https://us05web.zoom.us/j/84315220467?pwd=9M1SQg2Pu2l0cB078uz6AHeWelSK19.1", "bot_name": "My Bot"}'

The response is the bot object with its id and a state of joining and a transcription_state of not_started, and it represents the bot's state in the meeting.

The second call polls that bot by id.

bash
curl -X GET https://app.attendee.dev/api/v1/bots/bot_3hfP0PXEsNinIZmh \
-H 'Authorization: Token <YOUR_API_KEY>' \
-H 'Content-Type: application/json'

When the state comes back as ended, the meeting has ended. When transcription_state is complete, the recording has been transcribed.

The third call fetches the transcript itself, and the README notes you can also query it while the meeting is happening to retrieve partial transcripts, which is what makes a live captioning feature possible.

bash
curl -X GET https://app.attendee.dev/api/v1/bots/bot_3hfP0PXEsNinIZmh/transcript \
-H 'Authorization: Token <YOUR_API_KEY>' \
-H 'Content-Type: application/json'

Each transcript entry carries a speaker_name, a speaker_uuid, a speaker_user_uuid, a timestamp_ms, a duration_ms and the transcription text. The speaker identifiers are what let a client group speech by person, and having both a speaker_uuid and a speaker_user_uuid is how a client maps a meeting participant back to a user in its own system.

The three credentials you need before anything works

The prerequisites section lists three things, and all three are needed before a bot can join and produce a transcript.

The Attendee API key is created in the Attendee UI, by creating an account in your Attendee instance, signing in and navigating to the API Keys section in the sidebar.

The Zoom OAuth credentials are needed to join Zoom meetings, and they are the Zoom app client id and secret that uniquely identify your bot. The README walks through obtaining them: register or log in to a developer account in the Zoom Marketplace, click the Develop button, choose Build App and pick General App, copy the Client ID and Client Secret from the App Credentials section, then go to the Embed tab in the left navigation under Features and select the Meeting SDK toggle.

The Deepgram API key is needed for transcribing meetings, and the README says you can sign up with no credit card required and get 400 hours worth of free transcription.

The Zoom credentials and the Deepgram key are entered into the Attendee UI in the Settings section of the sidebar. So the separation is: the API key authorises your calls to Attendee, the Zoom credentials let Attendee into the meeting, and the Deepgram key turns the audio into text. A deployment missing any one of the three fails at a different stage, which is worth knowing when you are debugging a fresh install.

Running Attendee locally with Docker Compose

Attendee is designed for convenient self-hosting. It runs as a Django app in a single Docker image, and the only external services needed are Postgres and Redis. The README says that by self-hosting you can reduce costs by 10x compared to closed source vendors, which is the commercial argument for running it yourself.

The development mode instructions are a fixed sequence. The first step builds the image, which the README says takes about 5 minutes.

bash
docker compose -f dev.docker-compose.yaml build

Then you create the local environment variables, and the command differs by platform because of shell redirection. On Linux and Mac you redirect to a file.

bash
docker compose -f dev.docker-compose.yaml run --rm attendee-app-local python init_env.py > .env

On Windows the README uses Out-File with utf8 encoding instead. You then edit the .env file and enter your AWS information, which is where the object storage for recordings goes.

After that you start the services.

bash
docker compose -f dev.docker-compose.yaml up

The migrations run in a separate terminal tab once the services are up.

bash
docker compose -f dev.docker-compose.yaml exec attendee-app-local python manage.py migrate

Then you open localhost:8000 in the browser and create an account. The confirmation link is written to the server logs in the terminal where you ran the up command, in the form of an accounts/confirm-email path, and you paste it into the browser to confirm. After that you can log in and obtain an API key.

Where Attendee is the wrong choice

The first limitation is the Google Meet situation, and the README does not soften it. Google Meet provides no support at all, so using it means running a full instance of Google Meet in Chrome. That is a heavy, fragile arrangement for a production service, and it is the difference between a supported platform and a workaround.

The second is the Zoom SDK's own constraints leaking through. Per-participant audio streams are only available in the C++ variants of the SDK, so anything that needs to separate voices without relying on transcription has a hard boundary. And the Meeting SDK is a moving target, since Attendee pins a specific version of it in its requirements, zoom-meeting-sdk at 0.0.27, which tells you how tightly the two are coupled.

The third is the dependency count. The requirements file is long and includes Django 5.2.17, Celery, Redis, psycopg2, Django REST Framework, drf-spectacular, boto3 and django-storages for S3, opencv-python, selenium 4.27.1 and PyVirtualDisplay, aiortc, deepgram-sdk, stripe, kubernetes and the Google Cloud text to speech client. The Selenium and virtual display entries are what drive the Chrome-hosted Meet instance, and the Google client is what produces speech, so each one is a real operational dependency rather than a stray line.

The fourth is that a meeting bot joining a call is visible and can be refused. Attendee handles the technical side of joining, and it has to be handled with the consent of the people in the meeting, which is a policy question no API can answer for you.

The fifth is the licence. GitHub cannot classify the repository's licence, so the terms live in the LICENSE file and have to be read directly, and for a product that embeds a self-hosted Attendee that is a question for your own legal review.

Licence, release pace and what running Attendee costs you

The licence is one GitHub cannot classify, with the terms in the LICENSE file at the root of the repository. The README mentions no specific licence terms, so the file is the only source.

The repository is not archived and the last push was on 2026-10-22, so the project is actively maintained. The release pace is worth noting: v1.84.2 and v1.84.1 both shipped on 2026-10-19, and v1.84.0 on 2026-10-16. A version number in the eightieths with patch releases within hours of each other says the project is shipped continuously rather than in planned releases, which is what you want from a service that has to track third-party SDK changes, and which also means you should pin a version rather than track a branch.

The technology stack is visible in the files. It is a Django project with manage.py at the root and per-feature packages for accounts, attendee and bots. There is a Procfile and an heroku.yml, so Heroku deployment is a supported path alongside Docker, and a Dockerfile that starts from ubuntu:22.04 for the amd64 platform and installs build-essential, cmake, gfortran and libopencv-dev, which are the compilers and libraries the media stack needs.

The running cost is dominated by infrastructure rather than by Attendee itself. Postgres and Redis, storage for the recordings, Deepgram for transcription, and a browser instance for the Google Meet path. The README's ten-times cost claim is a claim about avoiding a closed-source vendor's per-minute pricing, and the cost of self-hosting is that you now operate the service.

Editorial conclusion

Attendee suits a product team that needs meeting transcripts and recordings in its own application and would rather run a service than sign up for a closed-source vendor, since the README claims self-hosting cuts cost by ten times. It does not suit a team without a Zoom developer account, because OAuth credentials for the Meeting SDK are a hard prerequisite. Verify the version you deploy against your own platform first, since the meeting SDK behaviour changes between Zoom releases, and note that Google Meet support is described as needing a full Meet instance running in Chrome.

Frequently asked questions

What does the Attendee API do?

It manages meeting bots on platforms like Zoom and Google Meet through a single REST API, handling the state and media streams, and returns the transcript and recording. The README says this can bring meeting transcripts and recordings into a product in days instead of months.

How do I create a bot with Attendee?

POST to the bots path with a meeting_url and a bot_name, authenticated with a Token header. The response gives you a bot id and a state of joining, and you then poll the bot by id until the state is ended and the transcription_state is complete, at which point you fetch the transcript.

What credentials does Attendee need?

Three. An Attendee API key from the API Keys section of the sidebar, Zoom app client id and secret with the Meeting SDK toggle enabled in the Zoom Marketplace, and a Deepgram API key for transcription, which the README says comes with 400 free hours and no credit card.

How do I run Attendee locally?

Build the Docker image with docker compose -f dev.docker-compose.yaml build, generate the .env with the init_env.py command, edit it with your AWS information, start the services, then run the migrations with manage.py migrate. Open localhost:8000 and create an account, confirming via the link written to the server logs.

Official sources

  1. attendee-labs/attendee on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/attendee-labs-attendee.svg)](https://hysenlabs.com/projects/attendee-labs-attendee)

Was this useful?