Skip to main content

Google Meet bot for meeting transcription, recording, and speech-to-text. Join meetings automatically, capture audio, and transcribe in real time with speaker attribution.

Project description

meeto

CI PyPI Python License: MIT

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

meeto-0.3.2.tar.gz (31.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

meeto-0.3.2-py3-none-any.whl (35.7 kB view details)

Uploaded Python 3

File details

Details for the file meeto-0.3.2.tar.gz.

File metadata

  • Download URL: meeto-0.3.2.tar.gz
  • Upload date:
  • Size: 31.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for meeto-0.3.2.tar.gz
Algorithm Hash digest
SHA256 dd5f2608add926f0574ac72a5e5ce1c5a498dd295ff749e0f28b3a184f2628a6
MD5 dc074046c50a05460e1776ea21ccaee0
BLAKE2b-256 956977117ab7da2bbad8811b66be417c7262f7f6669ca6b828cc3f3cf3a88e04

See more details on using hashes here.

Provenance

The following attestation bundles were made for meeto-0.3.2.tar.gz:

Publisher: release.yml on ResearchifyLabs/meeto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file meeto-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: meeto-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 35.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for meeto-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6c1d6afa1c5d07c7b7b00d6fae2f8c1fed71d73a2071d48cf83b834563a9bb19
MD5 2448b249a5bd2ef325637d8bc8fc3201
BLAKE2b-256 6f02133d59db4b28d9a59494165023e1432437b9177d3db878fb3ebdd99d4db5

See more details on using hashes here.

Provenance

The following attestation bundles were made for meeto-0.3.2-py3-none-any.whl:

Publisher: release.yml on ResearchifyLabs/meeto

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page