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.3.tar.gz (33.3 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.3-py3-none-any.whl (40.2 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for meeto-0.3.3.tar.gz
Algorithm Hash digest
SHA256 b646ec14b46c01e07f50b1ff7a1b88a696ed3895b6ee4b6e1996b103096ee84d
MD5 0aa2c4d049ffa17c9613bedba9647e1d
BLAKE2b-256 2698e8582d5c39530f0891419ecc0093bfe054cc1cb9725afd509dd13a7c31ec

See more details on using hashes here.

Provenance

The following attestation bundles were made for meeto-0.3.3.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.3-py3-none-any.whl.

File metadata

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

File hashes

Hashes for meeto-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 9a643a3fb6e6e6063cf8796cfb81b0b57c5796ad510f973ead8f78abc9c21681
MD5 5e76c5de21ed0ecf6757ff1f0751f4fb
BLAKE2b-256 fef4735d403a37bc6387fd49a93046bb425548ec741be4274f45f9f8603d6661

See more details on using hashes here.

Provenance

The following attestation bundles were made for meeto-0.3.3-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