Decode a Council hearing yourself

A NYC Council hearing is public, but it is hours of video. This guide shows how to turn one into a transcript that says who spoke, when, and about what. It is the process BetaNYC used for the October 16, 2026 hearing on AI, built on what we learned doing the October 5 hearing by hand. The method is open. Take it, use it, and tell us what to fix. BetaNYC's transcripts are our independent record, not the Council's official transcript.

What you need

FreeThe Council's own records: the hearing page, agenda, committee report, video and captions. Our scripts are free too. They need Python 3.11 to 3.14 and ffmpeg.
Maybe paidA speech-to-text service that can tell voices apart. BetaNYC used Deepgram, which charges by the length of the audio. We also tried a free tool on our own computer (Whisper). On long stretches of the October 5 hearing it got stuck repeating phrases.
JudgmentNaming voices, cleaning the text, and checking names against sources. This is where most of the work goes. At BetaNYC, AI assistants did it at our direction, and our pages say so.

The steps

  1. Pick a hearing and get its papers

    free

    Find the hearing on the Council's Legistar calendar. Download the agenda and the committee report. The report usually names who was invited to testify. Come back a day or two later. Written testimony is often posted after the hearing.

    Our script for this: fetch_legistar.py (needs a Legistar API token, which you ask the Council for).

  2. Get the video and the Council's captions

    free

    The video link appears on the hearing page once the hearing is over. Keep the Council's captions too. They are rough, but they are a second witness to what was said.

    Our script for this: fetch_media.py (video, captions and small audio files).

  3. Make a short word list

    judgment

    Write down this hearing's names: Council Members, witnesses, groups, and the products or terms that keep coming up. Take them only from the hearing's own papers. Speech-to-text gets names wrong, and a short list helps it get them right.

    What we learned: a general list can backfire. Our list of BetaNYC names turned a witness's self-introduction into a BetaNYC staff member's name. We paid to transcribe October 16 twice because of it. Keep the list to this one hearing.

    How we build the list

  4. Run speech-to-text that separates voices

    Send the audio to a service that does "diarization," meaning it splits the audio by voice: "speaker 1, speaker 2." You get words and times, but no names yet. Save the full response so you never pay for the same run twice.

    What we learned: "speaker 3" is a guess about a voice, not a person. On October 5, the service lumped different voices under one number, and a voice we took for one Council Member was another. Name each turn from what is said in it.

    What we sent Deepgram: scripts/README.md, section 3.

  5. Put names on the voices

    AI + sources

    Who is "speaker 3"? Look for clues: people saying their own names, the chair calling on someone, the oath, Zoom name tiles, and the Council's captions. (At our two hearings, the Council's on-screen banner showed only the Speaker.) An AI assistant can do the first pass if you give it the hearing's papers. Then check each name against a source in step 8.

    What we learned: read names off the screen, not off the transcript. Grab a still frame of the video, enlarge it, and copy the spelling you see.

    Our speaker-naming prompt

  6. Mark the parts of the hearing

    judgment

    Most hearings have parts: opening statements, the City's panel, invited witnesses, then the public. Write down when each part starts and ends. This is what lets you see who got the floor, and for how long.

    Example: who spoke, panel by panel, October 16

  7. Clean it up, carefully

    AI + sources

    Take out "um"s, stutters and false starts. Fix spelling. Keep each speaker's grammar as they said it. Never change a time or a name. Keep the unedited version next to the clean one, so anyone can compare.

    What we learned: a word that sounds better is not always right. We undid four edits, like "lunch" to "launch," because neither Deepgram nor the Council's captions supported them. An edit that changes meaning needs a second source.

    Our clean-up prompt · our checker: validate_clean.py

  8. Check every name against a public source

    AI + sources

    Check each person's name and group against the Council's records, posted testimony, or the group's own website. Write down where you checked. If you can't confirm it, say so on the page.

    Say who did the checking, too. For October 16, an AI assistant checked names against public sources. Elected officials were checked against the Council's records. Our pages say that other names were not each verified by a person.

    What we learned: never publish a guess about a private person. We had guessed one witness's law firm from a garbled word. The guess was right, but it stayed off the page until a public source confirmed it.
  9. Count and picture it

    free

    Now you can count. Count each speaker's talk time. Draw a timeline of the parts of the hearing. Make word clouds of the phrases each group used more than everyone else.

    What we learned: talk time is approximate. Some turns hold more than one voice, like a question and the start of its answer. On October 16, the two longest speakers swap places if you leave those turns out. Mark those turns, and round your numbers. If you remove words from a word cloud by hand, say so and publish the list.

    Our scripts: build_hearing.py, build_panels.py, build_wordclouds.py · example: October 16 word clouds

  10. Get two reviews, then look at every page

    judgment

    One reviewer reads the code and the pages as a stranger would, looking for what breaks. Another checks every name, number and claim against its source. Fix, then send it back to both, until both say it is ready. Then open every page in a browser yourself.

  11. Publish, save a copy, and take corrections

    free

    Put the pages online. GitHub Pages is free. Save the video to the Internet Archive (free, with an account) so it outlasts any one website. We put the full-quality audio in a GitHub Release. Check that you may re-host the video; our license covers only what we made. Always link back to the Council's official video, and say plainly that yours is not the Council's official transcript. Give every page a way to report a mistake, and fix the inputs, not the finished page.

    What we learned: plan for the slow parts. Written testimony posts days later. The Internet Archive can take hours or days to make a video playable; our October 16 copy was still processing that night. Until it plays, keep the Council's video as the main link.

Four rules we work by

The video is the record

A transcript helps you find a moment. Quote from the video, after you check it.

Machines count, sources decide

Scripts handle times, counts and checks. A name or an edit that changes meaning needs a source, and the page says who checked it: a person or an AI assistant.

Show your work

Publish the unedited transcript next to the clean one, the word list you sent the speech-to-text service, and where your names came from.

Say what you don't know

A missing surname or an unconfirmed group gets a note on the page, not a guess.

Take it and use it

Full checklist with every command: docs/PIPELINE.md

Finished transcripts to learn from: betanyc.github.io/hearings-transcripts

The whole process on one page: how we turn a hearing into an open transcript

The code is MIT licensed, and the transcripts and data BetaNYC made are CC BY 4.0. The Council's video and captions are the Council's. Spot a mistake, or decoded a hearing of your own? Open an issue.

BetaNYC · Prepared 2026-10-19. Two things are not public: the script that sends audio to Deepgram, which lives in BetaNYC's private workspace, and our raw working files (the Deepgram output and speaker labels). scripts/README.md describes the Deepgram request, so you can make it yourself. You can check our transcripts against the Council's video, but you can't rerun our hearings from scratch.