# Greenhouse & Ashby Job Change Monitor (`fluffy_ingot/job-board-change-feed`) Actor

Monitor up to 5 public Greenhouse and Ashby job boards. Export new, removed and edited jobs in CSV, JSON and an HTML report. Reuse a saved baseline for recurring checks; failed fetches preserve it. Salary and workplace fields appear only when supplied.

- **URL**: https://apify.com/fluffy\_ingot/job-board-change-feed.md
- **Developed by:** [yipee Gameplay](https://apify.com/fluffy_ingot) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / completed job board report

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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?

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

## Greenhouse & Ashby Job Change Monitor

Track **what changed on your target companies' Greenhouse and Ashby job boards**: new roles, removed postings, and edits to titles, locations and selected job fields. For Ashby, compare published salary and remote/hybrid/onsite fields when the source supplies them.

Save a baseline once, then run recurring checks to build a hiring-change feed for recruiting research, target-company monitoring or job-market analysis. Reports include exact before/after values, board health and CSV/JSON exports.

**One report covers up to 5 named boards. Base price: $0.50 per completed report + $0.00005 per start; platform usage included.** Jobs and findings are not individually billed. First-baseline and no-change reports also incur the report fee. The live Pricing tab shows your current price and tier discounts.

You can inspect the synthetic output below before running. [Run the same sample](https://apify.com/fluffy_ingot/job-board-change-feed/examples/detect-new-removed-and-changed-jobs-with-sample-data) with the displayed Actor price; it needs no live board or baseline store.

### Preview the example output

The synthetic demo produces the following changes. Reading this preview does not start a run:

| Change | Example |
| --- | --- |
| New | Developer Advocate appears |
| Removed | Operations Analyst is absent from the complete current board |
| Changed | Data Engineer changes from Hybrid to Remote and its published salary range changes from $100,000–$130,000 to $115,000–$145,000 |

The default dataset contains **one report summary**, not one charged item per job. Open **Readable change report** for board health and expandable before/after details. JSON, CSV and snapshot downloads appear alongside it.

### Monitor real boards

1. Choose **Live named boards**.
2. Enter one to five board objects. Greenhouse's board token appears in its hosted careers URL; Ashby's board name appears after `jobs.ashbyhq.com/`. Slugs are case-sensitive. Do not paste a whole URL.
3. For automatic comparison, create a **named key-value store** in your Apify account and select it under **Persistent baseline store**. Its ID is supplied by the picker. First run establishes a baseline; subsequent runs report differences.
4. Save a task and add an Apify schedule. Run a single schedule at a time against each baseline store. Choose a frequency that matches how quickly you need changes; this Actor does not send messages or create schedules itself.

```json
{
  "mode": "live",
  "boards": [
    {"provider": "greenhouse", "board": "YOUR_BOARD_TOKEN"},
    {"provider": "ashby", "board": "YourCompany"}
  ],
  "baselineStoreId": "YOUR_17_CHAR_ID_HERE"
}
```

Replace the placeholders with actual slugs and the selected store ID. You can omit `baselineStoreId` and pass a previous `SNAPSHOT` object as `previousSnapshot` instead. With neither input, the run produces a first baseline rather than treating every existing job as new.

#### Plan the recurring cost

At the base price, one scheduled report per day is **$15.0015 for 30 runs**. A 12-run month is **$6.0006**. These examples assume the same $0.50 report + $0.00005 start price, successful report generation, no extra runs, and unchanged pricing. Each report may cover all five boards within the stated limits.

Run only as often as your workflow needs. A report with no detected changes still incurs the report fee. If you already store prior `SNAPSHOT` outputs, supplying `previousSnapshot` avoids creating a separate persistent store; your workflow must pass the correct baseline each time.

### Automation example

**Named board → saved task → daily schedule → report → your downstream workflow.** Keep the board list and named store consistent between runs. On a successful run, read the default dataset's one summary item. If `newJobs`, `removedJobs` or `changedJobs` is greater than zero, use the `REPORT` or `changes.csv` record in that run's default key-value store. If `boardsFailed` is nonzero, inspect per-board health before drawing conclusions.

Apify's API tab provides the request and authorization code for your task. A downstream Make, n8n or API workflow can consume the returned report; configure any delivery destination yourself. API tokens never belong in Actor input. To replay saved observations with no source requests, choose **Compare saved snapshots** and supply `previousSnapshot` and `currentSnapshot` objects copied from this Actor's `SNAPSHOT` output.

### What is compared

| Field | Greenhouse | Ashby |
| --- | --- | --- |
| Title, location, departments and job URL | Yes | Yes |
| Secondary office/location names | When returned | When returned |
| Team and employment type | Unavailable | When returned |
| Explicit remote / hybrid / onsite value | Unavailable | When returned |
| Exact structured compensation | Unavailable in the list endpoint | When returned |
| Description change | SHA-256 hash | SHA-256 hash |

Missing values remain `null`; they are not inferred from titles or descriptions. Compensation retains the source's reported currency, interval, ranges and summaries, without currency conversion or annualization. Formatting edits may alter a description hash. Timestamp-only edits do not count as substantive changes.

Greenhouse identity uses its post ID. Ashby identity uses its documented job URL, so a URL change is reported as a removal plus an addition. The monitor excludes Ashby `isListed: false` postings. An absent posting means **removed from the public board**, not proof it was filled or that the company stopped hiring.

### Reports and baseline safety

- `REPORT`: summary, per-board health and up to 1,000 complete change details.
- `changes.csv`: formula-escaped change rows, summary and board health rows.
- `report.html`: readable report with expandable exact differences and no external scripts.
- `SNAPSHOT`: normalized observations to reuse later. Failed boards retain their previous complete snapshot when one exists.

Statuses distinguish `baseline_created`, `no_change`, `changes_found`, `partial_success` and failed boards. HTTP errors, 429 rate limits, invalid JSON, duplicates, incomplete responses and exceeded limits never produce removals or replace a good baseline. A genuinely complete empty board can produce removals.

Persistent snapshots use separate `JOBS-V1-*` records for each board in the selected named store. Only that supplied store requests read/write access; limited permissions are sufficient. Store access errors are reported. A pre-write recheck detects many overlapping-run conflicts, but storage and billing are not atomic. **Do not overlap runs using the same baseline store.** A storage write warning can cause the next run to repeat changes; the completed report remains downloadable.

### Price and limits

Launch configuration: **$0.50 per completed bounded report**, plus **$0.00005 per Actor start** at 256 MB. Platform usage is included. One report can cover up to five boards; findings and jobs are not charged individually. Set a maximum total charge of **$0.51** or higher at these prices. The Store pricing page is authoritative.

First-baseline, no-change, synthetic demo and partial-success reports are completed reports and incur the report fee. If every live board fails, the run saves diagnostic reports and fails **without charging a completed-report event**; the start fee may still apply. The runtime checks the remaining report budget before source requests.

Limits: five boards, 1,000 jobs per board, 2,500 jobs per run, 4 MB per source response, 1.5 MB per normalized board and 4 MB per normalized snapshot. Source requests use two concurrent connections at most, a 20-second hard deadline each and no redirects or retries. The recommended Actor timeout is 120 seconds with restart-on-error off. Full change counts are returned even if details exceed the 1,000-change cap. A board that exceeds a fetch or job limit is failed as a whole; its snapshot is not silently truncated.

### Source scope and support

This Actor uses the documented [Greenhouse Job Board API](https://docs.greenhouse.io/job-board.html) and [Ashby public job-posting API](https://developers.ashbyhq.com/docs/public-job-posting-api). It makes one list request per selected board. No login, proxy, arbitrary URLs, application endpoints, candidate information or inferred personal profiles are used. It does not bypass access controls or rate limits.

For an issue, provide the run link, provider and board slug, expected behavior and a small synthetic reproduction when possible. Do not send API tokens, applicant records or private job data. Source format changes may require an update; no report guarantees that a source has reported every vacancy.

### More previews and related tools

[Watch the 32-second synthetic portfolio demo](https://api.apify.com/v2/key-value-stores/pUK33haAXl69dRu1G/records/preflight-actors-demo.mp4?signature=1nIZqH2Dg5GUlcwpyKtnI) for a walkthrough of the four tools. The video uses sample data.

- [Shopify CSV Import Checker & Supplier Catalog Diff](https://apify.com/fluffy_ingot/supplier-catalog-preflight)
- [Google Merchant Feed Validator & Price Checker](https://apify.com/fluffy_ingot/merchant-feed-preflight)
- [OpenAPI JSON Diff & Breaking Change Checker](https://apify.com/fluffy_ingot/openapi-change-preflight)

# Actor input Schema

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

Demo returns one synthetic new, removed and changed job. Demo is still a completed report at the displayed Store price. Live reads only selected public ATS boards. Offline compares normalized SNAPSHOT outputs.

## `boards` (type: `array`):

Live mode only. One to five objects such as {"provider":"greenhouse","board":"your-board-token"} or {"provider":"ashby","board":"YourCompany"}. Use the exact board slug, not a URL. Maximum 1,000 jobs each and 2,500 total.

## `baselineStoreId` (type: `string`):

Optional in live mode. Select an existing NAMED key-value store in your account. The picker provides its 17-character ID. One record per board retains the last complete snapshot. No overlapping runs against the same store.

## `previousSnapshot` (type: `object`):

Optional previous normalized SNAPSHOT output. First observation creates a baseline and does not count existing jobs as new. Cannot be combined with a persistent store. Each snapshot maximum 4 MB and 2,500 jobs.

## `currentSnapshot` (type: `object`):

Required in offline mode. Paste normalized SNAPSHOT output, not raw ATS data. Must contain complete boards and ISO observation times. Demo mode supplies both synthetic snapshots automatically.

## Actor input object example

```json
{
  "mode": "demo"
}
```

# Actor output Schema

## `report` (type: `string`):

Board health, exact selected-field differences and coverage limits.

## `json` (type: `string`):

Aggregate counts, up to 1,000 detailed changes and per-board health.

## `csv` (type: `string`):

Formula-escaped change rows plus summary and board health.

## `snapshot` (type: `string`):

Normalized last complete observations. Failed boards retain prior good snapshots when available.

# 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": "demo"
};

// Run the Actor and wait for it to finish
const run = await client.actor("fluffy_ingot/job-board-change-feed").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": "demo" }

# Run the Actor and wait for it to finish
run = client.actor("fluffy_ingot/job-board-change-feed").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": "demo"
}' |
apify call fluffy_ingot/job-board-change-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fluffy_ingot/job-board-change-feed"
        }
    }
}
```

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/rqGQlgHxCnhJg6fYM/builds/cGBBbxn0b4L9qukjC/openapi.json
