meeto
Open-source Google Meet bot. Join meetings, capture audio, and transcribe in real time using Playwright and pluggable STT providers.
Installation
pip install meeto
playwright install chromium
Quick Start
The simplest way to use meeto is guest mode — no Google account needed. The bot joins the meeting as a guest and waits for the host to admit it.
import asyncio
from meeto import run_meeting_worker
from meeto.config import WorkerConfig, JoinConfig, SttConfig
config = WorkerConfig(
meeting_id="my-meeting-001",
meet_url="https://meet.google.com/abc-defg-hij",
join=JoinConfig(
bot_name="Meeto Bot",
),
stt=SttConfig(
provider="deepgram",
api_key="YOUR_DEEPGRAM_API_KEY",
),
)
asyncio.run(run_meeting_worker(config))
Or via the CLI example:
PYTHONPATH=src python scripts/example.py https://meet.google.com/abc-defg-hij --bot-name "Meeto Bot" --no-headless
Audio dumps are saved to ./audio/ and transcripts to ./transcripts/ by default.
Note: Guest mode requires a display — see Deployment for running on servers and containers.
Authenticated Mode
To join meetings as a Google account (no waiting room), generate a browser session first:
meeto-auth --output storage_state.json
This opens a Chromium window. Log in to Google, then press Enter in the terminal.
config = WorkerConfig(
meeting_id="my-meeting-001",
meet_url="https://meet.google.com/abc-defg-hij",
duration_seconds=3600,
join=JoinConfig(
headless=True,
storage_state_path="storage_state.json",
),
stt=SttConfig(
provider="deepgram",
api_key="YOUR_DEEPGRAM_API_KEY",
),
)
asyncio.run(run_meeting_worker(config))
Deployment
Guest Mode on Servers / Containers
Google blocks headless browsers from joining meetings via server-side bot detection. To run guest mode in a headless environment, use Xvfb to provide a virtual display. meeto automatically detects the DISPLAY environment variable and switches to headed mode.
Quick option — wrap your process with xvfb-run:
apt-get install -y xvfb
xvfb-run python your_bot_script.py
Docker — start Xvfb in your entrypoint:
RUN apt-get update && apt-get install -y xvfb
ENV DISPLAY=:99
#!/bin/bash
Xvfb :99 -screen 0 1920x1080x24 &
sleep 1
exec python your_bot_script.py
Authenticated Mode on Servers / Containers
Authenticated mode uses a saved Google session (storage_state.json), which Google trusts as a real user. This means it works with headless=True out of the box — no Xvfb, no virtual display, no extra system dependencies.
config = WorkerConfig(
meeting_id="my-meeting-001",
meet_url="https://meet.google.com/abc-defg-hij",
join=JoinConfig(
headless=True,
storage_state_path="storage_state.json",
),
)
Generate storage_state.json once on a machine with a display (your laptop), then copy it to the server or bake it into your deployment secrets.
Environment Variable Config
For container/job deployments, build config from env vars:
from meeto.config import worker_config_from_env
config = worker_config_from_env()
Required: MEETING_ID, MEET_URL. See meeto/config/env_config.py for the full list.
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
meeting_id |
str |
required | Unique identifier for the meeting |
meet_url |
str |
required | Google Meet URL |
duration_seconds |
int |
3600 |
Max recording duration |
audio |
AudioConfig |
defaults | Audio capture settings |
stt |
SttConfig |
defaults | Speech-to-text settings |
join |
JoinConfig |
defaults | Browser join settings |
Extending
Custom Storage Adapter
By default, artifacts stay local. To upload to cloud storage (S3, GCS, etc.), implement ArtifactStorageAdapter:
from meeto.storage import ArtifactStorageAdapter
class S3StorageAdapter(ArtifactStorageAdapter):
def upload(self, local_path, content_type="application/octet-stream"):
return f"s3://my-bucket/{local_path}"
asyncio.run(run_meeting_worker(config, storage_adapter=S3StorageAdapter()))
Custom Meeting State Store
By default, meeting lifecycle state is kept in memory. To persist state (e.g. to a database), implement MeetingLifecycleStore:
from meeto.state_store import MeetingLifecycleStore
class PostgresMeetingStore(MeetingLifecycleStore):
def update_status(self, meeting_id, *, status, ended_at=None, transcription_path=None):
...
def heartbeat(self, meeting_id):
...
asyncio.run(run_meeting_worker(config, state_store=PostgresMeetingStore()))
Custom STT Provider
Meeto ships with Deepgram support. To add your own STT provider, implement STTStreamingAdapter:
from meeto.stt import STTStreamingAdapter, register_stt
class MySTTAdapter(STTStreamingAdapter):
async def connect(self): ...
async def send_audio(self, pcm_bytes): ...
async def start(self, on_segment): ...
async def close(self): ...
register_stt("my_provider", MySTTAdapter)
Then set SttConfig(provider="my_provider").
Logging
meeto uses Python's standard logging module and does not configure any handlers itself. To see logs, configure logging in your application:
import logging
logging.basicConfig(level=logging.INFO)
For finer control:
logging.getLogger("meeto").setLevel(logging.DEBUG) # all meeto logs
logging.getLogger("meeto.stt").setLevel(logging.WARNING) # quieter STT logs
Architecture
meeto/
├── runtime.py # Main entrypoint: run_meeting_worker()
├── pipeline.py # Wires audio capture, STT, and transcript writing
├── storage.py # ArtifactStorageAdapter ABC + LocalStorageAdapter
├── audio_writer.py # PCM audio dump writer
├── transcript_writer.py # JSONL transcript writer
├── auth/ # Google login session generator
├── config/ # Typed config models + env var parser
├── meet/ # Playwright-based meeting join, end detection, speaker tracking
├── state_store/ # Meeting lifecycle state management
└── stt/ # STT adapter interface + Deepgram implementation
Contributing
See CONTRIBUTING.md for setup, code style, and PR guidelines.
License
MIT
Metadata
Release files for meeto 0.3.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| meeto-0.3.3.tar.gz | 33.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| meeto-0.3.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 73.5 kB
Release files / meeto-0.3.3.tar.gz
| Download URL | meeto-0.3.3.tar.gz |
|---|---|
| Size | 33.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b646ec14b46c01e07f50b1ff7a1b88a696ed3895b6ee4b6e1996b103096ee84d
|
|
BLAKE2b-256 checksum How to use checksums |
2698e8582d5c39530f0891419ecc0093bfe054cc1cb9725afd509dd13a7c31ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 13, 2026.
Transparency logRelease files / meeto-0.3.3-py3-none-any.whl
| Download URL | meeto-0.3.3-py3-none-any.whl |
|---|---|
| Size | 40.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9a643a3fb6e6e6063cf8796cfb81b0b57c5796ad510f973ead8f78abc9c21681
|
|
BLAKE2b-256 checksum How to use checksums |
fef4735d403a37bc6387fd49a93046bb425548ec741be4274f45f9f8603d6661
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 13, 2026.
Transparency logSecurity for meeto 0.3.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for meeto-0.3.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.