Job Lifecycle Monitor - Ghost Jobs & Reposts avatar

Job Lifecycle Monitor - Ghost Jobs & Reposts

Pricing

from $4.00 / 1,000 change event reporteds

Go to Apify Store
Job Lifecycle Monitor - Ghost Jobs & Reposts

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

DONGMIN KIM

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 hours ago

Last modified

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

EventWhat it means
openedA role that was not there last run
closedA role that disappeared, with daysOpen
repostedThe 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.
reopenedThe same ID came back after closing
editedTitle, 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.

OptionWhat it doesDefault
Companies to watchboardUrls (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 reporteventTypesopened 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 suspectsemitGhostsScore every open role against its own board's median age and report the outliers.true
Minimum ghost scoreminGhostScore0-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 containstitleContainsCase-insensitive. Narrow to the functions you care about. Filtered events are not billed.
Memory store namememoryStoreNameNamed key-value store holding the tracking history. Use different names to run independent watchlists."job-lifecycle-state"
Reset memoryresetMemoryDiscard history and treat this run as a new baseline. Only for starting over.false
ConcurrencyconcurrencyBoards fetched in parallel. Each board keeps its own tracking history regardless of ordering.5
ProxyproxyConfigurationLeave 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

FieldWhat it is
boardplatform:slug, e.g. greenhouse:stripe.
atsThe platform alone: greenhouse, ashby, lever or smartrecruiters.
boardSlugThe company's slug alone.
eventopened, closed, reposted, reopened, edited or ghost-suspect.
detectedAtWhen this run saw it. The event timestamp, not the board's.
jobIdThe platform's id for the role.
titleRole title.

Carried from the board, where the platform publishes it

FieldWhat it is
urlPublic application URL.
locationLocation string as published.
department / teamDepartment, and a finer team where the platform separates them.
employmentType / workplaceType / isRemoteContract shape and remote status, where published.
isListedfalse for delisted-but-not-deleted. Ashby only.
salaryRangemin, max, currency, interval. Changes to it are what an edited event reports.
requisitionIdThe company's internal requisition number, where exposed.
companyNameCompany name as the board publishes it.
firstPublishedAtWhen the role was first posted.
updatedAtLast edit to the posting, where published.
ageDaysDays open, from firstPublishedAt.

On change events

FieldEventsWhat it is
fingerprintallHash of title + location, which is how a repost under a new id is matched to the role that closed.
previousJobIdreposted, reopenedThe id this posting replaced. This is the whole point of the actor: the same role, renumbered.
daysClosedBeforereposted, reopenedHow long the gap was. A short gap is the classic evergreen-repost pattern.
changeseditedOne entry per changed field: field, from, to. Covers title, location and salary.
firstSeenAtclosedWhen this actor first saw the role — earlier than any board field when the role predates your first run.
lastSeenAtclosedThe last run that still saw it open, so the closure is bracketed.
daysOpenclosedTotal days the role stayed up.
cyclesclosedHow many times it has closed and come back since tracking began.

On ghost suspects

FieldWhat it is
ghostScore0–ghostScoreMax.
ghostScoreMaxThe highest score reachable given what this board's history supports — 65 before history exists, 100 after.
ghostScoreBasisage-only or age-and-republish-history.
ghostReasonsPlain-language reasons behind the score.
boardMedianAgeDaysThe board's median role age, which the score is relative to.
republishCountClose-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

Search demand

E-commerce

Hiring

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.