Career Site & ATS Jobs Scraper - Greenhouse, Lever, Ashby avatar

Career Site & ATS Jobs Scraper - Greenhouse, Lever, Ashby

Pricing

from $9.00 / 1,000 job results

Go to Apify Store
Career Site & ATS Jobs Scraper - Greenhouse, Lever, Ashby

Career Site & ATS Jobs Scraper - Greenhouse, Lever, Ashby

Scrape public company career sites and ATS boards: Greenhouse, Lever, Ashby, SmartRecruiters, Personio, Recruitee, Workable. Returns every open role with location, department, employment type and salary, plus new, reposted and closure signals when you pass a previous dataset id. Unofficial.

Pricing

from $9.00 / 1,000 job results

Rating

0.0

(0)

Developer

daehwan kim

daehwan kim

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Career Site & ATS Jobs Scraper - Greenhouse, Lever, Ashby and more

Give this Actor a company career page, a public ATS board URL or just a domain. It reads the board the company already publishes and returns every open role, one row per job, with location, department, employment type, salary, a description excerpt and the skills, benefits and experience requirements we read out of the posting.

Point it at the same boards again next week with the previous dataset id and it also tells you what changed: which roles are new, which look like reposts, which disappeared, and how each company's open headcount moved.

Supported public boards: Greenhouse, Lever, Ashby, SmartRecruiters, Personio, Recruitee, Workable.

Unofficial. This Actor is not affiliated with, endorsed by or sponsored by Greenhouse, Lever, Ashby, SmartRecruiters, Personio, Recruitee, Workable or any employer named in your input. All product names are trademarks of their respective owners and are used only to describe which public boards are read.

What it is good for

  • Sales and recruiting signals - a company that opened twelve engineering roles this month is a different prospect than one that closed five.
  • Job boards and aggregators - keep a live copy of hundreds of company boards without writing seven different clients.
  • Market research - salary, seniority, department and location across a whole portfolio of companies.
  • Competitor hiring watch - run it weekly, pass the previous dataset id, and read only the diff.

Input - every field is an array

FieldWhat it does
boardUrlsPublic board URLs, or platform:token shorthand such as greenhouse:stripe. Up to 50 per run.
companyDomainsDomains such as acme.com. Each domain is tried against every supported board pattern, so one domain can return a whole board.
atsPlatformsRestrict to greenhouse, lever, ashby, smartrecruiters, personio, recruitee, workable. Empty means all.
titleIncludes / titleExcludesKeep or drop jobs by title keyword.
locationIncludesKeep jobs whose location contains one of these terms.
postedWithinDaysOne integer. 0 disables the date filter.
maxResultsOne integer, 1 to 5000. Upper bound on charged rows.
includeDescriptionOne boolean. Description excerpt and the derived skill, benefit, language and experience fields.
fetchDetailPagesOne boolean. Fetch the public job page for boards whose list feed carries no description (SmartRecruiters, Personio).
previousDatasetIdsOne dataset id from an earlier run of this Actor. This is what turns on change detection.
comparisonModesoff or compare. Use compare together with previousDatasetIds.
detectClosuresOne boolean. Emit closure_suspected rows. Those rows are free.
proxyModesNONE, DATACENTER or RESIDENTIAL. Public ATS endpoints answer a direct connection, so NONE is the default.

Accepted board URL shapes include https://job-boards.greenhouse.io/<token>, https://boards-api.greenhouse.io/v1/boards/<token>/jobs, https://jobs.lever.co/<token>, https://jobs.ashbyhq.com/<token>, https://jobs.smartrecruiters.com/<Company>, https://<company>.jobs.personio.de/, https://<company>.recruitee.com/ and https://apply.workable.com/<token>/.

Example

{
"boardUrls": ["https://job-boards.greenhouse.io/stripe", "https://jobs.lever.co/leverdemo"],
"companyDomains": ["vanta.com"],
"titleIncludes": ["engineer", "data"],
"postedWithinDays": [30],
"maxResults": [500],
"includeDescription": [true],
"previousDatasetIds": ["PASTE_YOUR_PREVIOUS_DATASET_ID"],
"comparisonModes": ["compare"]
}

Output

One row per job. A few of the fields:

FieldMeaning
jobKey, jobId, url, applyUrlStable key and the public links. jobKey is platform:token:jobId.
title, companyName, location, isRemote, workModelThe basics, normalised across all seven platforms.
department, team, jobFunction, employmentType, seniorityLevelClassification as the board publishes it.
salary, salaryMin, salaryMax, salaryCurrency, salaryInterval, hasSalaryCompensation when the board exposes it.
descriptionSnippet, descriptionChars, descriptionTruncated, descriptionUrlFirst 500 characters of the posting, its true length, and the public page that holds the rest.
skillsMentioned, benefitsMentioned, languagesMentioned, yearsOfExperience, requiresVisaSponsorshipMentionFacts we derive from the posting text so you can filter without the prose.
postedAt, updatedAt, validThrough, ageDays, observedAtDates, always ISO 8601.
atsPlatform, companyBoardToken, boardUrl, sourceDomain, evidenceUrlsExactly which public page each field came from.
isNew, isReposted, suspectedClosed, previousJobId, postedAtChanged, changeReasonsChange detection.
companyCurrentCount, companyPreviousCount, companyDeltaOpen roles per company, now and in your baseline.
comparisonStatus, coverageComplete, scopeFingerprintWhether the comparison is trustworthy and why.
fieldAvailabilityPer field: observed, not_measured or excluded_by_policy.

Aliases such as jobTitle, company, organization, jobUrl, link and postedDate are included so the rows drop straight into pipelines built for other job scrapers.

Why there is no full description field

The posting text is the employer's copyrighted work. We do not republish it. Each row carries a 500-character excerpt, the real character count, the structured facts we derive locally, and descriptionUrl, the employer's own public page where the full text lives. descriptionText, description and descriptionHtml exist in the schema but are always null with excluded_by_policy, so a pipeline expecting those keys will not break and will not silently receive republished prose.

Change detection is honest about what it knows

  • No previousDatasetIds - every change field is null and comparisonStatus is no_baseline. Nothing is guessed.
  • Baseline scope differs from this run - scope_mismatch, change fields stay null.
  • This run or the baseline did not cover the whole board - incomplete, change fields stay null and no closure rows are produced.
  • comparable - isNew, isReposted, companyDelta and closure rows are filled in.

suspectedClosed means the job was in your baseline and is absent from a board listing that was read in full in this run. It is a strong signal, not a statement from the employer, which is why the field is named suspected.

The run summary in the key-value store record OUTPUT reports per board how many jobs were discovered, which boards failed and why, and how many descriptions were fetched. It keeps two coverage flags apart: coverageComplete says the board listings were read in full, which is what change detection and closure rows depend on, while descriptionsComplete says every description we went looking for came back. A board that answered its listing but rate-limited one detail page leaves coverageComplete: true and descriptionsComplete: false.

Pricing

EventWhat triggers it
Actor startCharged once per run by the platform, based on memory.
Job resultOne validated, unique open job row delivered to the dataset.

You are not charged for closure rows, duplicate rows, boards that returned an error, boards that do not exist, or runs that produce no jobs beyond the start event. Tiered pricing applies, so paid Apify plans pay less per row than the free tier. Current prices are on the Actor's pricing tab and always take precedence over this page.

If you set a maximum total charge for the run, the Actor plans its output to fit inside it, stops cleanly, keeps what it already delivered and marks coverageComplete: false.

How it collects

Only public, unauthenticated endpoints that each ATS publishes for its own job boards, with an honest bot user agent, at most a few requests per second, one request at a time per board and exponential backoff on transient errors. There is no login, no cookie, no captcha solving, no account pool and no IP rotation to get around a block. A board that refuses us is reported as refused.

Personal data is out of scope by design: contact emails, phone numbers and recruiter identities are never collected, and those fields are always null with excluded_by_policy in fieldAvailability.

Your responsibility as the operator

You choose the companies and boards. You are responsible for having the right to collect and use that data, for complying with the terms of the sites you point this Actor at, and for any onward use of the output, including GDPR and equivalent obligations where you are the data controller. We provide the tool and report what each public page returned.

Leave a review

A short review on the Reviews tab, good or bad, helps other people find this Actor and tells us what to build next. Found a bug or need a feature? Open an issue on the Issues tab and we'll look into it.