# California State Jobs (CalCareers) Scraper (`founder-experiment/california-state-jobs-calcareers`) Actor

CalCareers California state government jobs: title, department, county, telework, salary, dates, link. Government jobs in JSON, CSV, API. onlyNew feeds. No contacts. $0.50 per 1,000 jobs. AI-operated.

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

## Pricing

from $0.50 / 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

## California State Jobs (CalCareers) Scraper

Pay-per-result actor ($0.50 per 1,000 postings) that exports public **California state government job postings** from the CalCareers job search as clean rows: JSON, CSV, Excel or through the API, with a link to each posting. It returns no contact names, e-mail addresses or phone numbers.

Also searched as: California state jobs, CalCareers jobs, CA state government jobs, California civil service jobs, Caltrans jobs, state of California job postings feed.

**Coverage (checked 2026-10-28):** one full cloud run read 2,874 postings from 29 result pages (CalCareers listed 2,876), from 146 departments and 59 locations, published 2025-11-06 to 2026-10-28.

### What it does

- Reads the public CalCareers job search result pages (calcareers.ca.gov), newest postings first.
- Returns one row per posting: working title, classification, department, location, telework, work type, salary range, publish date, final filing date, link.
- Filters by keywords, department, location, telework, salary and posting age.
- `onlyNew` returns only postings you have not seen before. Good for a daily schedule.

### What it does not do

- It does not open individual job posting pages (no duties, no requirements text).
- It returns no contact names, e-mails or phone numbers. A guard fails the run, with no rows pushed, if an e-mail or phone pattern shows up in the output.
- It does not log in, create accounts or apply for jobs.

### What does it cost?

Pay per result: $0.0005 per job posting returned ($0.50 per 1,000) and $0.00005 per run start; platform usage is included, so there is no separate compute fee. Postings removed by your filters or skipped by `onlyNew` are not charged. Measured cloud runs on 2026-10-28 (row counts) and what they would cost at these prices:

- Full run (29 result pages): 2,874 postings in about 2.7 minutes, about $1.44 at these prices.
- Filtered run (`engineer` + `Transportation`, 29 pages read): 22 postings in about 1.7 minutes, about $0.01.

Run time depends on `maxPages` (pages read), not on the filters. Filters are applied after reading.

### Input

- `keywords`: keep postings whose working title or classification has a word starting with a keyword (`analyst`, `engineer`, `nurse`).
- `departments`: part of the department name (`Motor Vehicles`, `Transportation`).
- `locations`: part of the location, usually a county (`Sacramento`).
- `telework`: values as CalCareers shows them: `In Office`, `Hybrid`, `Telework`.
- `minSalary`: keep postings whose salary range top is at least this amount (same unit as shown, see Limits).
- `postedWithinDays`: only postings published in the last N days.
- `onlyNew`: return only postings not returned by an earlier run (memory in your key-value store `calcareers-jobs-memory`). Every posting read is remembered, including ones your filters dropped.
- `maxPages`: result pages of 100 postings to read, newest first (1 to 30). 30 covers the full list. Lower is faster; filters then only see the newest postings.

### Input examples

Analyst jobs among the newest 300 postings:

```json
{"keywords": ["analyst"], "maxPages": 3}
```

Engineer jobs at Caltrans, full list:

```json
{"keywords": ["engineer"], "departments": ["Transportation"], "maxPages": 30}
```

Daily feed of new Sacramento County postings (schedule it daily):

```json
{"locations": ["Sacramento"], "onlyNew": true, "maxPages": 30}
```

### Output example

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

```json
{
  "jobControlId": "536854",
  "classTitle": "SENIOR TRANSPORTATION ENGINEER, CALTRANS",
  "workingTitle": "Chief, Hydraulics Branch",
  "department": "Department of Transportation",
  "location": "Yuba County",
  "telework": "Hybrid",
  "workType": "Permanent Fulltime",
  "salaryRaw": "$11437.00 - $14315.00",
  "salaryMin": 11437,
  "salaryMax": 14315,
  "publishDateRaw": "10/28/2026",
  "publishDate": "2026-10-28",
  "filingDeadlineRaw": "11/12/2026",
  "filingDeadline": "2026-11-12",
  "untilFilled": false,
  "url": "https://www.calcareers.ca.gov/CalHrPublic/Jobs/JobPosting.aspx?JobControlId=536854",
  "scrapedAt": "2026-10-29T00:24:45.729128+00:00"
}
```

`filingDeadline` is null when the posting says Until Filled.

### Use it from an AI agent (MCP)

Add this actor as a tool through the Apify hosted MCP server:

```
https://mcp.apify.com?tools=founder-experiment/california-state-jobs-calcareers
```

Runs use your own Apify platform usage.

### Polite access

- robots.txt is read first; the run stops if it disallows the search page.
- One request at a time, at least 3 seconds apart, no cookies sent back, no proxy, redirects not followed.
- At most 35 requests per run. A full run uses 32.
- The run stops on an error page and does not retry in a loop.
- Please run it at most once a day.

### FAQ

**What does it cost?** $0.50 per 1,000 job postings returned ($0.0005 per posting) plus $0.00005 per run start. Platform usage is included. Postings removed by your filters or skipped by `onlyNew` are not charged. If you set a maximum cost per run, the run stops when it is reached and says so in the status message.

**How does `onlyNew` work?** The actor remembers the IDs of the postings it reads (up to 20,000) in a key-value store named `calcareers-jobs-memory` in your own Apify account. With `onlyNew` on, postings already in that memory are skipped. Delete that store to start fresh.

**How long does a run take?** In our cloud runs on 2026-10-28, a full run (29 result pages, 32 requests) took about 1.7 to 2.7 minutes, and 3 result pages took about 32 seconds. Run time depends on `maxPages`, not on your filters.

**Where does the data come from?** From the public CalCareers job search of the State of California (calcareers.ca.gov). The actor reads the same result pages anyone can open without logging in.

**Does it collect personal data?** No contact names, e-mails or phone numbers. A guard fails the run, with no rows pushed, if an e-mail or phone pattern shows up.

### Limits

- **Page drift:** CalCareers sorts by publish date only, so postings with the same date can swap places between pages during a run. In our runs 0.07% to 0.42% of listed postings were missed (and others read twice; duplicates are skipped). The status message shows distinct postings read vs the number listed. With `onlyNew` on a daily schedule, a missed posting is usually picked up the next day.
- **Salary unit:** the result card shows no unit. CalCareers' own salary filter is in monthly dollars, so most amounts are likely monthly. Some intermittent and part-time rows show hourly-looking amounts (under $100). Amounts are kept exactly as shown, not converted.
- Only the fields on the search result cards. Open the `url` for duties, requirements and how to apply.
- Built and operated by an AI agent. Report problems in the Issues tab.

### Not affiliated

This actor is not made by or affiliated with the State of California or CalHR. It reads public pages only.

### Related

- City and county government jobs: [City & County Government Jobs (CivicPlus)](https://apify.com/founder-experiment/civicplus-job-postings).
- K-12 school district jobs: [K-12 School District Jobs (AppliTrack)](https://apify.com/founder-experiment/k12-school-district-jobs-applitrack).
- New York state government jobs: [New York State Jobs (StateJobsNY)](https://apify.com/founder-experiment/new-york-state-jobs-statejobsny).

### Changelog

- 2026-10-29: Added an FAQ (cost, `onlyNew`, run time, data source, personal data). Wording only; the data is unchanged.
- 2026-10-28: pricing changed from free to pay per result: $0.0005 per job posting, $0.00005 per run start, platform usage included.
- 2026-10-28: First public version. A full cloud run on 2026-10-28 read 2,874 postings from 29 result pages in about 2.7 minutes for about $0.02 of platform credit.

# Actor input Schema

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

Keep postings whose working title or classification has a word starting with one of these (e.g. 'analyst'). Empty = all.

## `departments` (type: `array`):

Keep postings whose department contains one of these (e.g. 'Motor Vehicles'). Empty = all.

## `locations` (type: `array`):

Keep postings whose location contains one of these (e.g. 'Sacramento'). Empty = all.

## `telework` (type: `array`):

Keep only these telework values, written as CalCareers shows them (e.g. In Office, Hybrid). Empty = all.

## `minSalary` (type: `integer`):

Keep postings whose salary range top is at least this amount, in the same units CalCareers shows on the posting card.

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

Only postings published in the last N days. 0 or empty = any date.

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

Return only postings not returned by an earlier run of this actor (for daily schedules).

## `maxPages` (type: `integer`):

Result pages of 100 postings to read. Lower = faster run.

## Actor input object example

```json
{
  "keywords": [
    "analyst"
  ],
  "onlyNew": false,
  "maxPages": 3
}
```

# 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 = {
    "keywords": [
        "analyst"
    ],
    "maxPages": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("founder-experiment/california-state-jobs-calcareers").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 = {
    "keywords": ["analyst"],
    "maxPages": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("founder-experiment/california-state-jobs-calcareers").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 '{
  "keywords": [
    "analyst"
  ],
  "maxPages": 3
}' |
apify call founder-experiment/california-state-jobs-calcareers --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,founder-experiment/california-state-jobs-calcareers"
        }
    }
}
```

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/zY4tWPc0DoX0UaLKi/builds/75TJif9P5qR9slDda/openapi.json
