Open data
Download the record
Everything on this site, as files you can open in a spreadsheet or load into your own tools. They are rebuilt with the site every day; this copy is as of 4 November 2026. CSV files are UTF-8, comma-separated, with a header row; lists inside a cell are separated by "; ". Each JSON file carries the same notes as this page (source, AI labels, licence, columns) followed by its rows.
Two kinds of source, kept apart: the City's signed minutes (read in code, no AI) and AI drafts from the City's livestreams. Every AI-derived field is named as such in the notes, with the model; where a person checked or corrected something, a column says so. Check AI-drafted rows against the video link before you rely on them.
Licence. Our compilation (the selection, structure, transcripts, summaries and labels) is published underCC BY 4.0: reuse it freely, crediting "Said in Council" with a link to said-in-council.co.za. The City of Johannesburg's own documents and videos linked from these files remain the City's.
Council meetings (signed minutes)
From the minutes65 rows · 26 January 2023 to 20 March 2026
Each City of Johannesburg council meeting whose signed minutes this site has read: dates, the PDF, start times and how many votes and motions they record. Attendance, votes and motions join to it by minutes_id.
Source: The City of Johannesburg's signed council minutes (PDFs on joburg.org.za), read in code.
AI and checks: No AI. Everything is as printed in the minutes (blank where they don't say), except first_seen, the date this site first found the PDF online.
Columns (14)
- minutes_id
- Id of the minutes (the PDF's file name); attendance, votes and motions use it
- date
- First day of the meeting
- dates
- All days, space-separated
- meeting
- Meeting title as printed
- minutes_url
- The signed minutes (PDF) on joburg.org.za
- scheduled
- Start time printed in the header (per day when the days differ)
- commenced
- Actual start, when the minutes record a late one
- delay_reason
- The reason given for the late start
- present
- Names listed present
- on_leave
- Names listed on leave
- counted_votes
- Counted votes printed
- motions
- Motions listed
- scanned
- true when read from a scanned image with OCR
- first_seen
- Date this site first found the minutes online
Attendance per councillor per meeting
From the minutes17 124 rows · 26 January 2023 to 20 March 2026
Who was present, on leave or absent without leave at each City of Johannesburg council meeting, one row per councillor per meeting, from the City's signed minutes. The JSON groups the rows by meeting.
Source: The City of Johannesburg's signed council minutes (PDFs on joburg.org.za), read in code.
AI and checks: No AI. Present, leave, late and left early are as printed in the minutes. "absent" is never printed: this site infers it (on council before and after the meeting, no name in the minutes that could be them, no party-wide leave), and never from scanned minutes.
Columns (9)
- date
- First day of the meeting (YYYY-MM-DD)
- minutes_id
- The meeting; its title, PDF and dates are in the meetings dataset
- councillor_id
- This site's id; the councillor's page is /councillors/<id>/
- name
- Councillor's name (from the City's councillor list when matched, else as spelled in the minutes)
- party
- Party
- status
- present or leave (as printed), or absent (inferred by this site; see the AI note)
- leave_reason
- Reason for leave, as printed
- late
- Listed as arriving late (true/false)
- left_early
- Listed as leaving early (true/false)
The JSON has one row per meeting (minutes_id, date, meeting, minutes_url, scanned) with that meeting's rows in attendance.
Counted votes
From the minutes86 rows · 26 January 2023 to 20 March 2026
Every counted vote (for, against, abstain) printed in the City of Johannesburg's signed council minutes, with the parties recorded as dissenting.
Source: The City of Johannesburg's signed council minutes (PDFs on joburg.org.za), read in code.
AI and checks: No AI. Counts, outcome and dissent are as printed; outcome_from_count is true where the minutes print no outcome and this site took it from the count (more for than against).
Columns (14)
- date
- First day of the meeting
- minutes_id
- The meeting (see the meetings dataset)
- meeting
- Meeting title as printed
- item
- Agenda item, motion or section number, as printed
- title
- Heading above the vote
- for
- Votes for
- against
- Votes against
- abstain
- Abstentions (blank when no abstain line is printed)
- outcome
- carried or defeated
- outcome_from_count
- true when no outcome is printed and it was read from the count
- dissent
- Parties recorded as dissenting, separated by "; "
- page
- PDF page of the count
- minutes_url
- The minutes PDF, opened at that page
- scanned
- true when read from a scanned image with OCR
Motions
From the minutes108 rows · 26 January 2023 to 26 February 2026
Every motion listed in the MOTIONS section of the City of Johannesburg's signed council minutes, with its proposer and outcome.
Source: The City of Johannesburg's signed council minutes (PDFs on joburg.org.za), read in code.
AI and checks: No AI. Everything is as printed; blank where the minutes don't say.
Columns (11)
- date
- First day of the meeting
- minutes_id
- The meeting (see the meetings dataset)
- meeting
- Meeting title as printed
- item
- Agenda section number
- number
- Motion number, when numbered
- title
- Motion title
- mover
- The Proposer line as printed
- outcome
- adopted, rejected, withdrawn, deferred, referred or "not considered" (proposer absent); blank when not stated
- page
- PDF page
- minutes_url
- The minutes PDF, opened at that page
- scanned
- true when read from a scanned image with OCR
Promises and their deadlines
AI draft84 rows · 26 May 2026 to 30 September 2026
Commitments made in City of Johannesburg council sittings (a date, an amount or a "we will"), with the deadline read as a date, where each stands, later sittings that came back to it, City newsroom reports and matching rows in the City's official performance documents.
Source: AI draft from the City of Johannesburg's council livestreams on YouTube (@CityOfJoburgZA); follow-ups from later sittings and the City's newsroom; official-record matches from the City's SDBIP and JDA quarterly reports.
AI and checks: Every promise is an AI draft (Claude) from the transcript; quote is what was said and time links to it. due_by, latest_by and each follow-up's "by" say whether a field is an AI reading or judgment (with the model) or was checked or corrected by hand. reviewed is false until a person has checked the sitting. clock is counted on the as_of date.
Columns (26)
- id
- Promise id; its page is /promises/<id>/
- date
- Sitting date
- sitting_id
- Sitting day id
- time
- Time on the sitting-day timeline (h:mm:ss)
- video_url
- The moment on YouTube
- page_url
- The promise's page here
- speaker
- Who made it: the executive member when the promise can be tied to one, else the councillor, else as heard
- councillor_id
- This site's councillor id, when known
- office_or_party
- Their office(s) that day, or party
- speaker_as_heard
- The speaker as named in the transcript
- what
- What was promised (AI summary)
- quote
- What was said (transcript)
- deadline_as_said
- The deadline in the speaker's words
- amount
- Amount, as said
- due_date
- The deadline read as a date (YYYY-MM-DD; City financial year July-June), blank if none
- due_reading
- How the date was read
- due_by
- Whether that reading is AI, checked or corrected by hand
- clock
- overdue (date passed, nothing found saying done), soon (30 days), later, passed (date passed, said done), sitting (due same or next day), none
- clock_days
- Days overdue or until due, on the as_of date
- latest_status
- The newest word on it, from a later sitting or the City
- latest_date
- Date of that word
- latest_by
- AI judgment (model) or corrected by hand
- later_sittings
- Later sitting days that came back to it
- city_reports
- City newsroom articles about it
- official_matches
- Rows in the City's official documents matched to it
- reviewed
- true when a person has checked this sitting
The JSON rows have these fields plus the lists the CSV can only count: followups, city_reports and official_matches.
Sittings
AI draft10 rows · 26 May 2026 to 30 September 2026
Each published City of Johannesburg council sitting day: its livestream videos, a prose summary and counts of chapters, promises and decisions. The JSON nests each day's chapters.
Source: AI draft from the City of Johannesburg's council livestreams on YouTube (@CityOfJoburgZA).
AI and checks: summary and chapters are AI drafts (model named in summary_by and chapters_by); reviewed is false until a person has checked the sitting.
Columns (16)
- sitting_id
- Sitting day id; its page is /sittings/<id>/
- date
- Date (SAST)
- title
- Sitting name
- meeting
- Meeting as named by the City
- term
- Year the council was elected
- duration_seconds
- Length of the day's video
- videos
- YouTube videos, in order, space-separated
- chapters
- Number of chapters
- promises
- Number of promises
- decisions
- Number of decisions (AI-drafted from the video, not the minutes)
- summary
- Prose summary (AI draft)
- summary_by
- Model, and the check it passed
- chapters_by
- Model that drafted chapters, promises and decisions
- reviewed
- true when a person has checked it
- page_url
- Its page here
- transcript_url
- Its full transcript (JSON)
The JSON rows have these fields plus each day's chapters (as in the chapters dataset).
Chapters
AI draft440 rows · 26 May 2026 to 30 September 2026
Every chapter of every published sitting day: start time, title, summary and who spoke, linked to the second of video.
Source: AI draft from the City of Johannesburg's council livestreams on YouTube (@CityOfJoburgZA).
AI and checks: Title, summary and speakers are AI drafts (Claude). A speaker is named only from the councillor list or office holders with a quote from the transcript as evidence; otherwise "Unidentified councillor".
Columns (10)
- sitting_id
- Sitting day id
- date
- Sitting date
- index
- Chapter number in the day, from 0
- start
- Start on the sitting-day timeline (h:mm:ss)
- video_url
- The start on YouTube
- page_url
- The chapter on its sitting page here
- title
- Title (AI draft)
- summary
- Summary (AI draft)
- speakers
- Who spoke, "Name (Party)", separated by "; "
- councillor_ids
- This site's id for each speaker in the same order (blank when not matched), separated by "; "
Money decisions
AI draft53 rows · 31 October 2023 to 30 September 2026
Rand amounts City of Johannesburg council decided on (loans, budgets, transfers and the like), from the signed minutes and from the sitting videos, kept apart by source_type.
Source: The City of Johannesburg's signed council minutes (PDFs on joburg.org.za), read in code (pages around money items read by AI); AI draft from the City of Johannesburg's council livestreams on YouTube (@CityOfJoburgZA).
AI and checks: Every row is AI-extracted (model in "by"); a row is kept only when its quote was found in the minutes page or transcript. Votes from the minutes are as printed. Rows a person rejected are left out; corrected rows say so in "by".
Columns (15)
- date
- Meeting or sitting date
- source_type
- minutes (signed minutes) or transcript (sitting video)
- where
- The meeting
- item
- Agenda item
- what
- What the money is for (AI summary)
- amount
- Amount as printed or said
- rands
- Amount in rand, as a number
- kind
- Kind of decision
- outcome
- Outcome
- for
- Votes for, when counted
- against
- Votes against, when counted
- abstain
- Abstentions, when counted
- quote
- The words in the source
- url
- The minutes page (PDF) or the moment on YouTube
- by
- AI draft (model) or corrected by hand
Party positions on items
AI draft646 rows · 26 May 2026 to 30 September 2026
Where parties said they stood (for, against, abstain) on items in City of Johannesburg council sittings, one row per party per item, from the sitting videos. Parties recorded as dissenting in the signed minutes are in the votes dataset's dissent column.
Source: AI draft from the City of Johannesburg's council livestreams on YouTube (@CityOfJoburgZA).
AI and checks: AI draft (model in "by"): each position is kept only when its quote was found in the transcript and names the party. Positions a person rejected are left out.
Columns (13)
- date
- Sitting date
- sitting_id
- Sitting day id
- item
- Agenda item
- title
- Item title
- method
- How it was decided (voice, count, ...)
- outcome
- Outcome
- party
- Party
- side
- for, against or abstain, as stated
- kind
- How the position was stated
- quote
- What was said
- time
- Time on the sitting-day timeline
- video_url
- The moment on YouTube
- by
- AI draft (model)
Transcripts
AI draft10 sitting days · 26 May 2026 to 30 September 2026
Every line of each published sitting day, one JSON file per day. Each line has start and end (seconds on the day's timeline: its videos laid end to end, listed in the file with their YouTube links), the video it is in, the language when it isn't English, and the text. Speakers are not in the transcript; they are in the chapters dataset.
Source: AI draft from the City of Johannesburg's council livestreams on YouTube (@CityOfJoburgZA). AI and checks: machine transcription (model named in each file), not checked line by line; names and non-English speech are the weak points.
- 55th Extra-Ordinary Council Meeting30 September 2026 · 610 kB
- 39th Ordinary Council Meeting, Day 227 August 2026 · 170 kB
- 54th Extra-Ordinary Council Meeting27 August 2026 · 23 kB
- 39th Ordinary Council Meeting, Day 126 August 2026 · 409 kB
- 53rd Extra-Ordinary Council Meeting30 July 2026 · 70 kB
- 52nd Extra-Ordinary Council Meeting22 July 2026 · 311 kB
- 38th Ordinary Council Meeting, Day 225 June 2026 · 348 kB
- 38th Ordinary Council Meeting, Day 124 June 2026 · 300 kB
- Budget Debate28 May 2026 · 261 kB
- 51st Extra-Ordinary Council Meeting26 May 2026 · 40 kB
Not included: anyone's contact details (never collected), the audio, and drafts or pairs a person rejected. Want something on a page in your own story instead? Promise, councillor and sitting pages have an "Embed this" card.