# Patch Scraper (`crawlerbros/patch-scraper`) Actor

Scrape Patch.com hyperlocal US news, local events, and classifieds. Search by keyword; browse by town, category, author, or tag; or browse the events calendar or marketplace listings. Filter by date range or distance. Get headline, summary, author, date, town, category, and image.

- **URL**: https://apify.com/crawlerbros/patch-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Lead generation, Developer tools
- **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 and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Patch Scraper

Scrape **Patch.com** — hyperlocal news, local events, and classifieds for thousands of US towns and cities. Search any keyword nationwide or within a specific town, browse the latest headlines for any town/city, browse by category (Politics & Government, Sports, Real Estate, Crime & Safety, and more), pull every article by a specific author, browse by editorial tag, browse the local events calendar, or browse classifieds/marketplace listings. Filter by publish-date range, event date range, or by distance from a location, and get the headline, summary, author, date, town, category, tags, and image for every record. No login, no cookies, no proxy required.

### What this actor does

- **Seven modes:** `search`, `byTown`, `byCategory`, `byAuthor`, `byTag`, `events`, `classifieds`
- **Nationwide or scoped:** search and browse across all of Patch, or narrow to one US state and/or one town/city
- **21 news categories:** Politics & Government, Sports, Crime & Safety, Real Estate, Schools, Business, Arts & Entertainment, Obituaries, Pets, Weather, and more
- **11 classifieds categories:** For Sale, Housing, Gigs & Services, Announcements, Lost & Found, and more
- **Local events calendar:** browse upcoming community events with venue address and event date, independent from news articles
- **Date-range filtering:** only return articles/events/classifieds published between two dates, plus a dedicated event-occurrence date range for `mode=events`
- **Geo-radius filtering:** only return news articles from towns within N miles of a latitude/longitude, and sort by distance (news modes only)
- **Flexible sorting:** relevance, newest first, oldest first, nearest first (news), or soonest-event-first (events)
- **Empty fields are omitted** — every field returned in a record has real, populated data

### Output per record

Every record always includes `recordType` (`"article"` / `"event"` / `"classified"`) and `scrapedAt`. Field availability depends on `recordType`:

#### News articles (`recordType: "article"`)

- `articleId` — Patch's internal article ID
- `headline` — article title
- `shortHeadline` — shortened headline used on Patch's cards/feeds
- `summary` — one-line article summary/dek
- `author` — byline name
- `authorId` — Patch's internal author ID (useful to disambiguate two reporters who share a name)
- `authorUrl` — link to the author's Patch profile
- `publishedDate` — publish timestamp (ISO 8601, UTC)
- `updatedDate` — last-updated timestamp (only present when different from `publishedDate`)
- `url` — canonical article URL on patch.com
- `town` — the Patch community the article belongs to (e.g. `Santa Monica`)
- `townUrl` — link to that town's Patch homepage
- `state` — 2-letter US state/territory abbreviation (e.g. `CA`)
- `regionUrl` — link to that state's Patch statewide news hub
- `category` — news category/topic (e.g. `Politics & Government`)
- `tags` — editorial tags on the article (e.g. `["Back To School"]`; only present when Patch tagged the article — most articles have none)
- `imageUrl` — article thumbnail image
- `distanceMiles` — distance from `nearLat`/`nearLng`, in miles (only present when a geo search is used)

#### Local events (`recordType: "event"`, `mode=events`)

- `eventId` — Patch's internal event ID
- `headline` — event title
- `shortHeadline`, `summary`, `author`, `authorId`, `authorUrl` — same meaning as articles (the event's poster)
- `eventDate` — the event's own occurrence date/time (ISO 8601, UTC) — this is what you filter with `eventDateAfter`/`eventDateBefore`
- `publishedDate` / `updatedDate` — when the event listing itself was posted/edited on Patch (filter with `publishedAfter`/`publishedBefore`)
- `url`, `town`, `townUrl`, `state`, `regionUrl`, `imageUrl` — same meaning as articles
- `eventAddress` — venue city/state/postal code, comma-joined (only present when Patch has address data for the event; most recent events include this)
- `eventLat` / `eventLng` — venue coordinates (only present when Patch has geocoded the venue)
- `isPromoted` — `true` if the event listing is a paid/sponsored promotion

#### Classifieds (`recordType: "classified"`, `mode=classifieds`)

- `classifiedId` — Patch's internal classified listing ID
- `headline` — listing title
- `shortHeadline`, `summary`, `author`, `authorId`, `authorUrl` — same meaning as articles (the poster)
- `category` — classifieds category (e.g. `Housing`, `For Sale`, `Gigs & Services` — see `classifiedCategory` input)
- `publishedDate` / `updatedDate` — when the listing was posted/edited
- `expiresDate` — when the listing expires from Patch's classifieds board
- `url`, `town`, `townUrl`, `state`, `regionUrl`, `imageUrl` — same meaning as articles
- `isPromoted` — `true` if the listing is a paid/sponsored promotion

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byTown` / `byCategory` / `byAuthor` / `byTag` / `events` / `classifieds` |
| `searchQuery` | string | – | Free-text keyword (mode=search; also works as an optional keyword filter on byTown/byCategory/byAuthor/byTag/events/classifieds) |
| `authorName` | string | – | Exact byline/reporter/poster name, e.g. `Eric Heyl` (required for mode=byAuthor; optional filter combinable with any other mode, including events/classifieds) |
| `tagName` | string | – | Exact editorial tag, e.g. `Back To School` (required for mode=byTag; optional filter on search/byTown/byCategory/byAuthor; not applicable to events/classifieds) |
| `regionSlug` | string | – | US state to scope to, e.g. `california` (required for mode=byTown; optional filter on every other mode) |
| `townSlug` | string | – | Town/city URL slug, e.g. `santamonica` (required for mode=byTown, needs `regionSlug` too; optional filter on every other mode) |
| `category` | string | – | News category (required for mode=byCategory; optional filter on search/byTown/byAuthor/byTag; not applicable to events/classifieds) |
| `classifiedCategory` | string | – | Classifieds category, e.g. `housing` (mode=classifieds only; a separate value set from `category`) |
| `sortBy` | string | `relevance` | `relevance` / `newest` / `oldest` / `nearest` (news modes only, requires `nearLat`/`nearLng`) / `eventDate` (mode=events only) |
| `publishedAfter` | string | – | Only records posted to Patch on/after this date (`YYYY-MM-DD`) |
| `publishedBefore` | string | – | Only records posted to Patch on/before this date (`YYYY-MM-DD`) |
| `eventDateAfter` | string | – | mode=events only. Only events occurring on/after this date (`YYYY-MM-DD`) |
| `eventDateBefore` | string | – | mode=events only. Only events occurring on/before this date (`YYYY-MM-DD`) |
| `nearLat` | number | – | Latitude to search near (news modes only; combine with `nearLng`, `radiusMiles`) |
| `nearLng` | number | – | Longitude to search near (news modes only; combine with `nearLat`, `radiusMiles`) |
| `radiusMiles` | int | `25` | Search radius in miles around `nearLat`/`nearLng` (news modes only, 1–500) |
| `maxItems` | int | `25` | Maximum records to return (1–250) |

`regionSlug` and `townSlug` come straight from the Patch URL — for `patch.com/california/santamonica`, `regionSlug` is `california` and `townSlug` is `santamonica`. Every filter above — including `authorName` and `tagName` — can be combined with any mode: e.g. `mode=search` + `searchQuery` + `authorName` searches one reporter's own articles for a keyword, or `mode=byCategory` + `category` + `tagName` narrows a category browse down to one editorial tag. `mode=events` and `mode=classifieds` browse Patch's local events calendar and classifieds board — separate content types from news articles, sharing the same town/state scope, `searchQuery`, and `authorName` filters, but with their own category axis (`classifiedCategory`) and date axis (`eventDateAfter`/`eventDateBefore` for events).

#### Example: nationwide keyword search

```json
{
  "mode": "search",
  "searchQuery": "school board",
  "sortBy": "newest",
  "maxItems": 30
}
```

#### Example: latest news for a specific town

```json
{
  "mode": "byTown",
  "regionSlug": "california",
  "townSlug": "santamonica",
  "maxItems": 25
}
```

#### Example: browse a category nationwide

```json
{
  "mode": "byCategory",
  "category": "real-estate",
  "sortBy": "newest",
  "maxItems": 50
}
```

#### Example: category browse scoped to one state

```json
{
  "mode": "byCategory",
  "category": "sports",
  "regionSlug": "texas",
  "sortBy": "newest",
  "maxItems": 40
}
```

#### Example: everything by one author

```json
{
  "mode": "byAuthor",
  "authorName": "Eric Heyl",
  "sortBy": "newest",
  "maxItems": 25
}
```

#### Example: everything tagged with an editorial tag

```json
{
  "mode": "byTag",
  "tagName": "Back To School",
  "sortBy": "newest",
  "maxItems": 25
}
```

#### Example: real-estate news published in a date range

```json
{
  "mode": "byCategory",
  "category": "real-estate",
  "publishedAfter": "2026-08-01",
  "publishedBefore": "2026-08-31",
  "sortBy": "newest",
  "maxItems": 50
}
```

#### Example: news within 25 miles of a location, nearest first

```json
{
  "mode": "search",
  "searchQuery": "traffic",
  "nearLat": 40.4406,
  "nearLng": -79.9959,
  "radiusMiles": 25,
  "sortBy": "nearest",
  "maxItems": 30
}
```

#### Example: one category narrowed to one reporter

```json
{
  "mode": "byCategory",
  "category": "sports",
  "authorName": "Eric Heyl",
  "sortBy": "newest",
  "maxItems": 25
}
```

#### Example: local events happening this weekend in one town

```json
{
  "mode": "events",
  "regionSlug": "california",
  "townSlug": "santamonica",
  "eventDateAfter": "2026-08-21",
  "eventDateBefore": "2026-08-23",
  "sortBy": "eventDate",
  "maxItems": 30
}
```

#### Example: classifieds nationwide, one category

```json
{
  "mode": "classifieds",
  "classifiedCategory": "housing",
  "sortBy": "newest",
  "maxItems": 25
}
```

### Use cases

- **Local news monitoring** — track breaking news for a specific town or neighborhood
- **Real estate & business intelligence** — pull local real-estate and business coverage across a state or nationwide
- **Media monitoring** — search for a brand, person, or topic mentioned across thousands of local outlets
- **Content aggregation** — build a local-news feed or newsletter for a specific community
- **Academic & civic research** — analyze hyperlocal coverage of politics, schools, and community issues
- **Reporter/byline tracking** — follow every article published by a specific journalist
- **Location-based monitoring** — find recent local coverage within a radius of a specific address or landmark
- **Community calendar aggregation** — pull upcoming local events for a town/state into your own calendar or newsletter
- **Local marketplace monitoring** — track new housing, for-sale, or gigs/services classifieds in a specific area

### FAQ

**What is the data source?**
Patch.com's own public news search — the same search index the Patch.com website itself uses.

**Is this affiliated with Patch.com?**
No, this is an independent, third-party actor that reads Patch.com's publicly accessible pages and search service. It is not affiliated with or endorsed by Patch Media.

**How do I find a town's `regionSlug` and `townSlug`?**
Visit patch.com, search for your town, and look at the URL: `patch.com/{regionSlug}/{townSlug}`. For example `patch.com/new-york/manhattan` -> `regionSlug=new-york`, `townSlug=manhattan`.

**How do I find an author's exact `authorName`?**
Run any other mode first and copy the `author` field from a result — Patch matches bylines exactly (case-insensitive), so a guessed name may return 0 results if it doesn't match Patch's stored byline precisely.

**How do I find an exact `tagName`, and why isn't it a dropdown like `category`?**
Run any other mode first and copy a value from a result's `tags` field. Unlike `category` (a fixed list of Patch topics), editorial tags are open-ended and Patch editors coin new ones continuously, so there's no finite list to enumerate — only a minority of articles carry tags at all, so try a different query or mode until a `tags` field shows up.

**Why are some fields (like `updatedDate`, `distanceMiles`, `eventAddress`) sometimes missing?**
They're only included when the underlying data actually applies to that record — e.g. `updatedDate` only appears if the article was edited after publishing, and `distanceMiles` only appears when you set both `nearLat` and `nearLng` on a news mode. See the field descriptions under Output above for exactly when each optional field appears.

**Does this include the full article/event/classified body text?**
No — only the headline, summary, and structured metadata (author, dates, town, category, tags, image) are returned. Full body text isn't currently supported.

**What's the difference between `publishedAfter`/`publishedBefore` and `eventDateAfter`/`eventDateBefore`?**
`publishedAfter`/`publishedBefore` filter by when a record (article, event listing, or classified) was posted to Patch — available on every mode. `eventDateAfter`/`eventDateBefore` (mode=events only) filter by the event's own occurrence date instead — e.g. use them to find "events happening this weekend" regardless of when the listing was posted.

**Why does `maxItems` cap out at 250?**
Patch's public search only exposes the first 250 matching results per query. To page further back, run the actor again with `publishedBefore` (or `eventDateBefore` for events) set to the oldest date returned by the previous run.

**How fresh is the data?**
Results reflect Patch's live search index at the time the actor runs — typically minutes behind newly published articles/events/classifieds.

# Actor input Schema

## `mode` (type: `string`):

What to fetch from Patch.com.

## `searchQuery` (type: `string`):

Free-text keyword to search for (mode=search; also applies as a keyword filter on mode=events/classifieds). Leave empty on other modes to browse without a keyword filter, or leave empty on mode=search to browse the newest articles matching the other filters below.

## `authorName` (type: `string`):

Exact byline/reporter/poster name (required for mode=byAuthor; on any other mode -- including events/classifieds -- it's applied as an extra filter, e.g. combine mode=search + searchQuery + authorName to search one reporter's own articles). Find it in the `author` field of any article/event/classified this actor returns, e.g. "Eric Heyl".

## `tagName` (type: `string`):

Exact editorial tag (required for mode=byTag; on mode=search/byTown/byCategory/byAuthor it's applied as an extra filter, e.g. combine mode=byCategory + category + tagName to browse one category narrowed to a tag). Find it in the `tags` field of any article this actor returns, e.g. "Back To School". Only a minority of articles carry tags, so run another mode first to discover one. Not applicable to mode=events/classifieds -- Patch doesn't tag those content types.

## `regionSlug` (type: `string`):

US state to scope results to (required for mode=byTown; optional scope filter on every other mode, including events/classifieds). Leave as "(any state)" for nationwide results.

## `townSlug` (type: `string`):

Patch town/city URL slug (required for mode=byTown; requires regionSlug too). Find it in a Patch URL, e.g. patch.com/california/santamonica -> "santamonica". Example: "santamonica" (with regionSlug=california).

## `category` (type: `string`):

News category/topic to filter by (required for mode=byCategory; optional filter on mode=search/byTown/byAuthor/byTag). Not applicable to mode=events/classifieds -- use `classifiedCategory` for mode=classifieds instead.

## `classifiedCategory` (type: `string`):

Classifieds category to filter by (mode=classifieds only; a completely separate value set from `category`, which is news-only). Leave as "(any category)" to browse every classified category.

## `sortBy` (type: `string`):

Order of results. "Nearest first" requires both `nearLat`/`nearLng` AND mode=search/byTown/byCategory/byAuthor/byTag (news); otherwise it falls back to Relevance. "Soonest event first" requires mode=events; on any other mode it also falls back to Relevance.

## `publishedAfter` (type: `string`):

Only include articles/events/classifieds posted to Patch on or after this date (i.e. listing date, not an event's own occurrence date -- see `eventDateAfter` for that). Format: YYYY-MM-DD. Combine with `publishedBefore` for a date range.

## `publishedBefore` (type: `string`):

Only include articles/events/classifieds posted to Patch on or before this date. Format: YYYY-MM-DD. Combine with `publishedAfter` for a date range.

## `eventDateAfter` (type: `string`):

mode=events only. Only include events occurring on or after this date (the event's own date, not when it was posted to Patch -- see `publishedAfter` for that). Format: YYYY-MM-DD. Combine with `eventDateBefore` for a date range, e.g. "what's happening this weekend".

## `eventDateBefore` (type: `string`):

mode=events only. Only include events occurring on or before this date. Format: YYYY-MM-DD. Combine with `eventDateAfter` for a date range.

## `nearLat` (type: `number`):

Latitude of a point to search near (combine with `nearLng` and `radiusMiles`). News modes only (search/byTown/byCategory/byAuthor/byTag) -- not available for mode=events/classifieds, whose Patch indexes don't expose a filterable location field. Both `nearLat` and `nearLng` must be set together; otherwise this filter is ignored.

## `nearLng` (type: `number`):

Longitude of a point to search near (combine with `nearLat` and `radiusMiles`). News modes only -- see `nearLat` description. Both `nearLat` and `nearLng` must be set together; otherwise this filter is ignored.

## `radiusMiles` (type: `integer`):

Search radius around `nearLat`/`nearLng`, in miles. News modes only -- see `nearLat` description. Ignored unless both `nearLat` and `nearLng` are set.

## `maxItems` (type: `integer`):

Maximum number of articles/events/classifieds to return.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "city council",
  "regionSlug": "",
  "townSlug": "",
  "category": "",
  "classifiedCategory": "",
  "sortBy": "relevance",
  "radiusMiles": 25,
  "maxItems": 25
}
```

# Actor output Schema

## `articles` (type: `string`):

Dataset containing all scraped Patch.com records (articles, events, or classifieds, depending on the input `mode`).

# 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 = {
    "mode": "search",
    "searchQuery": "city council",
    "authorName": "",
    "tagName": "",
    "regionSlug": "",
    "townSlug": "",
    "category": "",
    "classifiedCategory": "",
    "sortBy": "relevance",
    "radiusMiles": 25,
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/patch-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 = {
    "mode": "search",
    "searchQuery": "city council",
    "authorName": "",
    "tagName": "",
    "regionSlug": "",
    "townSlug": "",
    "category": "",
    "classifiedCategory": "",
    "sortBy": "relevance",
    "radiusMiles": 25,
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/patch-scraper").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 '{
  "mode": "search",
  "searchQuery": "city council",
  "authorName": "",
  "tagName": "",
  "regionSlug": "",
  "townSlug": "",
  "category": "",
  "classifiedCategory": "",
  "sortBy": "relevance",
  "radiusMiles": 25,
  "maxItems": 25
}' |
apify call crawlerbros/patch-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/SKFjOMkMXqFoDWhNe/builds/ZVQEDN3h3jg5mZLop/openapi.json
