# Patch.com Local News, Events & Classifieds Finder (`dataspryva/patch-com-local-news-events-and-classifieds-finder`) Actor

Search Patch.com's hyperlocal US news by keyword, town, category, author, or tag, and browse its local events calendar or classifieds board, with date-range and distance filters.

- **URL**: https://apify.com/dataspryva/patch-com-local-news-events-and-classifieds-finder.md
- **Developed by:** [Dataspryva](https://apify.com/dataspryva) (community)
- **Categories:** News, Automation, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 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?

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

## Patch.com Local News, Events & Classifieds Finder

Collect hyperlocal US news, local events and classifieds from **Patch.com** in one run. Search by keyword across the whole country, browse a town or a news category, follow one reporter or editorial tag, open the local events calendar, scan the classifieds board, or paste Patch URLs directly. Every record can include the full body text, article coordinates and expiry, and optional detail-page metadata such as gallery images, author avatars, comment counts, town grade/views/ZIPs, event venue details and classified contact state. No login, cookies, proxy or API key required.

### What this actor does

- **Eight modes:** `search`, `byTown`, `byCategory`, `byAuthor`, `byTag`, `events`, `classifieds`, `byUrl`
- **Direct URL support:** paste article, event, classified, town, topic, state or search URLs and the actor turns them into a record or an equivalent scoped query
- **Full body text:** `bodyHtml`, `bodyText` and `bodyLength` come straight from Patch's own search payload, so they cost no extra request
- **Optional detail enrichment:** gallery images with captions/credits, author avatar and points, comment/reply counts, breaking/sponsored/staff flags, town grade/weekly views/ZIPs/timezone/county/metro, event venue/type/website and classified contact-form state
- **Article coordinates and expiry:** `latitude`, `longitude` and `expiresDate` for articles; events and classifieds also expose their expiry and event coordinates
- **Up to 1,000 rows:** requests above Patch's 250-hit search window are automatically split into date partitions and deduplicated
- **Monitor mode:** emit only IDs that a previous run with the same monitor key has not seen
- **Search matching control:** all-words matching by default, exact-phrase matching when you need it
- **Filters:** publish-date range, event-occurrence date range, US state/edition, town, news category, classifieds category, author, tag and geo-radius/nearest sorting
- **Clean records:** empty fields are omitted at every depth; no `null`, `""` or `[]` values are pushed

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | select | `search` | `search`, `byTown`, `byCategory`, `byAuthor`, `byTag`, `events`, `classifieds` or `byUrl` |
| `startUrls` | request list | – | mode=byUrl only. Article, event, classified, town, category/topic, state or search URLs |
| `searchQuery` | text | – | Keyword to search for; empty means browse with the other filters |
| `searchMatch` | select | `allWords` | `allWords` (every word anywhere) or `exactPhrase` (words adjacent, the old behavior) |
| `authorName` | text | – | Exact byline; required for `byAuthor`, extra filter elsewhere |
| `tagName` | text | – | Exact editorial tag; required for `byTag`, extra filter on article modes |
| `regionSlug` | select | – | US state/edition, including `across-america` (national) and `us-territories` |
| `townSlug` | text | – | Town/city slug or full town URL; pair with `regionSlug` for `byTown` |
| `category` | select | – | One of 21 Patch news topics |
| `classifiedCategory` | select | – | One of 11 classifieds categories (classifieds mode only) |
| `sortBy` | select | `relevance` | `relevance`, `newest`, `oldest`, `nearest` (news + geo), `eventDate` (events) |
| `publishedAfter` / `publishedBefore` | text | – | `YYYY-MM-DD` bounds on when the record was posted to Patch |
| `eventDateAfter` / `eventDateBefore` | text | – | `YYYY-MM-DD` bounds on the event's own occurrence date (events only) |
| `nearLat` / `nearLng` | number | – | Center point for a news geo-radius search; set both together |
| `radiusMiles` | integer | `25` | Radius in miles (1–500) |
| `includeBodyText` | boolean | `true` | Add `bodyHtml`, `bodyText`, `bodyLength` |
| `includeDetails` | boolean | `false` | Fetch each record's Patch page for optional enrichment fields |
| `maxDetails` | integer | `100` | Detail pages to fetch; `0` means every emitted record |
| `monitorMode` | boolean | `false` | Emit only records not seen by an earlier run |
| `monitorKey` | text | – | Namespace for monitor state; derived from the query when empty |
| `maxItems` | integer | `25` | Maximum records to return (1–1,000) |

`regionSlug` and `townSlug` are the two path segments in a Patch town URL: `patch.com/california/santamonica` gives `regionSlug=california`, `townSlug=santamonica`. `startUrls` accepts full URLs or bare `patch.com/...` paths; non-Patch URLs are ignored with a warning.

### Modes

| Mode | What it does |
|---|---|
| `search` | Keyword or browse search across Patch articles; combine any filters |
| `byTown` | Latest articles for one town (requires `regionSlug` + `townSlug`) |
| `byCategory` | Browse one Patch news topic (requires `category`) |
| `byAuthor` | Every article matching one exact byline (requires `authorName`) |
| `byTag` | Every article carrying one exact editorial tag (requires `tagName`) |
| `events` | Patch's local events calendar with venue, type and website enrichment |
| `classifieds` | Patch's marketplace listings with contact-form state |
| `byUrl` | Paste Patch article/event/classified URLs for direct records, or town/topic/state/search URLs for scoped queries |

### Output fields

Every record includes `recordType` (`article` / `event` / `classified`) and `scrapedAt` last. Field availability depends on the content type and on whether detail enrichment is on; anything Patch does not provide is omitted rather than returned as an empty value.

#### Common fields

- `headline`, `shortHeadline`, `summary`, `author`, `authorId`, `authorUrl`
- `publishedDate`, `updatedDate` (only when changed), `url`
- `town`, `townUrl`, `state`, `regionUrl`, `stateName`
- `imageUrl`, `imageCount`, `images[]` (`url`, `caption`, `credit`, `copyright` when detail enrichment is on)
- `bodyHtml`, `bodyText`, `bodyLength` (when `includeBodyText` is true)
- `expiresDate`, `contentType`, `patchId`, `promotedUntil`

#### Articles

- `articleId`, `category`, `tags`, `latitude`, `longitude`, `distanceMiles` (geo runs only)
- `topicId`, `tagIds`, `townId`
- Detail enrichment: `preHeader`, `authorAvatarUrl`, `authorPoints`, `commentCount`, `replyCount`
- Detail enrichment: `isBreakingNews`, `isSponsoredContent`, `isStaffContent`, `isPressRelease`, `isNeighborContent`, `isNewsPartnerContent`, `isDailyDigest`, `isRobot`, `isExternal`, `isTopStory`, `isMostRecent`, `isShared`, `isEvergreen`, `isOriginalContent`, `contentSource`
- Detail enrichment: `townGrade`, `townWeeklyViews`, `townZipCodes`, `timezone`, `countyName`, `countyFips`, `metroArea`, `townLatitude`, `townLongitude`, `townType`, `townModel`

#### Events

- `eventId`, `eventDate`, `eventAddress`, `eventLat`, `eventLng`, `isPromoted`, `isSharedNationally`
- Detail enrichment: `eventVenueName`, `eventStreetAddress`, `eventCountry`, `eventWebsite`, `eventType`, `eventStatus`, `interestedCount`, `sharedTowns[]`
- Same author, comment, town and image enrichment fields as articles

#### Classifieds

- `classifiedId`, `category`, `expiresDate`, `isPromoted`, `isSharedNationally`
- Detail enrichment: `contactFormEnabled`, `thankCount`
- Same author, comment, town and image enrichment fields as articles

### Examples

Nationwide keyword search with full body text:

```json
{
  "mode": "search",
  "searchQuery": "school board",
  "sortBy": "newest",
  "includeBodyText": true,
  "maxItems": 50
}
```

One town with detail enrichment:

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

Events happening in a date range:

```json
{
  "mode": "events",
  "regionSlug": "california",
  "townSlug": "santamonica",
  "eventDateAfter": "2026-11-01",
  "eventDateBefore": "2026-11-30",
  "sortBy": "eventDate",
  "maxItems": 100
}
```

Classifieds in one category:

```json
{
  "mode": "classifieds",
  "classifiedCategory": "housing",
  "regionSlug": "texas",
  "maxItems": 50
}
```

Paste any mix of Patch URLs:

```json
{
  "mode": "byUrl",
  "startUrls": [
    { "url": "https://patch.com/california/santamonica/some-article" },
    { "url": "https://patch.com/california/across-ca" }
  ],
  "includeBodyText": true,
  "maxItems": 100
}
```

Only new records since the previous run:

```json
{
  "mode": "search",
  "searchQuery": "city council",
  "monitorMode": true,
  "monitorKey": "santamonica-council",
  "maxItems": 100
}
```

Large runs above 250 rows:

```json
{
  "mode": "search",
  "searchQuery": "high school sports",
  "sortBy": "newest",
  "maxItems": 1000
}
```

### How pagination works

Patch's public search key exposes at most 250 hits per query. For `maxItems` above 250 the actor probes the date range, recursively splits it into `created_ts` slices (or `display_date_ts` for `sortBy=eventDate`), collects each slice under the cap, deduplicates by Patch ID and then sorts the merged result. A bounded request budget prevents runaway calls; if the budget is reached before the requested row count, the status message says so instead of silently short-changing the run. There is no wall-clock cutoff.

### Data source

Patch.com's public site and the search service that powers it. The actor bootstraps the scoped search host/key from Patch's own SSR payload on each run, and uses public SSR detail pages only when detail enrichment or URL mode asks for them. It never uses cookies, logins, paid proxies or unofficial credentials.

### Limitations

- **250 hits per backend query:** handled with date partitioning; extremely dense single-second ranges can still cap a slice.
- **Image placeholders:** some `imageUrl` values are Patch layout assets rather than article photos; `images[]` from detail pages is the gallery source.
- **Conditional metadata:** venue name/street, author avatars, gallery captions and classified contact state appear only when Patch stores them.
- **US only:** Patch is a US hyperlocal network. `us-territories` is a valid region but currently has no articles; `across-america` is the national edition.
- **Comment text and article view counts:** Patch does not expose comment threads, commenter identities or article view counts publicly; only counts and town-level weekly views are available.
- **Detail enrichment is optional and per-record:** it costs one request per record, so it is off by default and can be capped with `maxDetails`.

### FAQ

**Do I need an API key, cookies or a proxy?**
No. The actor reads Patch's public search service and public pages directly. Every mode works without credentials or proxy setup.

**Is this affiliated with Patch.com?**
No. It is an independent third-party actor that reads publicly accessible Patch.com data. It is not affiliated with or endorsed by Patch Media.

**How do I find a town's `regionSlug` and `townSlug`?**
Open the town on patch.com and read the URL: `patch.com/new-york/manhattan` means `regionSlug=new-york`, `townSlug=manhattan`. You can also paste the full town URL into `byUrl`.

**How do I find an exact `authorName` or `tagName`?**
Run another mode first and copy the value from the `author` or `tags` field. Patch matches these exactly (case-insensitive), so a guessed value may return zero records.

**Why did a keyword search change its result count compared with the old version?**
The new default is `searchMatch=allWords`, which requires every word to appear anywhere in the headline/summary/topic and usually returns more relevant matches than an exact phrase. Set `searchMatch=exactPhrase` to restore the old phrase-only behavior.

**Does the actor return the full article, event or classified body?**
Yes. `bodyHtml`, `bodyText` and `bodyLength` are included by default. Set `includeBodyText=false` to keep records small and avoid the body payload entirely.

**What does `includeDetails` add, and what does it cost?**
It fetches each record's Patch page once to add gallery images/captions/credits, author avatars, comment counts, flags, town metadata, event venue/type/website and classified contact state. Failed detail pages never discard the base record; use `maxDetails` to cap the extra requests.

**How do I get more than 250 rows?**
Set `maxItems` up to 1,000. The actor automatically partitions the date range to stay under Patch's per-query window. For very broad queries, narrow the town, category or publish-date range to reduce the number of partitions.

**How does monitor mode remember what it has seen?**
It stores a bounded list of Patch IDs in a persistent named key-value store (shared across runs) under a key derived from `monitorKey` (or from the query when no key is given). Reuse the same key across scheduled runs to receive only new records.

**How fresh is the data?**
Results come from Patch's live search index and live pages at run time, so they typically reflect newly published articles/events/classifieds within minutes.

# Actor input Schema

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

What to fetch from Patch.com.

## `startUrls` (type: `array`):

mode=byUrl only. Paste Patch article, event, classified, town, category/topic, state or search URLs. Article/event/classified URLs are scraped directly; town/topic/state/search URLs are converted into the equivalent scoped query.

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

Free-text keyword to search for (mode=search; also applies to mode=events/classifieds and to scope URLs). Leave empty to browse the newest articles matching the other filters.

## `searchMatch` (type: `string`):

How multi-word searches match. "All words" requires every word anywhere in the headline/summary/topic (more results). "Exact phrase" requires the words to appear together (the old behavior).

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

Exact byline/reporter/poster name (required for mode=byAuthor; on any other mode it is an extra server-side filter). Copy it from this actor's `author` output field, e.g. "Eric Heyl".

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

Exact editorial tag (required for mode=byTag; on article modes it is an extra filter). Copy it from this actor's `tags` field, e.g. "Back To School". Only a minority of articles carry tags.

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

US state/edition to scope results to (required for mode=byTown; optional filter on every other mode). "Across America" is Patch's national edition (code US); "US Territories" is a valid Patch region with no current articles.

## `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.

## `includeBodyText` (type: `boolean`):

Add bodyHtml (the original HTML), bodyText (readable plain text) and bodyLength to each record. Article/event/classified bodies come from Patch's own search payload, so this costs no extra request.

## `includeDetails` (type: `boolean`):

Fetch each record's Patch page and add gallery images/captions/credits, author avatar and points, comment/reply counts, breaking/sponsored flags, town grade/weekly views/ZIPs/timezone/county/metro, event venue/type/website, and classified contact state. One extra request per record; failed pages never discard the base record.

## `maxDetails` (type: `integer`):

How many records to enrich when `includeDetails` is on. 0 means every emitted record (up to `maxItems`). Ignored when detail enrichment is off.

## `monitorMode` (type: `boolean`):

Emit only records whose Patch ID has not been seen by an earlier run with the same monitor key. State is stored in the actor's key-value store.

## `monitorKey` (type: `string`):

Optional namespace for monitor state. Give different saved tasks different keys to keep their seen-ID lists separate. Derived automatically from the mode and filters when empty.

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

Maximum number of articles, events or classifieds to return (1-1000). Requests above 250 are automatically split into date partitions to bypass Patch's 250-hit search-key window.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "city council",
  "searchMatch": "allWords",
  "authorName": "",
  "tagName": "",
  "regionSlug": "",
  "townSlug": "",
  "category": "",
  "classifiedCategory": "",
  "sortBy": "relevance",
  "radiusMiles": 25,
  "includeBodyText": false,
  "includeDetails": false,
  "maxDetails": 0,
  "monitorMode": false,
  "monitorKey": "",
  "maxItems": 3
}
```

# Actor output Schema

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

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

# 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",
    "searchMatch": "allWords",
    "authorName": "",
    "tagName": "",
    "regionSlug": "",
    "townSlug": "",
    "category": "",
    "classifiedCategory": "",
    "sortBy": "relevance",
    "radiusMiles": 25,
    "includeBodyText": false,
    "includeDetails": false,
    "maxDetails": 0,
    "monitorMode": false,
    "monitorKey": "",
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataspryva/patch-com-local-news-events-and-classifieds-finder").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",
    "searchMatch": "allWords",
    "authorName": "",
    "tagName": "",
    "regionSlug": "",
    "townSlug": "",
    "category": "",
    "classifiedCategory": "",
    "sortBy": "relevance",
    "radiusMiles": 25,
    "includeBodyText": False,
    "includeDetails": False,
    "maxDetails": 0,
    "monitorMode": False,
    "monitorKey": "",
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("dataspryva/patch-com-local-news-events-and-classifieds-finder").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",
  "searchMatch": "allWords",
  "authorName": "",
  "tagName": "",
  "regionSlug": "",
  "townSlug": "",
  "category": "",
  "classifiedCategory": "",
  "sortBy": "relevance",
  "radiusMiles": 25,
  "includeBodyText": false,
  "includeDetails": false,
  "maxDetails": 0,
  "monitorMode": false,
  "monitorKey": "",
  "maxItems": 3
}' |
apify call dataspryva/patch-com-local-news-events-and-classifieds-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataspryva/patch-com-local-news-events-and-classifieds-finder"
        }
    }
}
```

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/C5BexVLa39ZcPgizT/builds/kgvnqgKSosfpPzZC4/openapi.json
