Job Lifecycle Monitor - Ghost Jobs & Reposts
Pricing
from $4.00 / 1,000 change event reporteds
Job Lifecycle Monitor - Ghost Jobs & Reposts
Watch company career pages on a schedule and get only what changed: roles opened, closed, quietly republished under a new ID, or silently edited. Detects ghost jobs by scoring roles against board median age and republish history. Greenhouse, Ashby, Lever and SmartRecruiters. Remembers between runs.
Pricing
from $4.00 / 1,000 change event reporteds
Rating
0.0
(0)
Developer
DONGMIN KIM
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 hours ago
Last modified
Categories
Share
Job Lifecycle Monitor — Track Openings, Closures, Reposts & Ghost Jobs
Paste company domains and watch them on a schedule. You get only what changed: roles opened, roles closed, roles quietly republished under a new ID, and silent edits to titles, locations or salary ranges.
No need to know which ATS each company uses — the board is discovered and verified for you across Greenhouse, Ashby, Lever and SmartRecruiters.
Why this data does not exist anywhere else
Every ATS publishes when a role opened. None of them publish when it closed, that it was reposted last month under a different ID, or that the salary band changed on Tuesday.
Those facts only exist for someone who was watching. They cannot be back-filled, bought, or reconstructed after the fact — not by you, and not by anyone who starts later.
That has a practical consequence worth understanding before you start: the first run is a baseline and reports no change events. From the second run onward you get the half of the job market nobody else has.
Events
| Event | What it means |
|---|---|
opened | A role that was not there last run |
closed | A role that disappeared, with daysOpen |
reposted | The same role under a new ID — matched on a normalised title and city, so seniority tweaks and "Seoul" vs "Seoul, KR" still match. The strongest ghost-job signal there is. |
reopened | The same ID came back after closing |
edited | Title, location or salary changed silently, with before and after |
Plus ghost-suspect rows scoring open roles against their own board's median age and
their republish history.
Input
{"boardUrls": ["stripe.com", "notion.so", "https://jobs.ashbyhq.com/ramp"],"eventTypes": ["opened", "closed", "reposted", "edited"],"emitGhosts": true,"minGhostScore": 40,"titleContains": ["engineer"],"memoryStoreName": "job-lifecycle-state"}
Every option
The same wording you see in the Apify console, with the JSON key for API and MCP callers.
| Option | What it does | Default |
|---|---|---|
Companies to watch — boardUrls (required) | Paste plain company domains — stripe.com, notion.so — and the ATS board is found and verified automatically. Careers URLs work too: boards.greenhouse.io/<company>, jobs.ashbyhq.com/<company>, jobs.lever.co/<company>, jobs.smartrecruiters.com/<Company>. | — |
Events to report — eventTypes | opened and closed are the basics. reposted catches the same role republished under a new ID — the strongest ghost-job signal. edited catches silent title, location or salary changes. | ["opened","closed","reposted","reopened","edited"] |
Report ghost-job suspects — emitGhosts | Score every open role against its own board's median age and report the outliers. | true |
Minimum ghost score — minGhostScore | 0-100. Below 40 gets noisy on boards that legitimately keep evergreen roles open. Note the ceiling: republish history is worth up to 40 points and only exists once this actor has watched a board for a while, so early runs top out at 65. Each row carries ghostScoreMax so you can see which ceiling applied. | 40 |
Only roles whose title contains — titleContains | Case-insensitive. Narrow to the functions you care about. Filtered events are not billed. | — |
Memory store name — memoryStoreName | Named key-value store holding the tracking history. Use different names to run independent watchlists. | "job-lifecycle-state" |
Reset memory — resetMemory | Discard history and treat this run as a new baseline. Only for starting over. | false |
Concurrency — concurrency | Boards fetched in parallel. Each board keeps its own tracking history regardless of ordering. | 5 |
Proxy — proxyConfiguration | Leave the default. | {"useApifyProxy":true} |
Output
{"board": "greenhouse:stripe","event": "reposted","jobId": "8412991","previousJobId": "8077887","title": "Backend Engineer II, Payments","location": "Dublin, Ireland","daysClosedBefore": 12,"republishCount": 2,"detectedAt": "2026-08-13T09:22:14.001Z"}
Ghost suspects are a different row. They are an assessment of a role as it stands rather than a transition, so they carry the score and what the score was able to see:
{"board": "greenhouse:stripe","event": "ghost-suspect","jobId": "4921361","title": "Backend Engineer/API, Payments and Risk","department": "8556 LPM Core - Eng","ageDays": 1243,"ghostScore": 65,"ghostScoreMax": 100,"ghostScoreBasis": "age-and-republish-history","ghostReasons": ["open 1243 days (board median 58)", "older than a year"],"boardMedianAgeDays": 58,"republishCount": 0,"detectedAt": "2026-08-15T23:34:02.855Z"}
Read ghostScore against ghostScoreMax, not against 100. Republish history is worth
up to 40 points and only exists once this actor has watched a board for a while, so early
runs top out at 65 and ghostScoreBasis says age-only. A minGhostScore of 70 returns
nothing at all until the history has accumulated.
The row above shows why the two are separate numbers. The ceiling is 100 because this
board has been watched long enough to have a history; this particular role scores 65
because it has not been closed and reposted in that time. A high ceiling with a low score
means "we looked and found no cycles", which is a different statement from "we could not
look" — and republishCount tells you which.
Every field
You are billed per row delivered — change events and ghost suspects alike — so here is everything a row can contain. Both row types carry the role's own fields from the board, so a row is readable on its own without joining back to a scrape.
On every row
| Field | What it is |
|---|---|
board | platform:slug, e.g. greenhouse:stripe. |
ats | The platform alone: greenhouse, ashby, lever or smartrecruiters. |
boardSlug | The company's slug alone. |
event | opened, closed, reposted, reopened, edited or ghost-suspect. |
detectedAt | When this run saw it. The event timestamp, not the board's. |
jobId | The platform's id for the role. |
title | Role title. |
Carried from the board, where the platform publishes it
| Field | What it is |
|---|---|
url | Public application URL. |
location | Location string as published. |
department / team | Department, and a finer team where the platform separates them. |
employmentType / workplaceType / isRemote | Contract shape and remote status, where published. |
isListed | false for delisted-but-not-deleted. Ashby only. |
salaryRange | min, max, currency, interval. Changes to it are what an edited event reports. |
requisitionId | The company's internal requisition number, where exposed. |
companyName | Company name as the board publishes it. |
firstPublishedAt | When the role was first posted. |
updatedAt | Last edit to the posting, where published. |
ageDays | Days open, from firstPublishedAt. |
On change events
| Field | Events | What it is |
|---|---|---|
fingerprint | all | Hash of title + location, which is how a repost under a new id is matched to the role that closed. |
previousJobId | reposted, reopened | The id this posting replaced. This is the whole point of the actor: the same role, renumbered. |
daysClosedBefore | reposted, reopened | How long the gap was. A short gap is the classic evergreen-repost pattern. |
changes | edited | One entry per changed field: field, from, to. Covers title, location and salary. |
firstSeenAt | closed | When this actor first saw the role — earlier than any board field when the role predates your first run. |
lastSeenAt | closed | The last run that still saw it open, so the closure is bracketed. |
daysOpen | closed | Total days the role stayed up. |
cycles | closed | How many times it has closed and come back since tracking began. |
On ghost suspects
| Field | What it is |
|---|---|
ghostScore | 0–ghostScoreMax. |
ghostScoreMax | The highest score reachable given what this board's history supports — 65 before history exists, 100 after. |
ghostScoreBasis | age-only or age-and-republish-history. |
ghostReasons | Plain-language reasons behind the score. |
boardMedianAgeDays | The board's median role age, which the score is relative to. |
republishCount | Close-and-return cycles seen for this role. 0 with a ghostScoreMax of 100 means we looked and found none. |
The memory, and why it is a named store
Tracking history lives in a named key-value store, not the default one. Apify's default store is scoped to a single run — history kept there would be silently discarded every time, and the monitor would report the entire board as newly opened on each run. That would make it a slower, more expensive version of the plain scraper. A test covers this.
Use different memoryStoreName values for independent watchlists. Set resetMemory to
start a fresh baseline.
Who this is for
- Job boards and hiring products — prove a role keeps being republished rather than filled, and say so to your users.
- Recruiting analysts — real time-to-fill data by function and company, which nobody publishes.
- Competitive watchers — know within a day when a rival opens a role, and catch salary bands changing quietly.
- Investors — closure rates as a hiring-health signal, accumulated over time.
Common uses
- Ghost-job detection — prove a role keeps being republished rather than filled.
- Time-to-fill benchmarking — real closure data by function and company.
- Competitor hiring alerts — know within a day when a rival opens a role.
- Compensation drift — catch salary bands changing quietly on Lever boards.
- Market research — closure rates as a hiring-health signal, accumulated over time.
Pricing
Pay per event reported and per ghost suspect. Watching costs almost nothing — reading a board is billed at $0.00002 per run — the platform's $0.00001 minimum, charged once per GB of memory, on 2 GB — and everything beyond that is charged only for the changes it surfaces. On a steady schedule most runs report a handful of events, or none, and cost well under a hundredth of a cent.
Other Actors in this family
Same engines, same billing, no account or API key on any of them.
YouTube & video
- Download YouTube Subtitles in Bulk — SRT, VTT & Text — Bulk subtitles from videos, channels or playlists — text, SRT, VTT or RAG chunks.
- Export YouTube Comments to CSV — Replies and Likes — Every comment and reply thread, with likes, authors and creator flags.
- List Every Video on a YouTube Channel — Export to CSV — A channel's whole back catalogue plus a subscriber and RSS summary row.
- Find YouTube Sponsors — Brand Deals, Codes & Links — Which brands pay which creators, with the campaign link, the code and the timestamp.
- YouTube Search API — Bulk Results, No Quota — Many search terms at once, every result as a row, filtered before you are billed.
- Track Deleted YouTube Videos & Title Changes — What a channel quietly changed: deleted videos, rewritten titles, view velocity.
- YouTube Creator Email Finder & Sponsor Lookup — A channel list into leads: the published email, audience bands, and who already sponsors them.
- Export a YouTube Playlist to CSV — Every Video — Any playlist as a table, with each video position in it.
Search demand
- AnswerThePublic Alternative — Autocomplete Keyword API — One seed into hundreds of real keywords from Google, YouTube and Amazon autocomplete.
- Google Trends API — Today's Trending Searches, No Key — Today's trending searches by country, with traffic bands and the news behind them.
E-commerce
- Export Any Shopify Store's Products to CSV or JSON — Any Shopify catalogue: variants, SKUs, live prices, stock, images, collections.
- New Shopify Product Alerts — Competitor Drop Tracker — Only what a store launched since the last run. Scanning is free.
Hiring
- Greenhouse, Lever & Ashby Job Scraper — No API Key — Paste a company domain, get its open roles from Greenhouse, Ashby, Lever or SmartRecruiters.
FAQ
Why did the first run report nothing? By design. It records a baseline instead of claiming every existing role just opened.
How often should I run it? Daily is the sweet spot. Hourly rarely surfaces more, because ATS boards do not change that fast.
What if a run is interrupted? State is written after all boards complete, so an interrupted run re-reports next time rather than losing history.
Can I watch many companies? Yes, in one run. Each board's history is tracked separately.
Is it legal to monitor careers pages? Greenhouse, Ashby, Lever and SmartRecruiters publish documented, public, no-authentication job board APIs intended for syndication. There is no login and nothing bypassed. What this adds is your own record of what changed between two public snapshots, which is data you created by watching. Each company's own terms are a separate contract question. Not legal advice.
Will I get blocked or rate-limited? These are official JSON endpoints built for syndication, so a daily schedule across many boards is well within normal use.
How much does 1,000 changes cost? $4.00 per 1,000 change events and $2.00 per 1,000 ghost suspects, plus $0.00002 for the run. A quiet day reports nothing and costs the run fee alone.
Can I export the results to Excel or Google Sheets? Yes. Every run's dataset downloads as CSV, Excel, JSON, XML or RSS from the Storage tab, or straight from the API if you want a live link a spreadsheet can pull.
Can I connect it to Zapier, Make or n8n? Yes — Apify publishes integrations for all three, plus webhooks that fire when a run finishes. A common setup is a schedule here and a webhook into your own database or Slack.
Do I need to write code? No. Fill the form in the console and press Start. If you do want code, the Apify client libraries for Python and JavaScript call this the same way, and it is available over MCP so an AI agent can call it directly.