# Hiring Changes Monitor: Opened & Closed Jobs by Company (`clearpath-data/hiring-changes-monitor`) Actor

Track which jobs each company opened or closed since your last run, from public Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee job boards. One summary row per company plus one row per changed job. No login needed.

- **URL**: https://apify.com/clearpath-data/hiring-changes-monitor.md
- **Developed by:** [Clearpath Data](https://apify.com/clearpath-data) (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 $5.00 / 1,000 company checks

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

### Hiring Changes Monitor: Opened & Closed Jobs by Company

See which jobs a company **opened** and **closed** since your last run. Point it at company job boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee, schedule it, and get one summary row per company (open jobs, opened, closed, net change by department) plus one row per changed job. The first run already returns data: each company's current open jobs.

**Price:** $0.005 per company checked and $0.001 per changed job. You only pay for rows saved to your dataset. Set `maxResults` or your maximum cost per run to cap the spend.

### What does it do?

- Reads each company's public job board through the board's public job-board API. No login, no cookies, nothing behind a sign-in.
- On the **first run** for a company it saves the list of open jobs as a baseline and also lists them: one **current-job row** per open job matching your filters, with `changeType: "current"`. Current-job rows are free; you pay only the company check. Turn them off with `currentJobsOnFirstRun: false`.
- On **every later run** it compares the board with that baseline and saves:
  - one **company row**: open jobs, opened, closed, net change, opened/closed by department, days since the last check;
  - one **job-change row** per opened or closed job: title, department, location, workplace type, posted date, link, and a `possibleRepost` flag when a job with the same title and location closed and reopened under a new ID.
- Then it moves the baseline forward, so the next run shows only what's new. Later runs never repeat the current-job list.

### Quick start

1. Click **Try for free**, keep the prefilled companies (Stripe, Spotify, OpenAI) and press **Start**. The first run saves baselines and lists each company's open jobs (up to Max job changes, 1,000 by default).
2. Run it again later (or schedule it daily) to see what opened and closed.
3. Or call it from code:

```bash
curl -X POST "https://api.apify.com/v2/acts/clearpath-data~hiring-changes-monitor/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" -d '{"companies": ["stripe", "https://jobs.lever.co/spotify"], "stateName": "my-watchlist"}'
```

### Sample output: job changes

| changeType | company | title | department | location |
|---|---|---|---|---|
| opened | Spotify | Art Director - Mexico | Markets and Subscriber Growth | Mexico City |
| opened | Spotify | Audiobook Licensing & Partnerships Manager - Japan | Business Team | Tokyo |
| opened | Spotify | AV Engineer - Platform | Engineering | Stockholm |
| opened | Spotify | Client Partner ANZ | Advertising | Sydney |

### Sample output: first run (current jobs)

| changeType | company | title | department | location |
|---|---|---|---|---|
| current | Spotify | Art Director - Mexico | Markets and Subscriber Growth | Mexico City |
| current | Spotify | Artist & Label Partnerships Contractor, Vietnam | Content | Ho Chi Minh |
| current | Spotify | Artist Label Partnerships Manager, Taiwan | Markets and Subscriber Growth | Taiwan (Home Mix) |
| current | Spotify | Associate – Audiobook Licensing & Author Partnerships | Operations and Business Support | New York, NY |
*Real output of a local first run on 2026-10-20 (Spotify's public Lever board); the first rows by title.*

### Sample output: company summary

| company | status | openJobs | opened | closed | netChange | daysSincePreviousCheck |
|---|---|---|---|---|---|---|
| Spotify | checked | 82 | 17 | 14 | +3 | 9.9 |

*Real output of a test run on 2026-10-19, compared with Spotify's public Lever board as saved on 2026-10-09. Engineering had the most new roles (5).*

### Use cases

- **Sales and recruiting agencies:** spot companies that just opened roles in your niche (e.g. `departments: ["Engineering"]`, `locations: ["London"]`).
- **Investors and market research:** track hiring velocity of a watchlist; net change by department shows where a company is growing or cutting.
- **Competitive intelligence:** see when a competitor opens a new team or closes a group of roles.
- **Job seekers' tools:** alert on new roles at target companies only, instead of re-reading whole boards.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `companies` | array | | Board slugs ("stripe"), prefixed slugs ("lever:spotify"), board URLs or careers-page URLs |
| `ats` | string | "auto" | Which ATS to try for plain slugs; "auto" tries them in turn |
| `changeTypes` | array | \[] (both) | "opened", "closed" |
| `keywords` | array | \[] | Only jobs whose title contains one of these |
| `locations` | array | \[] | Only jobs whose location contains one of these |
| `remoteOnly` | boolean | false | Only remote jobs |
| `departments` | array | \[] | Only jobs whose department or team contains one of these |
| `stateName` | string | "default" | Name of the saved baseline; use one per schedule or task |
| `baselineDatasetId` | string | | Compare with an earlier run's dataset instead of the saved state |
| `updateState` | boolean | true | Move the baseline forward after a company's changes are all saved |
| `currentJobsOnFirstRun` | boolean | true | On a company's first check, also list its open jobs as free `current` rows |
| `maxResults` | integer | 1000 | Stop saving job rows after this many (0 = no limit); opened/closed rows first, first-check current rows use the room left |
| `maxConcurrency` | integer | 3 | Boards read in parallel (1 to 10) |

Filters apply to both the baseline and today's board, so changing them between runs doesn't create false changes.

### Integrations, schedules and AI agents

- **Schedules:** Schedule it daily or weekly with one `stateName` per watchlist. See [Apify schedules](https://docs.apify.com/platform/schedules).
- **No-code tools:** send results to Google Sheets, Slack or a CRM with Apify's [Make](https://docs.apify.com/platform/integrations/make), [Zapier](https://docs.apify.com/platform/integrations/zapier) or [n8n](https://docs.apify.com/platform/integrations/n8n) integrations, or a [webhook](https://docs.apify.com/platform/integrations/webhooks) when a run finishes.
- **AI agents (MCP):** connect an MCP client such as Claude Code or Cursor to `https://mcp.apify.com?tools=clearpath-data/hiring-changes-monitor` and the agent can run this Actor directly. See the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) docs.

### How much does it cost?

| What | Price | Per 1,000 |
|---|---|---|
| Company check (summary row) | $0.005 | $5.00 |
| Job opened or closed | $0.001 | $1.00 |
| Actor start (Apify standard) | $0.00005 per GB of memory, per run | |

**Examples:**

- The test above (Spotify, 17 opened + 14 closed): $0.005 + 31 × $0.001 = **$0.036**.
- A watchlist of 50 companies checked daily, with about 3 changes per company per day (estimate): 50 × $0.005 + 150 × $0.001 = **$0.40 per day**.
- The first run for each company costs only the company check. Its current open jobs are listed free, because there's nothing to compare yet.

Platform usage (compute) is billed by Apify separately as usual.

### Limits and honest notes

- **Only public job boards on the six supported ATSs.** No social networks and no sites that need a login. Companies whose careers page uses another system can't be monitored.
- **"Closed" means the posting left the public board.** It could be filled, paused, cancelled or moved to an internal board; the API doesn't say why.
- **Re-posts:** some companies take a job down and post it again under a new ID. That shows as one closed plus one opened; `possibleRepost` marks pairs with the same title and location.
- **Timing depends on how often you run it.** A job that opens and closes between two runs is never seen.
- **SmartRecruiters company IDs are case-sensitive** ("BoschGroup"), and an unknown ID returns an empty board, which is reported as not found.
- **Polite by design:** at most 10 boards in parallel and at least 0.5 s between requests to the same job-board host. Very large watchlists take a little longer.
- **If a run stops early** (Max results or your maximum cost per run), the baseline isn't moved forward for companies whose changes were cut off, so the next run lists them again.
- Job data belongs to the companies that post it, and is read from each vendor's public job-board API.

### FAQ

**How is this different from a jobs scraper?** A jobs scraper returns every open job each time. This Actor returns only what changed, plus a per-company summary, so a daily schedule stays cheap and easy to act on.

**Where is my baseline stored?** In a key-value store named `hiring-changes-monitor-state` in your own Apify account, one record per state name and company. Delete it to start over.

**No saved state, or a new account?** Set **Compare with dataset** to the dataset of an earlier run of this Actor. Its company rows hold each board's open jobs.

**Can I export to CSV or Excel?** Yes. Every Apify dataset can be downloaded as CSV, Excel, JSON or XML. Use the **Job changes** or **Companies** view.

**What's in the run report?** The `RUN_REPORT` record lists every company's status (checked, baseline, not found), counts, changes saved, the stop reason and warnings.

### Other Clearpath Data Actors

| Actor | What it does |
|---|---|
| [ats-jobs-by-company](https://apify.com/clearpath-data/ats-jobs-by-company) | All open jobs from Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee boards |
| [uk-visa-sponsor-register](https://apify.com/clearpath-data/uk-visa-sponsor-register) | UK visa sponsor licence list from the GOV.UK register, with a changes feed |
| [us-new-business-filings](https://apify.com/clearpath-data/us-new-business-filings) | New LLCs and corporations from the NY, CO and CT state registries, since your last run |
| [remote-jobs-aggregator](https://apify.com/clearpath-data/remote-jobs-aggregator) | Remote jobs from Remote OK and Himalayas |
| [companies-house-new-companies](https://apify.com/clearpath-data/companies-house-new-companies) | New UK companies from Companies House, with officers and PSCs |
| [lei-lookup](https://apify.com/clearpath-data/lei-lookup) | LEI lookup via the GLEIF API (LEI, name, BIC, ISIN) |

# Changelog

This Actor's version history is a separate document: https://apify.com/clearpath-data/hiring-changes-monitor/changelog.md

# Actor input Schema

## `companies` (type: `array`):

One company per line. Accepts a board slug ("stripe"), a prefixed slug ("lever:spotify", "workable:huggingface", "smartrecruiters:BoschGroup", "recruitee:bunq"), a job-board URL (job-boards.greenhouse.io/airbnb, jobs.lever.co/palantir, jobs.ashbyhq.com/openai, apply.workable.com/huggingface, careers.smartrecruiters.com/BoschGroup, bunq.recruitee.com), or a company careers page URL (the Actor looks for an embedded Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee board). SmartRecruiters company IDs are case-sensitive.

## `ats` (type: `string`):

Which ATS to query for plain slugs such as "stripe". "Auto-detect" tries Greenhouse, Ashby, Lever, Workable, Recruitee, then SmartRecruiters, and uses the first board with open jobs. URLs and prefixed slugs always use their own ATS.

## `changeTypes` (type: `array`):

Which job changes to return. Leave empty for both.

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

Keep only jobs whose title contains at least one of these words (case-insensitive). Leave empty for all jobs.

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

Keep only jobs whose location (or any secondary location / country) contains at least one of these strings, e.g. "London", "Germany", "Remote".

## `remoteOnly` (type: `boolean`):

Keep only jobs marked remote by the ATS, or whose location says Remote/Anywhere.

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

Keep only jobs whose department or team contains at least one of these strings, e.g. "Engineering", "Sales".

## `stateName` (type: `string`):

Each company's open jobs are saved under this name in a key-value store named "hiring-changes-monitor-state" in your account; the next run compares against it. Use a different name per schedule or task. Letters, digits and hyphens.

## `baselineDatasetId` (type: `string`):

Instead of the saved state, compare with the dataset of an earlier run of this Actor (its company rows hold each board's open jobs). Companies not in that dataset start a new baseline.

## `updateState` (type: `boolean`):

After a company's changes are all saved, store its current open jobs so the next run starts from here. Not done for a company whose changes were cut off by Max results or your maximum cost per run.

## `currentJobsOnFirstRun` (type: `boolean`):

On a company's first check (no baseline yet), also save one row per open job matching your filters, with changeType "current". These rows are free (only the company check is charged). Later runs list only opened and closed jobs. Uses the room left under Max job changes.

## `maxResults` (type: `integer`):

Stop saving job rows after this many (0 = no limit). Opened and closed jobs count first; current jobs listed on a first check use the room that is left. Company rows are always saved for companies that were checked. Your maximum cost per run also stops the run.

## `maxConcurrency` (type: `integer`):

How many boards to read at once. Requests to the same job-board host are spaced at least 0.5 s apart regardless.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai"
  ],
  "ats": "auto",
  "changeTypes": [],
  "keywords": [],
  "locations": [],
  "remoteOnly": false,
  "departments": [],
  "stateName": "default",
  "updateState": true,
  "currentJobsOnFirstRun": true,
  "maxResults": 1000,
  "maxConcurrency": 3
}
```

# Actor output Schema

## `changes` (type: `string`):

Opened and closed jobs

## `companies` (type: `string`):

One summary row per company checked

## `runReport` (type: `string`):

Per-company status, counts, baseline used, stop reason and warnings

# 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 = {
    "companies": [
        "stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/openai"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("clearpath-data/hiring-changes-monitor").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 = { "companies": [
        "stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/openai",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("clearpath-data/hiring-changes-monitor").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 '{
  "companies": [
    "stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai"
  ]
}' |
apify call clearpath-data/hiring-changes-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,clearpath-data/hiring-changes-monitor"
        }
    }
}
```

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/OSIQQGXfYK4cA5U1G/builds/GTV0vW7hh4eZbWTcI/openapi.json
