# City Calendar Scraper - US Local Events (`knutty_cadet/city-calendar-scraper`) Actor

Extract events from US city .gov and community calendars. Auto-detects Drupal, CivicPlus, FullCalendar and generic layouts. Outputs clean JSON or CSV with event name, date, time, venue, description. Residential proxy recommended.

- **URL**: https://apify.com/knutty\_cadet/city-calendar-scraper.md
- **Developed by:** [Anh Nguyen](https://apify.com/knutty_cadet) (community)
- **Categories:** Automation, Developer tools, Other
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## City Calendar Scraper — US Local Events

Extract events from US city `.gov` and community calendars automatically. One actor, unified output, no custom coding needed.

### What it does

This actor scrapes event listings from city and community calendar websites. It automatically detects the calendar type and extracts event data into a clean, normalized format.

**Supported calendar types:**

- Drupal Views Calendar (monthly grid with event items)
- CivicPlus / VisionInternet event widgets
- FullCalendar JS-rendered calendars (Revize CMS)
- Generic event listings (any page with event-like structure)

### Who is this for

- **Newsletter publishers** — pull local events for weekly roundups
- **Real estate agents** — show community events near listings
- **Local SEO agencies** — generate content from city calendars
- **Event aggregators** — build databases of community events
- **Researchers** — track municipal activities across cities

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| urls | string[] | required | List of city/community calendar page URLs |
| maxEventsPerSite | integer | 50 | Maximum events to extract per URL (1-200) |
| includeDescription | boolean | true | Fetch full event description from detail pages |
| outputFormat | string | csv | Output format: "json" or "csv" |

#### Example input

```json
{
  "urls": [
    "https://www.fostercity.org/calendar",
    "https://www.redwoodcity.org/events",
    "https://www.ssfca.gov/Departments/Parks-Recreation/Events"
  ],
  "maxEventsPerSite": 20,
  "includeDescription": true,
  "outputFormat": "csv"
}
````

### Output

Each event contains:

| Field | Description |
|-------|-------------|
| eventName | Event title |
| date | Event date |
| time | Event time (if available) |
| city | City name extracted from URL |
| venue | Venue or location (if available) |
| description | Full event description (if includeDescription is enabled) |
| price | Free/Paid info (if detected) |
| eventUrl | Direct link to event detail page |
| imageUrl | Event image URL (if available) |
| sourceUrl | Calendar page that was scraped |
| scrapedAt | Timestamp of extraction |

#### Example output

```json
{
  "eventName": "Egg Hunt 2026",
  "date": "2026-04-04",
  "time": "10:00am",
  "city": "fostercity",
  "venue": "Leo J. Ryan Meadow",
  "description": "The City of Foster City presents our inaugural Egg Hunt...",
  "price": "N/A",
  "eventUrl": "https://www.fostercity.org/parksrec/page/egg-hunt-2026",
  "imageUrl": null,
  "sourceUrl": "https://www.fostercity.org/calendar",
  "scrapedAt": "2026-04-05T07:15:10.823Z"
}
```

### How it works

1. The actor visits each URL you provide
2. It detects the calendar/CMS type automatically
3. Events are extracted using the matching strategy
4. If `includeDescription` is enabled, it visits detail pages for full descriptions
5. Data is normalized and deduplicated
6. Results are saved to the dataset (JSON) and optionally as CSV

### Proxy

Recommended: **Residential proxies** for best results. Many `.gov` sites block datacenter IPs.

### Performance

- \~10 events per site takes 5-15 seconds
- Memory usage: under 1024 MB
- Each URL is processed sequentially for stability

### Cost estimate

- \~0.3 compute units per 10 sites with 50 events each
- Using `includeDescription: true` increases compute time (detail page visits)

### Limitations

- Event data accuracy depends on source site structure
- Some fields may not be available on all sites (venue, price, image)
- FullCalendar (JS-rendered) sites may have limited extraction
- If a site changes its layout, extraction may need updating
- Sites with heavy bot protection may return fewer results

### Tips

- Start with `maxEventsPerSite: 10` and `includeDescription: false` for quick testing
- Use `includeDescription: true` for production runs to get full event details
- Check the logs to see which calendar type was detected for each URL
- CSV output opens directly in Excel and Google Sheets (UTF-8 with BOM)

### Disclaimer

Data accuracy depends on source sites. This actor extracts publicly available information. User is responsible for compliance with source site Terms of Service. This actor does not store or cache data between runs.

### Changelog

- 1.0 — Initial release: Drupal Calendar, CivicPlus Widget, FullCalendar, Generic fallback strategies

# Actor input Schema

## `urls` (type: `array`):

List of city/community calendar page URLs

## `maxEventsPerSite` (type: `integer`):

Maximum number of events to collect per input URL

## `includeDescription` (type: `boolean`):

Fetch detail pages for longer descriptions when missing on list view

## `outputFormat` (type: `string`):

Dataset is always JSON; CSV writes an additional OUTPUT.csv to key-value store when csv

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

Use Apify Proxy (e.g. RESIDENTIAL) for .gov / CivicPlus sites that block datacenter IPs.

## Actor input object example

```json
{
  "maxEventsPerSite": 50,
  "includeDescription": true,
  "outputFormat": "csv"
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("knutty_cadet/city-calendar-scraper").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("knutty_cadet/city-calendar-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{}' |
apify call knutty_cadet/city-calendar-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=knutty_cadet/city-calendar-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "City Calendar Scraper - US Local Events",
        "description": "Extract events from US city .gov and community calendars. Auto-detects Drupal, CivicPlus, FullCalendar and generic layouts. Outputs clean JSON or CSV with event name, date, time, venue, description. Residential proxy recommended.",
        "version": "1.0",
        "x-build-id": "uQ4sya7NxeXvDw9u4"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/knutty_cadet~city-calendar-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-knutty_cadet-city-calendar-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/knutty_cadet~city-calendar-scraper/runs": {
            "post": {
                "operationId": "runs-sync-knutty_cadet-city-calendar-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/knutty_cadet~city-calendar-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-knutty_cadet-city-calendar-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "urls"
                ],
                "properties": {
                    "urls": {
                        "title": "Calendar URLs",
                        "minItems": 1,
                        "type": "array",
                        "description": "List of city/community calendar page URLs",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxEventsPerSite": {
                        "title": "Max events per site",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Maximum number of events to collect per input URL",
                        "default": 50
                    },
                    "includeDescription": {
                        "title": "Include full description",
                        "type": "boolean",
                        "description": "Fetch detail pages for longer descriptions when missing on list view",
                        "default": true
                    },
                    "outputFormat": {
                        "title": "Output format",
                        "enum": [
                            "json",
                            "csv"
                        ],
                        "type": "string",
                        "description": "Dataset is always JSON; CSV writes an additional OUTPUT.csv to key-value store when csv",
                        "default": "csv"
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Use Apify Proxy (e.g. RESIDENTIAL) for .gov / CivicPlus sites that block datacenter IPs."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
