# Stale Job Listing Checker — Greenhouse, Lever & Ashby (`mrtronson/job-listing-status-auditor`) Actor

Audit existing job URLs against live ATS boards. Find missing listings and stale titles in one grouped check, independent of your original scraper. $0.05 per audit, up to 5,000 jobs.

- **URL**: https://apify.com/mrtronson/job-listing-status-auditor.md
- **Developed by:** [Typed Diff](https://apify.com/mrtronson) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$50.00 / 1,000 delivered audits

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

### Check whether the jobs in your catalog are still listed

**Audit existing job URLs against current Greenhouse, Lever and Ashby public job feeds.** Get a review queue of listings that are no longer present, listings marked unlisted, and titles or locations that have changed.

Paste your catalog's job URLs and run. The Actor groups them by company board, so 1,000 jobs at one company are checked against one board snapshot instead of making 1,000 separate page requests. Lever boards are read page by page.

### Why use this job listing status checker?

Job boards and recruiting pipelines often collect listings from multiple suppliers. A supplier-specific expired-ID feed cannot reconcile another supplier's IDs, and an HTTP 200 response does not prove a job is still listed. This Actor uses the original public ATS job URL and current board membership. It works on demand, with no monthly subscription or third-party API key.

Use Apify's API to connect it to a catalog pipeline, or schedule an Apify task to recheck the same URLs. Your source catalog is never modified. Review the output before changing or removing listings.

### How to use it

1. Replace the example with job URLs from your catalog.
2. Optionally supply each URL as an object with your stored `title` and `location`.
3. Run the Actor and filter the results by `reviewRequired`.
4. Export the dataset in JSON, CSV or Excel, or retrieve it through the Apify API.

### Input

```json
{
  "jobs": [
    {
      "url": "https://jobs.ashbyhq.com/ashby/390e266b-4b6c-4490-ad74-05ff5e0bb36a",
      "title": "Product Manager, Onboarding and Growth"
    }
  ]
}
```

Supports Greenhouse `boards.greenhouse.io` and `job-boards.greenhouse.io`, Lever `jobs.lever.co` and `jobs.eu.lever.co`, and Ashby `jobs.ashbyhq.com`. Provide job URLs, not company homepages. Limits: 5,000 input jobs, 20 company boards, 10,000 source jobs per board and 12 MB per source response. Larger or incomplete responses are reported as unknown, never silently truncated into missing-job results.

### Output

| Field | Meaning |
|---|---|
| `status` | `listed`, `unlisted`, `not_listed`, or `unknown` |
| `currentTitle`, `currentLocation` | Current source values, when found |
| `titleChanged`, `locationChanged` | Comparisons when the corresponding catalog value was supplied |
| `reason` | Why this result was produced |
| `sourceUrl`, `sourceJobCount`, `checkedAt` | Evidence for the board snapshot |
| `reviewRequired` | True for missing, unlisted or unverifiable listings |

Input order and duplicate catalog rows are preserved so you can join the results back to your own records using `inputIndex`. A full report is also saved under `OUTPUT` in the run's key-value store.

### Price

$0.05 per delivered audit, covering up to 5,000 input jobs across 20 company boards. One event per run, regardless of how many changed or missing listings are found. Invalid input and runs where no board can be verified do not incur the audit event. An audit with some unavailable boards still costs $0.05; those jobs are explicitly marked unknown. Platform usage is included under the published pay-per-event model.

### Interpretation and support

`not_listed` means absent from the public feed at the check time. It is a review signal, not proof that the employer filled the role: a job may become private, move boards, or temporarily disappear. `unlisted` is an explicit Ashby listing flag; the direct application link may still work. `listed` is not a guarantee that applications will be accepted.

The Actor checks the public APIs documented by [Greenhouse](https://docs.greenhouse.io/job-board.html), [Lever](https://github.com/lever/postings-api), and [Ashby](https://developers.ashbyhq.com/docs/public-job-posting-api). It does not log in, submit applications, bypass blocks, or use residential proxies. Board data can change during a check; rerun consequential missing-job findings before making catalog changes. Report unsupported URL formats or source failures in the Issues tab.

# Actor input Schema

## `jobs` (type: `array`):

1–5,000 HTTPS job URLs from Greenhouse, Lever (global/EU), or Ashby. Or objects with url and optional title/location to compare. Maximum 20 company boards. Only public board APIs are read.

## Actor input object example

```json
{
  "jobs": [
    {
      "url": "https://jobs.ashbyhq.com/ashby/390e266b-4b6c-4490-ad74-05ff5e0bb36a",
      "title": "Product Manager, Onboarding and Growth"
    }
  ]
}
```

# Actor output Schema

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

No description

## `report` (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 = {
    "jobs": [
        {
            "url": "https://jobs.ashbyhq.com/ashby/390e266b-4b6c-4490-ad74-05ff5e0bb36a",
            "title": "Product Manager, Onboarding and Growth"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrtronson/job-listing-status-auditor").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 = { "jobs": [{
            "url": "https://jobs.ashbyhq.com/ashby/390e266b-4b6c-4490-ad74-05ff5e0bb36a",
            "title": "Product Manager, Onboarding and Growth",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("mrtronson/job-listing-status-auditor").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 '{
  "jobs": [
    {
      "url": "https://jobs.ashbyhq.com/ashby/390e266b-4b6c-4490-ad74-05ff5e0bb36a",
      "title": "Product Manager, Onboarding and Growth"
    }
  ]
}' |
apify call mrtronson/job-listing-status-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrtronson/job-listing-status-auditor"
        }
    }
}
```

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/MUTmlbT1WJYjnRJQs/builds/IBLxx8F0q1vaAvkIE/openapi.json
