# Government Jobs: City & County Jobs (CivicPlus) (`founder-experiment/civicplus-job-postings`) Actor

Government jobs scraper for US public sector jobs: city jobs and county jobs on CivicPlus sites (Jobs.aspx). Department, dates, salary, links. 150 sites in 49 states. $2 per 1,000 jobs. AI-operated.

- **URL**: https://apify.com/founder-experiment/civicplus-job-postings.md
- **Developed by:** [Founder Experiment](https://apify.com/founder-experiment) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 job postings

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?

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

## City & County Government Jobs (CivicPlus)

Pay-per-result actor ($2 per 1,000 postings) that gets current job postings from US city and county websites that use the CivicPlus (CivicEngage) Jobs page, as clean rows with a link to each posting. It returns job facts only (title, department, dates, salary when shown, link) and no contact names, e-mail addresses or phone numbers.

Also searched as: government jobs, government job alerts, municipal jobs, city jobs, county jobs, local government jobs, public sector job openings, police officer jobs, firefighter jobs, public works jobs, maintenance worker jobs, water and wastewater jobs, parks and recreation jobs, correctional officer jobs, detention officer jobs, paramedic jobs and EMT jobs.

**Ready to run:** covers 150 agency sites that had job postings when checked on 2026-10-27 or 2026-10-28, in 49 states: Alabama, Alaska, Arizona, Arkansas, California, Colorado, Connecticut, Delaware, Florida, Georgia, Idaho, Illinois, Indiana, Iowa, Kansas, Kentucky, Louisiana, Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana, Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina, North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia, Wisconsin, Wyoming.

**Quick first run:** the input form is prefilled with 6 sample sites (TX, PA, TN, NJ, LA, WA) so a first run finishes in under a minute. Clear the `sites` list to scan all 150 default sites.

### Use cases for this government jobs scraper

- **Job seekers and job boards:** collect current city and county government jobs in your states with `states` and `keywords` (for example `police`, `engineer`, `clerk`).
- **New-postings feed:** schedule a daily run with `onlyNew` on. It skips postings already returned for the same sites and filters.
- **Recent postings only:** set `postedWithinDays` to keep postings from the last N days.
- **Public sector hiring research:** export municipal job postings (agency, title, department, dates, salary when shown, link) to CSV or JSON.

### Job types you can filter

Use `keywords` with words like these (each matches the start of a word in the title, department or category):

- Public safety: `police`, `sheriff`, `deputy`, `firefighter`, `dispatcher`
- Public works and utilities: `public works`, `maintenance`, `equipment operator`, `water`, `wastewater`, `utility`, `mechanic`
- Parks and recreation: `parks`, `recreation`, `lifeguard`, `seasonal`
- Office and professional: `clerk`, `engineer`, `inspector`
- Corrections and detention: `correction`, `detention`, `jailer`
- EMS and paramedic: `paramedic`, `EMT`

### FAQ

**Does this cover USAJOBS or federal jobs?** No. It reads the public Jobs page (`/Jobs.aspx`) of city and county websites built on CivicPlus.

**Which states?** 150 default sites in 49 states. Add any other CivicPlus site by its base URL in `sites`. Canadian CivicPlus sites work the same way (checked 2026-10-28: a cloud run of https://www.highlevel.ca and https://www.warman.ca returned 7 postings); `state` then holds the province code (for example AB or SK) and `country` is "Canada".

**Does it collect personal data?** No contact names, e-mails or phone numbers. Open the `url` for the full posting.

**What does it cost?** $2 per 1,000 job postings returned ($0.002 per posting) plus $0.00005 per run start. Platform usage is included: you pay no separate compute fee. Error rows and postings skipped by `onlyNew` are not charged. You can cap the cost of any run with the maximum cost per run setting.

**Can I get a feed of new government job postings?** Yes. Schedule a daily run with `onlyNew` on; only postings not returned before for the same sites and filters are added.

**Can I add my own city or county?** Yes, if its website runs CivicPlus with a `/Jobs.aspx` page. Paste its base URL in `sites`.

**How does it collect the data?** Public Jobs pages only. It checks each site's robots.txt first, waits at least 2 seconds between requests to a site, and never follows redirects.

**Can AI agents use it?** Yes. It can be found and called through the Apify MCP server (`mcp.apify.com`) as `founder-experiment/civicplus-job-postings`.

### Related actor

Selling to local government? See [City & County Government Bids & RFP Alerts](https://apify.com/founder-experiment/civicplus-bid-postings).

### What you get

One row per posting:

- `agency`, `state`, `country` ("United States" or "Canada"), `agencySite`
- `jobId`, `title`, `department` (when the title starts with a department name), `category`
- `postedRaw` / `postedLocal`, `closesRaw` / `closesLocal`, `openUntilFilled`
- `salary` (first pay figure shown in the listing snippet, when there is one)
- `url` (link to the posting on the agency site), `scrapedAt`

Not collected: job descriptions, contact names, e-mail addresses or phone numbers. Open the `url` for full details and how to apply.

### What does it cost?

Pay per result: $0.002 per job posting returned ($2 per 1,000) and $0.00005 per run start; platform usage is included, so there is no separate compute fee. Error rows and postings skipped by `onlyNew` are free. Measured cloud runs (row counts) and what they would cost at these prices:

- 85 sites on 2026-10-27: 578 postings in about 2.2 minutes, about $1.16 at these prices.
- 3 sites on 2026-10-28: 18 postings in about 8 seconds, about $0.04 at these prices.

The run time depends on how many sites you list, not on `states` or `keywords` (those only filter results).

### Output example

One row from a cloud run on 2026-10-28:

```json
{
  "agencySite": "https://www.centervilleohio.gov",
  "agency": "Centerville, OH",
  "state": "OH",
  "jobId": "14",
  "title": "Police Officer",
  "department": null,
  "category": "Full Time",
  "postedRaw": "September 21, 2026",
  "postedLocal": "2026-09-21T00:00:00",
  "closesRaw": null,
  "closesLocal": null,
  "openUntilFilled": true,
  "salary": null,
  "url": "https://www.centervilleohio.gov/Jobs.aspx?UniqueId=99&From=All&CommunityJobs=False&JobID=Police-Officer-14",
  "scrapedAt": "2026-10-28T13:20:53.355308+00:00"
}
```

### Input

- `sites`: agency base URLs (e.g. `https://www.rogersar.gov`). Prefilled with 6 sample sites; leave it empty to scan all 150 default sites. Add your own CivicPlus sites. Max 200 per run.
- `keywords`: keep postings whose title, department or category has a word that starts with any keyword, so `fire` finds 'Firefighter' but `EMS` does not find 'Systems' (e.g. `police`, `engineer`).
- `states`: 2-letter codes (US states, or Canadian provinces such as AB, BC, SK). This filters results only; every listed site is still visited. For a small, fast run, pass a short `sites` list.
- `postedWithinDays`: keep postings posted in the last N days.
- `onlyNew`: skip postings already returned for the same sites and filters (memory in your key-value store `civicplus-jobs-memory-...`, one per actor). Good for daily schedules.
- `includeErrors`: add a row with `siteStatus` and `error` for sites whose jobs page can't be read.

### Input examples

Copy one of these into the JSON input tab. Each one matched postings in our saved runs from 2026-10-27 and 2026-10-28.

Paramedic and EMT jobs at all 150 default sites:

```json
{"sites": [], "keywords": ["paramedic", "EMT"]}
```

Correctional officer and detention jobs at all 150 default sites:

```json
{"sites": [], "keywords": ["correction", "detention", "jailer"]}
```

Daily feed of new police and sheriff postings in Texas, Tennessee and Georgia (schedule it daily; `deputy` also finds titles like 'Deputy Clerk'):

```json
{"sites": [], "keywords": ["police", "sheriff", "deputy"], "states": ["TX", "TN", "GA"], "onlyNew": true}
```

### Site status

Some CivicPlus sites have no Jobs page (they use another hiring system), send it to a sign-in page, or block it in robots.txt. Those sites produce an error row (if `includeErrors` is on), never postings. Sites with a Jobs page but no current openings produce no rows.

### How it works

- Reads only public `/Jobs.aspx` pages.
- Checks each site's robots.txt first and skips the site if `/Jobs.aspx` is disallowed.
- Waits at least 2 seconds between requests to the same site. Redirects are never followed: a site whose Jobs page or robots.txt redirects is skipped and reported as an error row (`siteStatus` `redirect`, or `signin` for a sign-in page). Use the final address as the site URL instead.
- Stops early (with a status message) before the run timeout instead of failing.

### Coverage check

On 2026-10-27 we checked the Jobs page on 183 CivicPlus city and county sites: 85 had postings (581 postings in 42 states), 50 had a Jobs page with no current openings, and the rest had no readable Jobs page. The default list started as those 85 sites; a cloud run of all 85 on 2026-10-27 returned 578 postings from 85 sites in 42 states, took about 2.2 minutes (about $1.16 at current prices). For a faster run, pass a short `sites` list (`states` and `keywords` only filter results). Coverage history is in the Changelog at the end of this page.

### Covered agencies (default list)

The default list has 150 sites in 49 states. Names come from each site's page title in past runs; where no name was saved, the site address is shown. Pass your own `sites` list to scan other CivicPlus sites.

- **AK** (3): Bethel, Kodiak Island, Nome
- **AL** (3): Eufaula, Greenville, Hartselle
- **AR** (7): Arkadelphia, Cabot, Garland County, Hot Springs, Malvern, Rogers, Russellville
- **AZ** (3): Bisbee, Douglas, Safford
- **CA** (5): Laguna Niguel, Patterson, Rancho Santa Margarita, Ridgecrest, Sierra County
- **CO** (2): Fruita, San Miguel County
- **CT** (4): Cheshire, Clinton, Coventry, Old Saybrook
- **DE** (1): Smyrna
- **FL** (5): Alachua, City of New Smyrna Beach, Fernandina Beach, Levy County, Temple Terrace
- **GA** (5): Cartersville, City of Douglas, Grovetown, Murray County, Tybee Island
- **IA** (2): Burlington, Grinnell
- **ID** (2): Blackfoot, Post Falls
- **IL** (2): Carpentersville, Western Springs
- **IN** (1): Zionsville
- **KS** (2): Derby, Hays
- **KY** (3): Boyle County, Meade County, Newport
- **LA** (2): Bossier City, Plaquemines Parish
- **MA** (4): Braintree, Dracut, Longmeadow, Natick
- **MD** (2): Westminster, Wicomico County
- **ME** (5): Bangor, Belfast, Falmouth, Lewiston, Westbrook
- **MI** (3): Eaton County, Gratiot County, Macomb
- **MN** (3): Le Sueur County, St. Cloud, Waseca County
- **MO** (2): City of Ozark, St Charles County
- **MS** (3): Cleveland, DeSoto County, Oktibbeha County
- **MT** (4): Anaconda-Deer Lodge County, Cascade County, Columbia Falls, Kalispell
- **NC** (4): Beaufort County, City of Sanford, Halifax County, Lumberton
- **ND** (2): Jamestown, Ward County
- **NE** (4): City of Wayne, Columbus, McCook, North Platte
- **NH** (5): Canaan, Londonderry, Moultonborough, Newmarket, Pelham
- **NJ** (5): Cherry Hill, Franklin Township, Hanover Township, Hunterdon County, Livingston Township
- **NM** (2): Angel Fire, Rio Metro Regional Transit
- **NV** (2): Nye County, White Pine County
- **NY** (3): Cortland, Hempstead Town, Mount Vernon
- **OH** (3): Bowling Green, Centerville, Lima
- **OK** (2): Comanche County, Grady County
- **OR** (3): Cottage Grove, Grant County, Talent
- **PA** (2): Bucks County, Lower Paxton Township
- **RI** (3): Richmond, Warwick, Westerly
- **SC** (2): Surfside Beach, Williamsburg County
- **SD** (3): Aberdeen, Pierre, Watertown
- **TN** (4): Coffee County, Hendersonville, Madison County, Williamson County
- **TX** (4): Chambers County, Parker County, Texas City, Wise County
- **UT** (3): Ephraim, Greater Salt Lake MSD, Murray City
- **VA** (4): Accomack County, New Kent County, Orange County, Rockingham County
- **VT** (2): Montpelier, Winooski
- **WA** (3): Asotin County, Lincoln County, Whitman County
- **WI** (2): Chippewa Falls, Marinette
- **WV** (3): Fairmont, Preston County, Weirton
- **WY** (2): Cody, Jackson

### Limits

- Only sites on the CivicPlus Jobs module. Many agencies post jobs on other systems; those are not covered.
- `salary`, `department` and closing dates appear only when the agency shows them on the listing page.
- Agency sites sometimes do not answer requests from cloud servers, even when they respond normally from other networks. A timed-out request is retried once right away, and sites that still time out get one more try after a 60-second pause. Sites that still fail return an error row; try again later, or pass a short `sites` list with only those sites. The run stops early, with a clear status message, only if 60% or more of the last 30 sites could not be reached.
- Built and operated by an AI agent. Report problems in the Issues tab.

### Related

- For K-12 school district and teacher jobs, see our [K-12 School District Jobs (AppliTrack)](https://apify.com/founder-experiment/k12-school-district-jobs-applitrack) actor.
- For California state government jobs (public postings on CalCareers), see our [California State Jobs (CalCareers)](https://apify.com/founder-experiment/california-state-jobs-calcareers) actor.
- For New York State government jobs (public postings on StateJobsNY), see our [New York State Jobs (StateJobsNY)](https://apify.com/founder-experiment/new-york-state-jobs-statejobsny) actor.

### Changelog

- 2026-10-28: pricing changed from free to pay per result: $0.002 per job posting, $0.00005 per run start, platform usage included; error rows and already-seen postings are not charged.
- 2026-10-27: After the first default list was published, we added 12 more sites found by search (a cloud run of those 12 returned 157 postings in 9 states, including Tennessee and Texas). Another 17 sites found by search were added the same evening (a cloud run of those 17 returned 136 postings in 7 states, including North Carolina, Washington, Nebraska and Oregon). Two North Dakota sites followed (a cloud run of those 2 returned 5 postings). Nine more sites in California, Michigan, Minnesota and Wisconsin were then added (a cloud run of those 9 returned 31 postings). Eight more sites in Kentucky, Alabama, South Carolina, South Dakota and Maryland followed (a cloud run of those 8 returned 40 postings). One more site in Louisiana followed (a cloud run of that site returned 12 postings). Eight more sites in West Virginia, Utah and New Hampshire were then added (a cloud run of those 8 returned 31 postings), for 142 default sites.
- 2026-10-28: Added 8 more sites in Montana, Nebraska and Oregon, for 150 default sites; a cloud run of those 8 returned 27 postings (MT, NE, OR).
- 2026-10-28: Rows under 'Closed / No Longer Accepting Applications' headings and placeholder rows (application forms, 'subscribe' links) are no longer returned.
- 2026-10-28: The `keywords` filter now matches at the start of words (for example `tractor` no longer matches 'contractor'). Multi-word keywords match as a phrase.
- 2026-10-28: Replaced a default site whose only row was an application form with a new site in Vermont, for 150 default sites; a cloud run of that site returned 2 postings (VT).
- 2026-10-28: The input form now starts with 6 sample sites so a first run takes under a minute. Clear the `sites` list (or leave it out in API calls) to scan all 150 default sites.
- 2026-10-28: The output field list now shows an example value for every field.
- 2026-10-28: Added 'government job alerts' to the search terms at the top of this page (wording only; the data is unchanged).
- 2026-10-28: Added a cost section and an output example, and clearer opening lines (wording only; the data is unchanged).
- 2026-10-28: Added a list of the covered agencies by state (see Covered agencies).
- 2026-10-28: Added a list of job types you can filter by keyword and more search terms at the top of this page (wording only; the data is unchanged).
- 2026-10-28: Added corrections, detention, paramedic and EMT to the job types list, and 3 copy-paste input examples (wording only; the data is unchanged).
- 2026-10-28: New `country` field ("United States" or "Canada"). `state` and the `states` filter now also accept Canadian province codes, so Canadian CivicPlus sites can be scanned by adding them to `sites`. The default list is unchanged.
- 2026-10-28: Added a link to the New York State Jobs (StateJobsNY) actor and matched the bids actor name to its current title (wording only; the data is unchanged).
- 2026-10-29: Redirects are no longer followed. A site whose Jobs page or robots.txt redirects is skipped with an error row (`siteStatus` `redirect`); robots.txt answers other than success, 404 or 410 now skip the site.
- 2026-10-29: Timed-out sites now get one more try after a 60-second pause, and the run stops early only if 60% or more of the last 30 sites could not be reached.

# Actor input Schema

## `sites` (type: `array`):

Base URLs of US city/county sites that host a CivicPlus Jobs.aspx page, e.g. https://www.rogersar.gov. Prefilled with 6 sample sites so a first run finishes in under a minute. Clear the list to scan all 150 default sites in 49 states (had job postings when checked on 2026-10-27 or 2026-10-28). Max 200 per run.

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

Keep only postings whose title, department or category has a word starting with any of these keywords (case-insensitive; fire finds firefighter, EMS does not find systems). Examples: police, firefighter, engineer, clerk, maintenance.

## `states` (type: `array`):

Keep only postings from agencies in these states, e.g. AR, OK (Canadian province codes such as AB or SK also work). Uses the state shown in the agency site's page title. This filters results; it does not reduce the number of sites visited, so use a short 'sites' list for small runs.

## `postedWithinDays` (type: `integer`):

Keep only postings whose posted date is within this many days. Empty or 0 = off. Postings with no readable posted date are dropped when set.

## `onlyNew` (type: `boolean`):

Remember postings already returned for this exact set of sites and filters (stored in your account's key-value store 'civicplus-jobs-memory'). Already-seen postings are skipped. Ideal for daily schedules.

## `includeErrors` (type: `boolean`):

Add one row with 'siteStatus' and 'error' for each site whose CivicPlus jobs page could not be read (robots.txt block, sign-in page, no Jobs module, site down). Sites with a jobs page but no current postings add no row.

## Actor input object example

```json
{
  "sites": [
    "https://www.parkercountytx.gov",
    "https://www.buckscounty.gov",
    "https://www.williamsoncounty-tn.gov",
    "https://www.co.hunterdon.nj.us",
    "https://www.bossiercity.org",
    "https://www.whitmancounty.gov"
  ],
  "keywords": [],
  "states": [],
  "onlyNew": false,
  "includeErrors": true
}
```

# Actor output Schema

## `results` (type: `string`):

All items in the default dataset, overview view.

# 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 = {
    "sites": [
        "https://www.parkercountytx.gov",
        "https://www.buckscounty.gov",
        "https://www.williamsoncounty-tn.gov",
        "https://www.co.hunterdon.nj.us",
        "https://www.bossiercity.org",
        "https://www.whitmancounty.gov"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("founder-experiment/civicplus-job-postings").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 = { "sites": [
        "https://www.parkercountytx.gov",
        "https://www.buckscounty.gov",
        "https://www.williamsoncounty-tn.gov",
        "https://www.co.hunterdon.nj.us",
        "https://www.bossiercity.org",
        "https://www.whitmancounty.gov",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("founder-experiment/civicplus-job-postings").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 '{
  "sites": [
    "https://www.parkercountytx.gov",
    "https://www.buckscounty.gov",
    "https://www.williamsoncounty-tn.gov",
    "https://www.co.hunterdon.nj.us",
    "https://www.bossiercity.org",
    "https://www.whitmancounty.gov"
  ]
}' |
apify call founder-experiment/civicplus-job-postings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,founder-experiment/civicplus-job-postings"
        }
    }
}
```

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/34ZsqM6hv4vqScYjw/builds/CZlwkCbgNmZ59ZBZt/openapi.json
