# Municipal Planning & Development Signals (`obsequious_doughnut/municipal-development-signals`) Actor

Source-linked Austin site-plan signals for data centers, solar, battery storage, multifamily, and warehouses.

- **URL**: https://apify.com/obsequious\_doughnut/municipal-development-signals.md
- **Developed by:** [BRADLEY B](https://apify.com/obsequious_doughnut) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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?

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 Planning & Development Signals

Turn Austin site-plan records into source-linked commercial development signals for data centers, solar projects, battery storage, multifamily projects, and warehouses.

The Actor reads the official City of Austin `Site Plan Cases` open dataset, applies deterministic evidence rules to source-authored fields, and writes normalized records ready for scheduled monitoring, CRM enrichment, research, webhooks, and AI agents.

### Why use this Actor?

Raw municipal records are difficult to monitor repeatedly. This Actor provides:

- stable source IDs and official record links;
- deterministic project-type matches with the exact matched terms;
- data-minimized source retrieval that never requests applicant/owner names, addresses, phone numbers, or case-manager fields;
- parcel, address, status, area, unit, and building-size fields where the source provides them;
- provenance, observation timestamps, evidence text, and completeness status;
- `updatedSince` support for filtering by the dataset refresh timestamp;
- honest partial-run summaries instead of silently dropping upstream failures.

### Source and permitted use

The MVP uses the City of Austin Development Services `Site Plan Cases` dataset (`mavg-96ck`):

- Dataset API: https://data.austintexas.gov/resource/mavg-96ck.json
- Dataset page: https://data.austintexas.gov/d/mavg-96ck
- City Open Data Terms: https://data.austintexas.gov/stories/s/ranj-cccq

The dataset metadata identifies it as official and public domain. The City's terms say portal data is offered free and without restriction unless otherwise noted, request attribution, prohibit attempts to re-identify individuals, and disclaim accuracy, completeness, quality, and timeliness warranties.

This Actor attributes every result to the City of Austin Development Services and deliberately does not request or emit source applicant/owner names, phone numbers, personal addresses, or case-manager names. It does not infer legal approval, investment value, developer identity, or project viability.

### Input

```json
{
    "jurisdiction": "austin-tx",
    "projectTypes": ["data-center", "solar", "battery-storage", "multifamily", "warehouse"],
    "keywords": ["semiconductor", "industrial campus"],
    "updatedSince": "2026-07-01T00:00:00Z",
    "maxResults": 100,
    "requestDelayMillis": 1000
}
```

#### Input fields

- `jurisdiction`: currently `austin-tx` only.
- `projectTypes`: one or more supported deterministic categories.
- `keywords`: optional phrases matched locally against official project text. They are never interpolated into the upstream query.
- `updatedSince`: optional RFC 3339 timestamp applied to `update_date`, which the source defines as the date the dataset was updated. It is a dataset-refresh filter, not a record-level change timestamp.
- `maxResults`: global output cap, 1–1,000.
- `requestDelayMillis`: 1,000–10,000 ms between API pages.

### Output example

```json
{
    "signalId": "austin-site-plan:12529218",
    "jurisdiction": "Austin, Texas",
    "recordType": "site-plan-case",
    "projectName": "Example Battery Storage Campus",
    "projectTypes": ["battery-storage"],
    "matchedTerms": ["battery energy storage", "battery storage"],
    "status": "In Review",
    "address": "9224 BLUFF SPRINGS RD, AUSTIN, TX 78747",

    "sourceDatasetId": "mavg-96ck",
    "sourceRecordId": "12529218",
    "sourceRecordUrl": "https://abc.austintexas.gov/web/permit/public-search-other?...",
    "attribution": "City of Austin Development Services via the City of Austin Open Data Portal",
    "observedAt": "2026-08-12T00:00:00.000Z",
    "completenessStatus": "complete",
    "evidence": "Example Battery Storage Campus — A 250 MW battery energy storage system..."
}
```

### Scheduled monitoring

Run the Actor on a schedule and deduplicate downstream using `signalId` plus source fields. `updatedSince` filters the source dataset refresh timestamp; because many or all rows can receive the same refresh time, it does **not** identify records that substantively changed. The Actor does not claim to reconstruct a field-level historical diff without a prior snapshot.

Example API call:

```bash
curl -X POST "https://api.apify.com/v2/acts/ACTOR_ID/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"updatedSince":"2026-08-01T00:00:00Z","projectTypes":["data-center","battery-storage"],"maxResults":100}'
```

Never embed an Apify token in source control or public automation examples.

### Cost controls

The Actor uses the official JSON API rather than browser automation or proxies. Control cost with:

- `updatedSince` for dataset-refresh windows;
- `maxResults` for a hard global result cap;
- deterministic local matching without paid AI APIs;
- Apify SDK pay-per-event budget enforcement before default-dataset items are published;
- one-second request spacing and 100 source rows per page.

### Limitations

- Coverage is currently limited to Austin site-plan cases.
- Source data can be delayed, corrected, incomplete, or historically rewritten.
- Runs stop after 10,000 source rows as a safety bound; the run summary explicitly reports `partial`, `truncated`, and `sourcePageLimitReached` when that bound is reached. Use `updatedSince` for bounded incremental monitoring.
- Categories are deterministic keyword evidence, not legal or professional conclusions.
- A record may match multiple categories.
- `updatedSince` filters dataset refresh time and is not proof that an individual record changed.
- Records with no matching category or user keyword are omitted.
- No personal contact information is emitted.
- Output is research infrastructure, not legal, planning, investment, procurement, or real-estate advice.

### Development

```bash
npm ci
npm run check
npm run build
apify validate-schema
apify run --purge
```

Local Actor input belongs at `storage/key_value_stores/default/INPUT.json`. Local storage is not synchronized to the Apify Cloud.

# Actor input Schema

## `jurisdiction` (type: `string`):

MVP coverage currently includes the City of Austin Site Plan Cases dataset.

## `projectTypes` (type: `array`):

Return records whose official name, description, land use, or work fields contain evidence for these categories.

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

Optional case-insensitive phrases matched locally against official project text. They are never inserted into the upstream query.

## `updatedSince` (type: `string`):

Optional ISO 8601 timestamp. Use this for scheduled delta windows. This does not prove what changed between runs.

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

Global cap on matching signals written to the dataset.

## `requestDelayMillis` (type: `integer`):

A conservative delay for the official Socrata API. The minimum is 1 second, matching the portal's robots crawl delay.

## Actor input object example

```json
{
  "jurisdiction": "austin-tx",
  "projectTypes": [
    "data-center",
    "solar",
    "battery-storage",
    "multifamily",
    "warehouse"
  ],
  "keywords": [],
  "updatedSince": "2026-07-01T00:00:00Z",
  "maxResults": 100,
  "requestDelayMillis": 1000
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `datasetView` (type: `string`):

No description

## `runSummary` (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 = {
    "updatedSince": "2026-07-01T00:00:00Z"
};

// Run the Actor and wait for it to finish
const run = await client.actor("obsequious_doughnut/municipal-development-signals").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 = { "updatedSince": "2026-07-01T00:00:00Z" }

# Run the Actor and wait for it to finish
run = client.actor("obsequious_doughnut/municipal-development-signals").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 '{
  "updatedSince": "2026-07-01T00:00:00Z"
}' |
apify call obsequious_doughnut/municipal-development-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,obsequious_doughnut/municipal-development-signals"
        }
    }
}

```

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/19XbzPNrhg1xvkIMT/builds/a7DEQ2402n6Yl66Mq/openapi.json
