# Legistar Agendas, Legislation & Votes Scraper (`talcoe/legistar-agendas`) Actor

Scrape meetings, agenda items, legislation and roll call votes from any public Legistar city or county portal, with filters for city, date window and keywords, priced per result.

- **URL**: https://apify.com/talcoe/legistar-agendas.md
- **Developed by:** [M Usama](https://apify.com/talcoe) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Legistar Agendas, Legislation & Votes Scraper do?

It pulls meetings, agenda items, legislation and roll call votes from city and county portals hosted on Granicus Legistar. Pick one or more cities, a date window and optional keywords, and get clean JSON, CSV or Excel with meeting date, body, agenda item title, file number, action taken, result, attachment links and a link back to the official meeting page. Filters keep runs small, and pricing is per result.

### Data source

The Actor reads the public Legistar Web API (`webapi.legistar.com`), the same JSON service that powers each city's `*.legistar.com` portal, so the data is as fresh as the city's own site.

### Why use it?

- Monitor zoning, permits, contracts, cannabis, short term rental or any other topic across many councils at once with keyword filters.
- Find business leads: contract approvals, RFP awards and licensing items mention vendors and dollar amounts before they reach the news.
- Track how each council member voted on a bill (roll call votes where the city records them).
- Replace manual portal browsing, PDF agenda downloads and brittle one off scrapers.

### How to use it

1. Open the Actor and set the filters.
2. Click Start. Download results as JSON, CSV or Excel, or read them through the API.
3. Add a Schedule and an Integration (Slack, Google Sheets, webhook) to get new records automatically.

### Input

| Field | Description |
|---|---|
| `clients` | Legistar client slugs, the first part of the portal address (`denver` for denver.legistar.com). Tested: denver, seattle, lacounty, boston, phoenix. |
| `recordType` | `agendaItems` (one record per agenda item), `meetings` (one per meeting) or `matters` (legislation such as ordinances, resolutions and appointments). |
| `keywords` | Keep only records matching any keyword (case insensitive). Matched against item title, file number, type and action for agenda items, body and location for meetings, and title for legislation. |
| `daysBack` | Include meetings (or legislation introduced) from this many days ago. Default 14. |
| `daysAhead` | Include meetings scheduled this many days ahead. Default 14. |
| `includeVotes` | Agenda items only. Adds each member's vote on acted on items. Slower, one extra request per item. |
| `maxResults` | Hard stop for the run. You are billed per result, so this caps the cost. |
| `proxyConfiguration` | Apify proxy is recommended for larger runs. |

Example input:

```json
{
    "clients": ["denver", "seattle"],
    "recordType": "agendaItems",
    "keywords": ["zoning", "contract"],
    "daysBack": 14,
    "daysAhead": 14,
    "maxResults": 100
}
```

### Output

Agenda item record (trimmed):

```json
{
    "id": "denver:item:238360",
    "client": "denver",
    "meetingId": 12969,
    "body": "Community Planning and Housing",
    "meetingDate": "2026-09-29T13:30:00",
    "title": "Approves the landmark designation application for 740 N. Washington St - The Stonehouse, in Council District 7.",
    "matterFile": "26-1405",
    "matterType": "Bill",
    "matterStatus": "Approved for Filing",
    "action": "approved for filing",
    "result": "Pass",
    "mover": "Amanda Sawyer",
    "seconder": "Flor Alvidrez",
    "votes": [
        { "person": "Flor Alvidrez", "vote": "Aye" },
        { "person": "Paul Kashmann", "vote": "Absent" }
    ],
    "consent": false,
    "attachments": [
        { "name": "740WashingtonSt_designation_CPH_staffreport.pdf", "url": "https://denver.legistar1.com/denver/attachments/4f99599f-2250-4210-b886-2fd7f8da6234.pdf" }
    ],
    "meetingUrl": "https://denver.legistar.com/MeetingDetail.aspx?LEGID=12969&GID=655",
    "scrapedAt": "2026-10-02T08:25:20.522Z"
}
```

| Field | Meaning |
|---|---|
| `id` | Stable key (`client:type:sourceId`), safe for deduplication between runs |
| `meetingDate` | Local meeting date and time in ISO format, no timezone offset (the city's local time) |
| `matterFile` | The legislation file number the item refers to |
| `action`, `result`, `tally` | What the body did and the outcome, when recorded |
| `votes` | Per member votes, only with `includeVotes` and only where the city records them |
| `attachments` | Staff reports, ordinances and exhibits linked to the item |

Meeting records add `agendaStatus`, `minutesStatus`, `location`, `agendaUrl`, `minutesUrl` and `videoUrl`. Legislation records add `file`, `type`, `status`, `introDate`, `agendaDate`, `passedDate`, `enactmentDate`, `enactmentNumber` and `requester`.

### Pricing

Pay per event: a small fee when a run starts, then a fixed price per result returned. You only pay for records that pass your filters. Set `maxResults` to cap any run.

### Limitations

- Only clients whose Legistar API is open to anonymous requests work. Some cities (for example New York City) require a private token and return no data. Others such as Chicago, Austin and San Francisco do not expose the API publicly.
- Vote detail and agenda item actions depend on what each city enters. Some cities record no roll calls.
- Legislation (`matters`) is filtered by introduction date and, with keywords, by title.
- Dates are the city's local time without a timezone offset.

### FAQ

**Is this legal?** The Actor reads data the cities publish for any visitor without a login. You are responsible for how you use the data.

**How do I find a city's client slug?** Look at the portal address: `https://denver.legistar.com` means the slug is `denver`.

**Something is missing or broken?** Open an issue in the Issues tab; response time is usually under a day.

# Actor input Schema

## `clients` (type: `array`):

Legistar client slugs, the first part of the portal address (denver for denver.legistar.com). Public clients such as denver, seattle, lacounty, boston and phoenix work. A few clients (nyc, chicago, austin) require a private token and return no data.

## `recordType` (type: `string`):

agendaItems returns one record per agenda item with action and attachments. meetings returns one record per meeting. matters returns legislation (ordinances, resolutions, appointments).

## `keywords` (type: `array`):

Keep only records whose title, file number or body matches any keyword (case insensitive). Leave empty for everything.

## `daysBack` (type: `integer`):

Include meetings (or legislation introduced) from this many days ago.

## `daysAhead` (type: `integer`):

Include meetings scheduled this many days into the future.

## `includeVotes` (type: `boolean`):

Agenda items only. Adds one extra request per acted on item and returns each member's vote when the city records them.

## `maxResults` (type: `integer`):

Hard stop for the run. You are billed per result, so this caps the cost.

## `proxyConfiguration` (type: `object`):

Apify proxy is recommended for larger runs.

## Actor input object example

```json
{
  "clients": [
    "denver",
    "seattle"
  ],
  "recordType": "agendaItems",
  "keywords": [],
  "daysBack": 14,
  "daysAhead": 14,
  "includeVotes": false,
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "clients": [
        "denver",
        "seattle"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("talcoe/legistar-agendas").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "clients": [
        "denver",
        "seattle",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("talcoe/legistar-agendas").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "clients": [
    "denver",
    "seattle"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call talcoe/legistar-agendas --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,talcoe/legistar-agendas"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0fGDWBqTkI3HykFzc/builds/o18s8WzFfqX4wAqYn/openapi.json
