# Municipal Agenda Keyword Radar (`searchandfind/municipal-agenda-keyword-radar`) Actor

Monitor US city-council agendas for your keywords: zoning, data centers, short-term rentals, competitors. Official Legistar + PrimeGov APIs, no proxies. Agenda-item snippets with links; alert mode sends only NEW matches to your webhook. Pay per match.

- **URL**: https://apify.com/searchandfind/municipal-agenda-keyword-radar.md
- **Developed by:** [Devon James](https://apify.com/searchandfind) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $150.00 / 1,000 keyword matches

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Municipal Agenda Keyword Radar

### What does Municipal Agenda Keyword Radar do?

**Municipal Agenda Keyword Radar watches US city-council and county-board agendas for the keywords you care about** — and tells you the moment they show up, with the exact agenda snippet, meeting date, and a link to the agenda. It reads official government sources directly across **four platform families** — the [Legistar](https://www.granicus.com) InSite API, PrimeGov portals, legacy Granicus (ViewPublisher) sites, and eScribe meeting portals — which together host most US local governments. **No proxies, no blocking, no brittle HTML scraping** of consumer sites.

Point it at your cities, give it phrases like `data center`, `short-term rental`, `battery storage`, `rezoning`, or a competitor's name, and run it on a schedule. In **alert mode** it remembers everything it has already told you and only outputs *new* hits — you pay only when something new appears.

### Why use Municipal Agenda Keyword Radar?

Local government is where revenue-moving decisions surface first — and almost nobody reads the agendas:

- **Data-center, solar, and battery developers**: catch moratoriums, zoning changes, and rival projects the week they hit a committee agenda.
- **Short-term-rental operators and property managers**: know when an ordinance targeting STRs is scheduled — before the vote, not after.
- **B2G and civic-tech sales teams**: an agenda item mentioning your category is a buying signal with a date attached.
- **Journalists and researchers**: track an issue across many cities without reading 40 agendas a week.
- **Government-affairs teams**: enterprise policy-monitoring platforms charge $10,000+/year for this. This Actor costs cents per alert.

### How to use Municipal Agenda Keyword Radar

1. Add your **keywords** (plain phrases; matching is case-insensitive and whole-word).
2. Add your **jurisdictions**: the subdomain of `{city}.legistar.com` goes in *Legistar cities*, `{city}.primegov.com` in *PrimeGov cities*, `{host}.granicus.com` in *Granicus sites* (as `host:viewIds`, or just the host to auto-discover its agenda views), and `{name}.escribemeetings.com` in *eScribe portals*. Pasting full URLs works too.
3. Click **Start**. Matches appear in the dataset with snippets and links.
4. For monitoring: turn on **Alert mode**, add a **webhook URL** (Slack, Zapier, Make, or your own endpoint), and put the Actor on a [schedule](https://docs.apify.com/platform/schedules) — daily or weekly. Each run then delivers only *new* matches.

#### Verified example cities

| Platform | Tested slugs |
|---|---|
| Legistar | `seattle`, `mesa`, `longbeach`, `oakland`, `sanjose`, `kingcounty`, `pittsburgh`, `columbus`, `madison`, `fortlauderdale`, `fulton` (Fulton County GA), `dekalbcountyga` (DeKalb County GA), `phoenix`, `mecklenburg` (Mecklenburg County NC), `santaclara` (Santa Clara CA) |
| PrimeGov | `lacity` (Los Angeles), `sanantonio`, `tucson`, `oaklandca` |
| Granicus | `pwcgov:23,12,24` (Prince William County VA — Board of County Supervisors, Planning Commission, Zoning Appeals) |
| eScribe | `pub-loudoun` (Loudoun County VA — Board of Supervisors and committees) |

Any other jurisdiction on those platforms works the same way — check whether `yourcity.legistar.com`, `yourcity.primegov.com`, `yourcity.granicus.com`, or `pub-yourcity.escribemeetings.com` exists.

### Input

See the Input tab for the full schema. Minimal example:

```json
{
    "keywords": ["data center", "substation", "moratorium"],
    "legistarClients": ["seattle", "dekalbcountyga"],
    "primegovClients": ["lacity"],
    "granicusClients": ["pwcgov:23,12,24"],
    "escribeClients": ["pub-loudoun"],
    "daysBack": 14,
    "daysAhead": 60,
    "onlyNewResults": true,
    "alertWebhookUrl": "https://hooks.zapier.com/..."
}
```

### Output

One record per keyword match. You can download the dataset in JSON, CSV, Excel, or HTML, or read it via API.

```json
{
    "platform": "legistar",
    "client": "seattle",
    "keyword": "housing",
    "matchType": "agenda-item",
    "snippet": "…of Council Bill 121254 as shown in the underlined and strike through language below: Rental junk fees are a growing issue within the housing affordability crisis. These unavoidable and often hidden fees increase the cost of living…",
    "meetingTitle": "City Council",
    "meetingDate": "2026-08-11",
    "meetingTime": "2:00 PM",
    "meetingStatus": "final",
    "isUpcoming": false,
    "itemTitle": "An ordinance relating to rental agreement regulation; requiring disclosure of fees, prohibiting and limiting certain fees…",
    "matterFile": "CB 121254",
    "matterType": "Ordinance (Ord)",
    "matterStatus": "Passed",
    "agendaUrl": "https://legistar2.granicus.com/seattle/meetings/2026/8/6854_A_City_Council_26-08-11_Full_Council_Meeting_Agenda.pdf",
    "meetingUrl": "https://seattle.legistar.com/MeetingDetail.aspx?LEGID=6854&GID=393&G=FFE3B678-CEF6-4197-84AC-5204EA4CFC0C",
    "videoUrl": "https://seattlechannel.org/FullCouncil?videoid=x189286"
}
```

#### Main output fields

| Field | Meaning |
|---|---|
| `keyword` | Which of your keywords matched |
| `matchType` | `meeting-title`, `agenda-item` (Legistar item/matter), or `agenda-text` (full HTML agenda) |
| `snippet` | ±140 characters of context around the match |
| `meetingDate` / `isUpcoming` | When the meeting happens/happened |
| `meetingStatus` | e.g. `final`, `cancelled` — cancellations are signals too |
| `matterFile` / `matterType` / `matterStatus` | Legislative file details when the match is a Legistar matter |
| `agendaUrl` / `meetingUrl` / `videoUrl` | Deep links to the official agenda, meeting page, and video |

### How much does it cost to monitor city-council agendas?

Pricing is **pay-per-event** — you pay for what the radar actually does:

| Event | Price | What it covers |
|---|---|---|
| Actor start | $0.01 | Run bootstrap |
| Meeting scanned | $0.002 | One meeting's agenda items / full agenda text fetched and scanned |
| Keyword match | $0.15 | One new match delivered (the thing you actually want) |

**Example**: a weekly run over 10 cities (~40 meetings each) that surfaces 6 new matches costs roughly 400 × $0.002 + 6 × $0.15 + $0.01 ≈ **$1.71**. A year of weekly monitoring ≈ $90 — versus $10K+/year for enterprise policy-monitoring suites. Use `maxTotalChargeUsd` when calling the Actor to hard-cap any run's spend.

### Tips

- **Alert mode + schedule + webhook** is the intended way to run this Actor. First run seeds the memory (you'll get a burst of current matches); every run after that is new-only.
- Keywords are whole-word: `solar` will not match `solaris`. Multi-word phrases match across line breaks.
- `daysBack` also catches *published minutes* of recent meetings; `daysAhead` catches agendas as soon as clerks publish them (often 3–7 days before the meeting).
- Turn **Scan full agenda content** off only if you need a very cheap title-level sweep.

### FAQ, disclaimers, and support

**Is this legal?** The Actor reads official public-record APIs and public agenda pages published by governments for exactly this purpose. It sends a handful of polite, rate-limited requests per city.

**A city returns no meetings?** Check the slug (`yourcity.legistar.com` must exist), and note some cities publish agendas only days before meetings. Failed cities are listed in the run's `SUMMARY` key-value record and the run log.

**Which platforms are supported?** Legistar InSite, PrimeGov, legacy Granicus (ViewPublisher/AgendaViewer), and eScribe today. CivicClerk, Municode Meetings, and per-item PDF attachment scanning (some Granicus towns keep item detail in attached PDFs rather than agenda text) are on the roadmap — open an issue on the **Issues tab** to vote, report a broken jurisdiction, or request a feature. Custom variants and white-label monitoring available on request.

# Actor input Schema

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

Words or phrases to find in council meeting agendas (case-insensitive, whole-word). Examples: <code>data center</code>, <code>short-term rental</code>, <code>rezoning</code>, <code>battery storage</code>, your company or a competitor's name.

## `legistarClients` (type: `array`):

Cities on Legistar InSite. Use the subdomain of <code>{city}.legistar.com</code> — e.g. <code>seattle</code> for seattle.legistar.com. Pasting the full URL also works. Hundreds of US cities and counties use Legistar; check <code>yourcity.legistar.com</code>.

## `primegovClients` (type: `array`):

Cities on PrimeGov portals. Use the subdomain of <code>{city}.primegov.com</code> — e.g. <code>lacity</code> for Los Angeles (lacity.primegov.com). Pasting the full URL also works.

## `granicusClients` (type: `array`):

Jurisdictions on legacy Granicus video/agenda portals ({host}.granicus.com). Format: <code>host:viewIds</code> — e.g. <code>pwcgov:23,12,24</code> for Prince William County VA (Board of County Supervisors, Planning Commission, Zoning Appeals). Give just the host (e.g. <code>pwcgov</code>) to auto-discover active agenda views (slower first run).

## `escribeClients` (type: `array`):

Jurisdictions on eScribe meeting portals — the subdomain of <code>{name}.escribemeetings.com</code>, e.g. <code>pub-loudoun</code> for Loudoun County VA. Pasting the full URL also works.

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

How many days of past meetings to scan (agendas AND minutes already published). 0 = upcoming meetings only.

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

How far into the future to scan scheduled meetings and their published agendas.

## `scanAgendaText` (type: `boolean`):

ON: scan every agenda item, legislative matter, and full HTML agenda text (recommended — this is where the signal lives). OFF: scan meeting titles only (faster, cheaper, much weaker).

## `onlyNewResults` (type: `boolean`):

Remember what previous runs already found and only output matches you haven't seen before. Turn this ON for scheduled monitoring so each run returns only NEW hits (you pay only for new matches).

## `maxMeetingsPerClient` (type: `integer`):

Upper bound of meetings scanned per city per run (closest meetings first).

## `alertWebhookUrl` (type: `string`):

Optional. If set and the run finds matches, the Actor POSTs a JSON payload <code>{ actorRunId, matchCount, matches\[] }</code> to this URL — plug into Slack, Zapier, Make, or your own endpoint.

## Actor input object example

```json
{
  "keywords": [
    "data center",
    "short-term rental",
    "zoning variance"
  ],
  "legistarClients": [
    "seattle"
  ],
  "primegovClients": [
    "lacity"
  ],
  "granicusClients": [
    "pwcgov:23,12,24"
  ],
  "escribeClients": [
    "pub-loudoun"
  ],
  "daysBack": 14,
  "daysAhead": 60,
  "scanAgendaText": true,
  "onlyNewResults": false,
  "maxMeetingsPerClient": 40
}
```

# 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 = {
    "keywords": [
        "data center",
        "short-term rental",
        "zoning variance"
    ],
    "legistarClients": [
        "seattle"
    ],
    "primegovClients": [
        "lacity"
    ],
    "granicusClients": [
        "pwcgov:23,12,24"
    ],
    "escribeClients": [
        "pub-loudoun"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("searchandfind/municipal-agenda-keyword-radar").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 = {
    "keywords": [
        "data center",
        "short-term rental",
        "zoning variance",
    ],
    "legistarClients": ["seattle"],
    "primegovClients": ["lacity"],
    "granicusClients": ["pwcgov:23,12,24"],
    "escribeClients": ["pub-loudoun"],
}

# Run the Actor and wait for it to finish
run = client.actor("searchandfind/municipal-agenda-keyword-radar").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 '{
  "keywords": [
    "data center",
    "short-term rental",
    "zoning variance"
  ],
  "legistarClients": [
    "seattle"
  ],
  "primegovClients": [
    "lacity"
  ],
  "granicusClients": [
    "pwcgov:23,12,24"
  ],
  "escribeClients": [
    "pub-loudoun"
  ]
}' |
apify call searchandfind/municipal-agenda-keyword-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,searchandfind/municipal-agenda-keyword-radar"
        }
    }
}

```

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/dgOMkhqeJ9uwDRgDk/builds/BUnA6eQOWgOUxq93u/openapi.json
