# Track Hiring Changes on Greenhouse Boards (`fluxory/hiring-activity-monitor`) Actor

Detect public Greenhouse job board changes between observations, with baseline-aware summaries of new, missing, and updated job posts.

- **URL**: https://apify.com/fluxory/hiring-activity-monitor.md
- **Developed by:** [yohei kotani](https://apify.com/fluxory) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 board 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?

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

## Hiring Activity Monitor

Detect changes in a company's public Greenhouse job board between observations.

This Actor is intentionally a hiring-activity monitor, not a generic job
scraper. Each successful check compares the current public board with the
previous snapshot for the same monitor and returns new, missing, and changed
job posts.

### Supported source

MVP support is limited to the public [Greenhouse Job Board API](https://developers.greenhouse.io/job-board.html).
No proxy, browser automation, AI API, or external database is used.

### Input

```json
{
  "targets": [
    {
      "board": "greenhouse",
      "monitorId": "greenhouse-main",
      "label": "Greenhouse Software"
    }
  ]
}
```

- `targets` contains 1 to 25 targets.
- `board` accepts a Greenhouse board token, a `boards.greenhouse.io` URL, or a
  `job-boards.greenhouse.io` URL.
- `monitorId` is optional and defaults to `default`. Use a different value to
  keep separate observations for the same board.
- A `board` plus `monitorId` pair must be unique within one run.

### Output

The default dataset receives one record for each processed target.

- `baseline_created` — the first successful observation. Existing jobs are
  recorded as the baseline, not reported as newly added.
- `success` — a comparison with the previous successful observation.
- `error` — an input, Greenhouse retrieval, validation, or storage-preflight
  error. It does not advance the monitor state.

Successful records include an `observationId`, a summary, the current
normalized jobs, and `changes.added`, `changes.removed`, and
`changes.updated`. Consumers can use `observationId` to deduplicate outcomes
when retrying runs.

`removed` means that a job was present in the preceding observation but is
absent from the current Greenhouse response. It does not prove when, or why,
the role closed.

To keep a dataset item within the platform limit, details may be shortened and
`detailsTruncated` set to `true`. Summary counts always remain complete.

### State and isolation

The Actor stores the full normalized snapshot in a named Apify Key-value Store
owned by the Apify account running the Actor. State is keyed by the normalized
board token and `monitorId`; internal store IDs and state keys are not emitted
in the dataset.

This relies on Apify account storage boundaries. Run the Actor through an
authenticated Apify account when continuity is required. Stateless or
account-less payment flows are not supported for stateful monitoring.

Do not run the same `board` and `monitorId` concurrently. The MVP deliberately
uses at-least-once processing rather than distributed locking or exactly-once
semantics. If state persistence fails after a successful charge, a later retry
can emit the same `observationId` again.

### Pricing

| Event | Price | When charged |
| --- | ---: | --- |
| `board-check` | $0.01 | One successfully checked board, including a baseline or unchanged board |
| `apify-actor-start` | $0.00005 | Automatically when the Actor starts |

The default-dataset-item event is disabled. Greenhouse, input, validation, and
state-size errors do not charge `board-check` and do not update state. The
automatic Actor-start event still applies to every run.

Set a run maximum cost high enough for the requested checks: at least
`$0.00005 + ($0.01 × number of boards)`. The configured minimum is `$0.011`,
which permits one board check. When the board-check cost limit is reached, the
Actor stops before processing later targets.

### Operational limits

- Greenhouse response cap: 10 MiB.
- Persisted state safe cap: 8 MiB.
- Dataset item safe cap: 8 MiB.
- Greenhouse prospect posts (`internal_job_id: null`) are excluded from
  comparisons and reported only as a count.
- Transient Greenhouse failures such as timeout, HTTP 429, and HTTP 5xx are
  retried up to two times. Invalid responses and HTTP 4xx errors other than
  429 are not retried.

### API and MCP use

Run this Actor through the standard authenticated Apify API or an authenticated
Apify MCP integration. Preserve the same Apify account and `monitorId` across
runs to retain the baseline. The dataset's JSON records are designed for
machine consumption; no AI model is required.

### Development

Requires Node.js 22.18 or later.

```sh
npm test
npm start
```

Before a Store release, verify the daily test, pricing configuration, and
runtime cost on the intended Apify account. This repository's Actor is kept
private until publication is explicitly approved.

# Actor input Schema

## `targets` (type: `array`):

Between 1 and 25 Greenhouse board tokens or supported board URLs. board + monitorId must be unique.

## Actor input object example

```json
{
  "targets": [
    {
      "board": "greenhouse",
      "monitorId": "greenhouse-main",
      "label": "Greenhouse Software"
    }
  ]
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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 = {
    "targets": [
        {
            "board": "greenhouse",
            "monitorId": "greenhouse-main",
            "label": "Greenhouse Software"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fluxory/hiring-activity-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 = { "targets": [{
            "board": "greenhouse",
            "monitorId": "greenhouse-main",
            "label": "Greenhouse Software",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("fluxory/hiring-activity-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 '{
  "targets": [
    {
      "board": "greenhouse",
      "monitorId": "greenhouse-main",
      "label": "Greenhouse Software"
    }
  ]
}' |
apify call fluxory/hiring-activity-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fluxory/hiring-activity-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/hdPhzMT1AruU3Eql0/builds/nUqktAyd2wvEfcaHb/openapi.json
