Ghost Job Detector — Stale, Reposted & Evergreen Job Check avatar

Ghost Job Detector — Stale, Reposted & Evergreen Job Check

Pricing

from $0.80 / 1,000 job scoreds

Go to Apify Store
Ghost Job Detector — Stale, Reposted & Evergreen Job Check

Ghost Job Detector — Stale, Reposted & Evergreen Job Check

Check job data you already have for ghost jobs: open too long, reposted, re-dated, evergreen wording, closed but still listed, no pay. Every job gets a 0-100 score and the reason for each point, quoted from the posting. Works on any job scraper's rows. Nothing is scraped.

Pricing

from $0.80 / 1,000 job scoreds

Rating

0.0

(0)

Developer

Northbell

Northbell

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 hours ago

Last modified

Share

Ghost Job Detector

Some job postings are not a seat someone is hiring for right now: they have been open for months, they come back every few weeks with a fresh date, or the text itself says it is collecting a "talent pipeline". Give this Actor the jobs you already have — from any job scraper, an ATS export, your own board — and every job gets a ghost score from 0 to 100 and the reason for each point, quoted from the posting or counted from your data. Turn on Remember jobs between runs and a job that comes back with a newer posting date is also flagged as re-dated. Nothing is scraped: the Actor only reads what you send.

$1 per 1,000 jobs returned, plus $0.01 per run.

Example

Input: three rows (two of them the same role listed twice on LinkedIn).

Output (a real run of the Actor's example input on 11 October 2026):

titleghostScoresignals
Customer Success Manager (Acme Corp)100 · highevergreen: the posting says "We are always accepting applications and building a talent pipeline for future opportunities on our customer team." · age: open for 101 days (posted 2026-07-01) · reposted: listed 2 times on linkedin.com under the same title and place (posted 2026-07-01, 2026-09-30) · noPay · thin: the description is only 114 characters
Customer Success Manager (Acme)25 · lowreposted (same as above). Pay and description not checked: the row has neither
Payments Engineer (Example Pay)0 · low—

Run it again and again

  • On a schedule — save your input as a task and add a Schedule: after your job scraper's scheduled run. Send each run to Google Sheets, Slack or email with an integration on the task.
  • Watch for changes — Turn on Remember jobs between runs: a job that comes back with a newer posting date is flagged redated, and its age counts from the first time it was seen.
  • In bulk — Pick every dataset in Datasets to check in one run.

The signals

SignalPointsWhat it means
closed50The source marks the job closed (closed: true, acceptingApplications: false) or the text says "no longer accepting applications" — but it is still in your list
evergreen35The text says it is not one current seat: "always accepting applications", "talent pool/community/pipeline", "future opportunities", "general application", "not a current opening". The sentence is quoted
redated30With memory on: the job was first seen with one posting date and now shows a date at least 7 days newer — the date was refreshed, the job was not
reposted25The same company, title and place is listed more than once on the same source with different links. The same job on LinkedIn and on the career page is not a repost
age15 / 30 / 40Open for 30 / 60 / 90 days or more — from the posting date, or from the first time it was seen (memory), whichever is older
applicants10500 or more applicants and still open after 30 days (from rows that carry an applicant count)
noPay10No pay range in the pay fields or in the text
thin10The description is under 300 characters

60 or more is high, 30 to 59 medium, under 30 low. The score is the order in which to check jobs before you apply, count or contact them — not proof that a job is fake. A role can be open for 100 days because it is hard to fill.

What cannot be read is not scored. A row without a description gets no noPay or thin points; it lists "pay" and "description" in notChecked instead. "Applications are reviewed on an ongoing basis until the position is filled" is a real seat and is not counted as evergreen.

Measured on real data

On 11 October 2026, with rows from two of our own scrapers:

  • 60 LinkedIn "customer success manager" jobs in the United States (with descriptions and applicant counts): 7 medium, 0 high. 5 had been open 90 days or more, 24 stated no pay. None used evergreen wording — the "pipeline" in their texts was the sales pipeline, which the Actor does not count.
  • 1,238 Stripe postings from LinkedIn and Stripe's Greenhouse board: 3 high, 276 medium. 178 open 90 days or more; 32 listed more than once on the same source — for example one sales role listed on 2025-10-06 and again on 2026-09-22.

A scheduled check: re-dated jobs

Turn on Remember jobs between runs and run it after your scraper on a schedule. The Actor keeps, for each job, the first day it saw it and the first posting date (in your key-value store ghost-job-history, for 180 days). From the second run, a job that shows a newer posting date gets redated, and its age counts from the first day it was seen — a refreshed date no longer makes an old job look new.

What you get

Your row as it was, plus:

Field
ghostScore, ghostLevel0-100, and high / medium / low
signals[{ signal, points, evidence }], highest first
notCheckedsignals that could not be read from the row (age, pay, description)
daysOpen, repostCountthe numbers behind age and reposted

Return jobs scoring at least (minScore) keeps only the jobs worth a look: 30 for medium and high, 60 for high only.

Input

  • jobs: rows from any scraper, as they are. Read from title/jobTitle/positionName, company/companyName, location, url/jobUrl, postedAt/datePosted/postedOn (also 30+ days ago), description, and when present applicants, closed, daysOpen and pay fields (salaryMin, salaryText, annualSalaryMin…).
  • datasetIds: datasets from your other runs, read in full.
  • Up to 50,000 rows per run.

The text rules are written for English postings.

Pricing

$1 per 1,000 jobs returned, plus $0.01 per run. Jobs below your minimum score are not returned and not charged.

For AI agents

Call with {"jobs": [...rows from any job scraper...], "minScore": 30} — seconds for a few thousand rows. Each row has type: "job", ghostScore and signals with the evidence as text.

Rows with applicant counts and days open, the richest input for this check: LinkedIn Jobs Scraper with Applicant Counts.