Skip to main content

msteams-transcripts

Download Microsoft Teams meeting transcripts from the command line, including the meetings where the Download button is greyed out.

It drives a browser you are already signed in to, so it needs no admin consent, no app registration and no Graph permissions, and it reaches exactly the meetings you can open yourself. Anything you can read in the Recap tab, this can save to a file.

uvx msteams-transcripts browser
uvx msteams-transcripts list --from 2026-09-01 --to today
uvx msteams-transcripts get 3 --details

Why the Download button being disabled does not matter

  • Listing meetings. The Teams web client loads your calendar from its middle-tier API. Each online meeting carries a thread identifier.
  • Finding the transcript. The Recap tab asks the meeting-content service about that thread. The reply lists resources; a transcript resource holds the OneDrive drive, item and transcript identifiers.
  • Reading the transcript. The recap page renders it from SharePoint, at /_api/v2.1/drives/<driveId>/items/<itemId>/media/transcripts/<id>/content, in JSON or WebVTT. That call is authenticated by your SharePoint cookies alone. The whole transcript is already delivered to your browser in one request, so no scrolling or scraping is involved. The disabled button is a user-interface policy, not an access control.
  • Tokens. The two Teams APIs want bearer tokens that the web client keeps encrypted in local storage. The tool captures them from the requests the Teams tab makes as it loads.

Install

With uv, nothing to install:

uvx msteams-transcripts --help

Or install it permanently:

uv tool install msteams-transcripts     # or: pipx install msteams-transcripts
pip install msteams-transcripts         # into the current environment

Both msteams-transcripts and the shorter teams-transcripts are installed as commands. Python 3.10 or newer is required. Playwright comes as a dependency, but do not run playwright install: the tool attaches to the Edge or Chrome already on your machine and downloads no browsers of its own.

Walkthrough

A first session from a clean machine, start to finish.

1. Start the browser.

uvx msteams-transcripts browser

An Edge window opens on Teams using a profile of its own. On a corporate, Entra-joined PC it usually signs in by itself. If a sign-in page appears, complete it there once. Leave the window open; you can minimise it. Recent Edge and Chrome refuse remote debugging on your everyday profile, which is why a separate one is used.

2. See what is available.

uvx msteams-transcripts list --from 2026-09-01 --to today
  #  Start (UTC)       Subject                                            Organizer
  1  2026-09-15 05:41  Weekly one to one                                  Priya Raman
  2  2026-09-15 06:09  Platform team sync                                 Tomas Lindqvist
  3  2026-09-16 09:02  Architecture review: storage tiering               Maya Okonkwo
12 transcript(s). Use:  msteams-transcripts get <#>

The first run takes 30 to 60 seconds while Teams loads and issues its tokens; later runs in the same browser session are quicker. Rows are transcripts rather than meetings, so a recurring meeting recorded twice appears twice.

3. Download one transcript with the meeting details.

uvx msteams-transcripts get 3 --details

This writes transcripts\2026-09-16 0902 - Architecture review storage tiering.txt:

# Architecture review: storage tiering
# Date: 2026-09-16 09:02
# Source: https://contoso-my.sharepoint.com/personal/.../Recordings/Architecture-review....mp4
# Organizer: Maya Okonkwo <maya.okonkwo@example.com>
# Location: Microsoft Teams Meeting
# Invited (13):
#   Priya Raman <priya.raman@example.com> (Required, Accepted)
#   Tomas Lindqvist <tomas.lindqvist@example.com> (Required, Tentative)
#   ...
# Speakers in transcript (5):
#   Priya Raman (84 segments)
#   Maya Okonkwo (72 segments)
#   ...
# Files shared in meeting chat (1):
#   capacity-plan.xlsx  https://contoso.sharepoint.com/sites/...
# Invitation text:
#   Agenda: ...

[00:00:03] Priya Raman:
    Good morning everyone, let's start with the architecture review.

A sidecar ...meta.json holds the same details as structured data: attendees with response status, speakers with segment counts, shared files, invitation text and the thread identifier.

4. Download from a link instead. Open the meeting in Teams, go to the Recap tab, copy the address bar, and pass it:

uvx msteams-transcripts get "https://teams.cloud.microsoft/l/meetingrecap?driveId=...&driveItemId=...&sitePath=..." --details -f all

This path does not touch the calendar and finishes in a few seconds.

5. Archive a whole period.

uvx msteams-transcripts batch --from 2026-09-01 --to 2026-09-30 --details -o C:\Archive\teams
uvx msteams-transcripts batch --from 2026-09-01 --to 2026-09-30 --only 3,7,12

Files with the same name are overwritten. Batch ends with a count of what was downloaded and what failed.

6. Skipping the "Stay better connected with the Teams desktop app" popup when you open recap links yourself: change /l/meetingrecap? in the address to /_#/l/meetingrecap?. That form opens the web client directly. The tool already uses it internally.

Commands

msteams-transcripts browser
msteams-transcripts list  --from YYYY-MM-DD --to YYYY-MM-DD|today [--json]
msteams-transcripts get   <row#|recap-url|thread-id> [-d] [-f txt|json|vtt|all] [-o DIR]
msteams-transcripts batch --from D --to D [-d] [-f FMT] [-o DIR] [--only 3,7,12]
Option Meaning
-d, --details organizer, location, invited attendees with response status, speakers, shared files, invitation text, plus a .meta.json sidecar
-f, --format txt (default), json for the raw Stream document, vtt for WebVTT, or all
-o, --out output directory, ./transcripts by default
--json on list, print the rows as JSON for scripting
--only on batch, restrict to given row numbers
--port, --profile, --browser override the debugging port, profile directory or browser executable

The text format is:

[00:00:03] Speaker Name:
    what they said
    the next sentence by the same speaker

Timestamps are offsets from the start of the recording, not wall-clock time. Row numbers used by get N come from the most recent list, cached in ~/.teams_transcripts/last_list.json.

Using it from an agent

.claude/skills/teams-transcripts/SKILL.md describes the tool for Claude Code or another agent: preconditions, commands, output format, typical flows and error handling. Claude Code picks it up automatically when working in this project.

Library use

import asyncio
from pathlib import Path
from teams_transcripts import TeamsSession, download_ref, refs_from_recap_url

async def main():
    async with TeamsSession() as s:
        ref = refs_from_recap_url("https://teams.cloud.microsoft/l/meetingrecap?...")
        await download_ref(s, ref, Path("out"), "txt", details=True)

asyncio.run(main())

Anything the user can act on raises TranscriptError.

Environment variables

Variable Default Purpose
TT_CDP_PORT 9222 browser debugging port
TT_PROFILE_DIR platform application-data directory browser profile
TT_BROWSER_EXE Edge, then Chrome, from the usual locations browser executable
TT_STATE_DIR ~/.teams_transcripts where the last listing is cached

Troubleshooting

  • "The browser did not expose its debugging port": another window is already using the dedicated profile without the port. Close it, then run browser again.
  • "Could not capture a Teams token": the Teams tab in that window is not signed in. Sign in there, then retry.
  • "Could not capture the meeting-content token": open any meeting's Recap tab in that window, then retry.
  • HTTP 403 when listing or downloading: the recording belongs to a tenant or site you cannot read. The Recap tab would be empty for you too.
  • Not available through this tool: the attendance report of who actually joined and when, collaborative Loop notes, and Copilot AI notes. --details gives the invited list from the calendar and who actually spoke per the transcript.
  • Recurring meetings share one thread identifier. Each occurrence's transcript is listed separately with its own start time.

Development

git clone https://github.com/divyavanmahajan/msteams-transcripts
cd msteams-transcripts
pip install -e ".[dev]"
python -m pytest

The tests cover the pure functions in model.py and formats.py and need neither a browser nor the network.

Hatchling owns the version, read from __version__ in src/teams_transcripts/__init__.py. To release:

hatch version patch            # or minor, major, or an explicit 1.2.3
git commit -am "Release 0.1.1"
git tag v0.1.1
git push --follow-tags

Pushing the tag runs .github/workflows/publish.yml, which refuses to continue if the tag and the package version disagree, then builds, publishes to PyPI through trusted publishing and creates a GitHub release. Trusted publishing is configured once on PyPI under Publishing, naming this repository, the publish.yml workflow and the pypi environment; no API token is stored. Running the workflow by hand offers TestPyPI as the target.

Licence

MIT. Transcripts are meeting content belonging to the people in them; this tool only fetches what you already have access to, and what you do with it afterwards is your responsibility.

Download files

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

Source Distribution

msteams_transcripts-1.0.0.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

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

msteams_transcripts-1.0.0-py3-none-any.whl (25.2 kB view details)

Uploaded Python 3

File details

Details for the file msteams_transcripts-1.0.0.tar.gz.

File metadata

  • Download URL: msteams_transcripts-1.0.0.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for msteams_transcripts-1.0.0.tar.gz
Algorithm Hash digest
SHA256 684dd078025113e82ca3556e0bad2d068eb977b3048580771910270530dcddc6
MD5 0fa359d3f6ab5eaf043c576b024431d3
BLAKE2b-256 9bfba5a13822913f5ed14253d9d1865286a3aa82b21769a4ff824b0a3df5de88

See more details on using hashes here.

Provenance

The following attestation bundles were made for msteams_transcripts-1.0.0.tar.gz:

Publisher: publish.yml on divyavanmahajan/msteams-transcripts

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

File details

Details for the file msteams_transcripts-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for msteams_transcripts-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bc290a9806e04d6f6a2ff75083e32f143cc02b7274cfa8dc0a740a9d249c5a72
MD5 711b72363c21bbcf26955b09179927a6
BLAKE2b-256 cbfddc6e97876c70d8ac2cd485b1c3a32cd7a1f882a9d20979038a4578b96e1b

See more details on using hashes here.

Provenance

The following attestation bundles were made for msteams_transcripts-1.0.0-py3-none-any.whl:

Publisher: publish.yml on divyavanmahajan/msteams-transcripts

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

Release history Release notifications | RSS feed

1.0.1

2 files

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page