# Job Board Monitor — New & Removed Job Alerts (7 ATS) (`opensignals/job-board-monitor`) Actor

Monitor careers pages for changes across 7 ATS (Greenhouse, Workday, Lever, Ashby +3, auto-detected from any URL). Alerts on NEW and REMOVED (filled) postings, repost/ghost-job hints, hiring-freeze detection, Slack-ready digest lines. Schedule daily. No cookies, no anti-bot issues.

- **URL**: https://apify.com/opensignals/job-board-monitor.md
- **Developed by:** [Andrey](https://apify.com/opensignals) (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

Pay per event

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/platform/actors/running/actors-in-store#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

## Job Board Monitor — New & Removed Job Alerts

*Job posting monitor & new-jobs alert tool for Greenhouse, Lever, Ashby, Workday and 3 more ATS — track new and removed job listings across careers pages.*

**Know the moment a company's hiring changes.** Point this Actor at any careers page, run it on a schedule, and get alerted about every **new posting** — and every **removed one**. A posting that disappears usually means the position was filled or closed: that's a signal almost nobody tracks, and it tells you a company just made a hire (new employee onboarding = new tooling decisions) or cut a search.

Works on top of stable public job-board APIs — **Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Workday & Personio** — so it never fights anti-bot walls and doesn't break when a page changes its layout.

### Why monitoring beats re-scraping

Scrapers give you a snapshot; you're left diffing CSVs by hand. This Actor keeps state between runs in your account and emits **only the changes**:

| Record | Meaning | Why you care |
|---|---|---|
| `new_job` | Posting appeared since last run | Fresh hiring intent — reach out while the pain is live |
| `removed_job` | Posting disappeared | Position filled or closed — congratulate, pitch onboarding tools, or note the hiring freeze |
| `board_summary` | Per-company digest | One row per company per run — includes a ready-to-send `summary_text` line for Slack/Telegram |

Extra signals baked into the records:

- **`repost_hint`** on new jobs — the same title was removed from this board within 60 days: likely a reposted/evergreen "ghost job", treat with skepticism
- **`hiring_freeze_hint`** on summaries — 3+ removals and zero additions in one run: possible hiring freeze; recruiters save their time, sellers adjust timing
- **`summary_text`** on summaries — one formatted line ("Acme: +3 new, -1 removed (120 open) — New: …") you can pipe straight into a Slack/Telegram/email integration without any templating

The first run for each board silently records a baseline (no flood of "new" alerts) — from the second run on, you only see real changes. Enable `emitBaseline` if you want the full current list on day one.

### 💥 Watch a whole niche — no list needed

Enable `watchNiche` and the Actor samples companies from its **built-in directory of ~8,800 job boards** (Common Crawl-harvested), **freezes the sample** in your account, and monitors the same companies run after run. Combine with keywords or role presets:

```json
{ "watchNiche": ["greenhouse", "ashby"], "watchLimit": 200, "keywords": ["golang"] }
```

That's a standing order: *"alert me whenever anyone in the Greenhouse/Ashby universe posts or removes a Go engineering job."* The sample stays frozen so day-to-day diffs are meaningful; delete the watchlist key in the `job-board-monitor-state` store to resample.

### Feed it anything

The `sources` field accepts, in any mix:

- **Any careers page URL** — `https://ramp.com/careers`, `https://acme.io/jobs`… The Actor fetches the page and **auto-detects the embedded ATS** (board links, embed scripts, API references)
- **Board URLs** — `boards.greenhouse.io/gitlab`, `jobs.lever.co/spotify`, `jobs.ashbyhq.com/ramp`, `apply.workable.com/blueground`, `careers.smartrecruiters.com/ServiceNow`
- **Bare slugs** (`gitlab`) or **plain company names** (`Blueground`) — probed against all five ATS providers

Optional `keywords` and `locationFilter` narrow monitoring to the roles you care about (e.g. only `sales` roles, only `remote`).

### Typical setups

- **SDR team:** monitor 100 target accounts daily, get `new_job` alerts for `SDR`, `sales`, `revops` keywords → outreach the same morning. Companies staffing sales teams are buying sales tooling.
- **Recruiting agency:** watch competitors' clients; a burst of new postings = an account that needs help, a burst of removals = placements happening without you.
- **Job seeker / talent community:** monitor dream-company boards for `remote` + your stack, pipe alerts to Telegram or email via Apify integrations.
- **Competitive intel:** removed engineering postings at a competitor often precede a launch.

### Scheduling & integrations

Designed for Apify **Schedules** (daily or hourly). Connect the run to **Slack, email, Telegram, Google Sheets, Zapier, Make or n8n** through standard Apify integrations — a run that found nothing new produces only compact `board_summary` records, so downstream alerts stay quiet unless something happened.

### Pricing

Pay per event: **$0.005 per detected change** (new or removed posting), $0.005 per board summary, $0.005 per Actor start. Monitoring 50 companies daily with a handful of changes typically costs a few cents per day. No subscriptions, no platform-usage surcharges.

### FAQ

**How is this different from job scrapers?** Scrapers re-download everything every time and leave the diffing to you. This Actor is stateful: it remembers what it saw and reports only deltas — including removals, which snapshots can't give you.

**A source shows "No ATS board found"?** The company either uses an unsupported ATS (iCIMS, Oracle HCM — on the roadmap) or a fully custom careers page with no embedded board. The Actor logs a warning and continues with your other sources.

**Where is the state kept?** In a named key-value store `job-board-monitor-state` in *your* Apify account — your tracking history stays private and survives between runs.

**Something broken or missing a feature?** Open an issue on the Actor's Issues tab — I respond within 1–2 business days.

***

*Need company-level hiring analytics instead of alerts — scored leads, tech-stack detection, seniority mix, hiring velocity? Check the companion Actor: [ATS Hiring Signals](https://apify.com/opensignals/ats-hiring-signals).*

# Actor input Schema

## `sources` (type: `array`):

Anything that points at a company's jobs: a careers page URL (`https://acme.com/careers` — the embedded ATS is auto-detected), a board URL (`boards.greenhouse.io/gitlab`), a bare slug (`gitlab`) or a plain company name.

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

Only track jobs whose title/department/location contains ANY of these. Leave empty to track the whole board.

## `locationFilter` (type: `array`):

Only track jobs whose location contains any of these substrings, e.g. `remote`, `berlin`.

## `searchDescriptions` (type: `boolean`):

Slower but catches tech-stack mentions buried in the description text.

## `notifyOn` (type: `array`):

`new` = postings that appeared; `removed` = postings that disappeared (position likely filled or closed).

## `emitBaseline` (type: `boolean`):

By default the first run for a board only records the baseline (no flood of `new_job` items). Enable to also output every currently open job on the first run.

## `rolePresets` (type: `array`):

Curated keyword bundles — pick roles instead of inventing keywords. Adds terms like `account executive`, `sdr`, `revops` (sales) or `backend`, `sre` (engineering) to your keywords.

## `watchNiche` (type: `array`):

Monitor a random-but-frozen sample of companies from the built-in directory of ~8,800 job boards. Pick ATS universes; combine with keywords ('watch everyone hiring Go engineers'). The sample is frozen on first run so day-to-day diffs stay meaningful.

## `watchLimit` (type: `integer`):

How many companies to keep under watch (frozen sample).

## Actor input object example

```json
{
  "sources": [
    "https://boards.greenhouse.io/gitlab",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "keywords": [],
  "locationFilter": [],
  "searchDescriptions": false,
  "notifyOn": [
    "new",
    "removed"
  ],
  "emitBaseline": false,
  "rolePresets": [],
  "watchNiche": [],
  "watchLimit": 100
}
```

# Actor output Schema

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

Postings that appeared or disappeared since the previous run

## `summaries` (type: `string`):

One digest row per monitored company: tracked/new/removed counts

## `allResults` (type: `string`):

All record types in one dataset

# 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 = {
    "sources": [
        "https://boards.greenhouse.io/gitlab",
        "https://jobs.ashbyhq.com/ramp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("opensignals/job-board-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 = { "sources": [
        "https://boards.greenhouse.io/gitlab",
        "https://jobs.ashbyhq.com/ramp",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("opensignals/job-board-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 '{
  "sources": [
    "https://boards.greenhouse.io/gitlab",
    "https://jobs.ashbyhq.com/ramp"
  ]
}' |
apify call opensignals/job-board-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,opensignals/job-board-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/J8XMS7k8t0MGfFang/builds/sMvRYWPunNxhuqEEw/openapi.json
