# Company Hiring Monitor — Jobs from Careers Pages (`farodata/company-hiring-monitor`) Actor

Paste job-board URLs (Greenhouse, Lever, Ashby, Workable), get every open job normalized to one schema — fresh from the source. Run it weekly and see exactly which roles opened, closed or changed.

- **URL**: https://apify.com/farodata/company-hiring-monitor.md
- **Developed by:** [Andrea Moscariello](https://apify.com/farodata) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 job returneds

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

## Company Hiring Monitor — every open job from the careers pages you care about

Paste job-board URLs. Get **every open position, normalized to one clean schema** — pulled live from the official job-board APIs (Greenhouse, Lever, Ashby, Workable), not from a stale index. Run it weekly and the summary tells you **exactly which roles opened, closed or changed**.

> **Platform compute is on me — you only pay for results delivered.** No second bill for
> compute time: the price below is the whole price.

![Real output: Greenhouse, Ashby and Workable companies side by side in the same columns — company, ATS, job title, location, department, publish date and a direct link](https://api.apify.com/v2/key-value-stores/06HZt1FFXiST6Ncc2/records/chm-results-table.png)

- ✅ **Fresh to the minute** — data comes straight from each company's own job board at run time, not from a crawl that happened hours ago.
- ✅ **One schema across four ATS platforms** — title, location(s), remote flag, department, employment type, publish date, URL, description excerpt: same fields whoever the company uses.
- ✅ **Change tracking built in** — select your previous results and the summary lists new, closed and changed positions per company. Hiring moves are business signals: who's scaling sales, who froze engineering.
- ✅ **Paste-a-URL simplicity** — no need to know *which* ATS a company uses: paste the URL of its job board (`boards.greenhouse.io/…`, `jobs.lever.co/…`, `jobs.ashbyhq.com/…`, `apply.workable.com/…`) and the Actor works out the platform and the company for you — or write `platform:slug` yourself.

### Who is this for?

- **Recruiters & sourcers**: watch target companies' openings without visiting ten career sites.
- **B2B sales & lead gen**: "they just opened 5 sales roles" is a buying signal — get it weekly, per company.
- **Job boards & aggregators**: a clean, normalized feed for specific companies, on demand.
- **Analysts & founders**: track competitors' hiring as a strategy signal.

### What do you get?

One item per open position — this is a real row from a real run (the description excerpt is shortened here; the Actor returns up to 400 characters):

```json
{
    "type": "job",
    "company": "gitlab",
    "platform": "greenhouse",
    "jobId": "8503792002",
    "title": "Account Executive - Italy",
    "locationText": "Remote, Italy",
    "locations": ["Italy"],
    "remote": true,
    "department": "EMEA - Commercial",
    "publishedAt": "2026-04-17T09:58:03.000Z",
    "url": "https://job-boards.greenhouse.io/gitlab/jobs/8503792002",
    "descriptionExcerpt": "GitLab is the intelligent orchestration platform for DevSecOps..."
}
```

![The run summary: totals, and what changed since the previous run — 23 new roles, 16 closed, 10 changed across 7 companies](https://api.apify.com/v2/key-value-stores/06HZt1FFXiST6Ncc2/records/chm-summary-delta.png)

Plus one `summary` item per run: per-company counts, error accounting, and — when you select a previous run — the **delta**:

```json
"delta": {
    "newJobs": [{ "company": "gitlab", "title": "Staff Engineer, Ruby", "url": "..." }],
    "closedJobs": [{ "company": "spotify", "title": "Ad Sales Lead" }],
    "changedJobs": [{ "company": "notion", "field": "location", "before": "NYC", "after": "Remote" }]
}
```

### How much does it cost?

Transparent pay-per-event pricing — you pay for what is delivered:

| Event | Price |
|---|---|
| Company checked (1 careers page, any size) | **$0.02** |
| Job returned (normalized) | **$0.002** ($2.00 / 1,000 jobs) |

**Example: watching 10 companies with ~40 open roles each ≈ $1.00 per run — about $4.30/month on a weekly schedule.** Failed companies are never charged. No API keys needed; the sources are the companies' own public job boards.

### How to use it (3 steps)

![The input form: one job-board URL per line, how many jobs per company, whether to include the description, and the previous run to compare with](https://api.apify.com/v2/key-value-stores/06HZt1FFXiST6Ncc2/records/chm-input-form.png)

1. Paste one job-board URL per line (e.g. `https://boards.greenhouse.io/gitlab`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/notion`). **It has to be the URL of the job board itself** — one of the four supported hosts — not the company's own careers page: `notion.so/careers` and the like are not recognised. Most careers pages link straight to the board, so open the company's careers page, click through to the list of openings, and copy *that* address. You can also write `platform:slug` directly (e.g. `greenhouse:gitlab`).
2. Run it. Export the table, or read it right in the Output tab.
3. To track changes: next run, select the previous results in **Previous run results** — the summary gains the new/closed/changed lists. Use [Apify Schedules](https://docs.apify.com/schedules) to make it weekly.

### Supported platforms

Greenhouse, Lever, Ashby, Workable — together they host the careers pages of most tech and scale-up companies. More platforms land based on demand: ask in Issues.

### Is it legal?

Yes. The Actor reads the **official public job-board APIs** that these platforms provide precisely so that job postings can be listed — the same data any visitor sees on the careers page. No login, and no scraping of protected content. It collects company data, not people: email addresses are removed from description excerpts, though those excerpts quote the public posting text and a company may have written other contact details into it.

### FAQ

#### How fresh is the data?

As fresh as it gets: each run queries the company's job board live. If a role was published five minutes ago, it's in your results.

#### Do I need to know which ATS a company uses?

No. Paste the URL of the company's **job board** — one of the four supported hosts — and the Actor works out both the platform and the company. What it does *not* recognise is a company's own careers page on its own domain (`notion.so/careers`, `about.gitlab.com/jobs`): those are ordinary web pages, and every company builds them differently. Open one, click through to the list of openings, and copy that address instead. Or write the explicit form `platform:slug` (e.g. `greenhouse:gitlab`).

#### Can I monitor hiring changes over time?

Yes — that's the point. Keep the same company list, select the previous run's dataset, and read the delta: new, closed and changed positions per company. Companies added to or removed from your list between runs are excluded from the comparison, so dropping a company from your list never shows up as that company closing every role.

#### Does turning off the description excerpt cost me anything else?

No. Greenhouse hands us the department, the office list and the description in one bundle, so asking for the light version used to empty those two columns as well. The Actor now always asks for the full bundle and simply does not return the description when you switch it off — the department and the office list stay filled on every platform, whatever you choose.

#### What happens if a careers page is down or a slug is wrong?

That company is reported as failed in the summary — with the reason — and is **not charged**. The rest of your list proceeds normally.

#### Is there a cap on results?

Default 300 jobs per company (configurable up to 1,000). The cap bounds what a single company can cost you, and you're only charged for jobs actually returned.

#### What if a company that had 40 roles suddenly shows zero?

You get the closures — that is the point of the tool — plus a flag on that company in the summary. A whole board emptying at once is sometimes a real hiring freeze and sometimes a company that moved or renamed its job board, and no ATS API tells the two apart. We report it and say so, rather than picking one for you.

#### What happens to the delta if a company hits the cap?

That company is **excluded from new/closed** for that run, and flagged `truncated: true` in the summary. Reason: a position missing from a capped list may simply be beyond the cap, not closed — and we would rather show nothing than a false closure. If a company you follow is near the cap (large boards often are), raise **Max jobs per company** so its delta stays complete.

#### Why not SmartRecruiters?

It was supported during development and was deliberately removed before release. Their API
host publishes a `robots.txt` that allows the endpoint we would use to one named crawler and
disallows it to everyone else — an explicit choice about that exact path, not a generic rule
aimed at search engines. The other four platforms carry no such restriction, and we would
rather ship four platforms we can stand behind than five with an asterisk. If you need
SmartRecruiters, say so in Issues: the right route is asking them for access, and demand is
what would justify it.

#### Why is "Remote" not a column in the results table?

Because it would be empty about half the time, and a half-empty column reads as a broken
product rather than as missing information. Only some job boards state it explicitly; on the
others we will not guess. The flag is still in the data (`remote`, `true`/`false`, absent when
the source does not say) and in the **All fields** view — and in practice the **Location**
column already tells you: a remote role reads "Remote — Illinois". The same applies to
`employmentType` and `salary`, which most boards simply do not publish.

#### What if I set a maximum cost per run?

Apify lets you cap what a single run can charge. This Actor respects that cap **company by
company**: it delivers a company's positions, charges for that company, then moves to the
next. When your cap is reached it stops cleanly — you keep (and pay for) everything
delivered so far, and the run summary lists the companies it did not reach, so you know
exactly what is missing. Those companies are also left out of the new/closed comparison:
their positions are absent from the data, not from the market, and reporting them as
closed would be wrong.

#### How much does the prefilled demo run cost?

The three prefilled companies return roughly 400–450 positions, so a demo run costs about **$0.91**. Lower **Max jobs per company** to try it for less.

### Support

Found an issue or want another ATS platform supported? Open an issue on the **Issues** tab — issues are answered within one business day.

***

*Independent, **unofficial** tool: not affiliated with, endorsed or sponsored by Greenhouse, Lever, Ashby or Workable — their names are used only to identify the public job-board APIs being read. Only company data is collected; email addresses are redacted from description excerpts, which may still quote the public posting text. You are responsible for how you use the data.*

# Actor input Schema

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

One per line: the URL of a company's job board on Greenhouse, Lever, Ashby or Workable (e.g. https://boards.greenhouse.io/gitlab) — not the company's own careers page. You can also write platform:slug, e.g. greenhouse:gitlab.

## `maxJobsPerCompany` (type: `integer`):

Safety cap per company: it bounds what a single company can cost you. A company whose list is cut by this cap is left out of the new/closed comparison (a missing position might simply be beyond the cap), so raise it for companies with large boards.

## `includeDescription` (type: `boolean`):

Include a plain-text excerpt of each job description. Turning it off costs you nothing else: the department and the office list stay filled on every platform.

## `previousDataset` (type: `string`):

Select the dataset (results) of a previous execution with the same companies. The summary will include the delta: which positions opened, closed or changed since then.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/gitlab",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/notion"
  ],
  "maxJobsPerCompany": 300,
  "includeDescription": true
}
```

# Actor output Schema

## `jobs` (type: `string`):

One item per open position (unified schema across ATS platforms), plus one summary item with per-company counts and the delta vs a previous run.

# 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": [
        "https://boards.greenhouse.io/gitlab",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/notion"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("farodata/company-hiring-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": [
        "https://boards.greenhouse.io/gitlab",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/notion",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("farodata/company-hiring-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": [
    "https://boards.greenhouse.io/gitlab",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/notion"
  ]
}' |
apify call farodata/company-hiring-monitor --silent --output-dataset

```

## MCP server setup

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