Greenhouse, Lever & Ashby Jobs Scraper API avatar

Greenhouse, Lever & Ashby Jobs Scraper API

Pricing

$1.00 / 1,000 job postings

Go to Apify Store
Greenhouse, Lever & Ashby Jobs Scraper API

Greenhouse, Lever & Ashby Jobs Scraper API

Normalize public Greenhouse, Lever, and Ashby jobs into one dataset. Detect official career URLs and optionally emit only new postings across scheduled runs.

Pricing

$1.00 / 1,000 job postings

Rating

0.0

(0)

Developer

Kunteper Koyu

Kunteper Koyu

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

6 days ago

Last modified

Share

Fetch published job postings from official public Greenhouse, Lever, and Ashby endpoints and normalize them into one stable schema. Build job boards, hiring-signal datasets, market research, alerts, and recruiting automations without maintaining three provider-specific integrations.

Editing an AI-jobs newsletter? Start with the daily Anthropic jobs feed. Collect a baseline once, then receive previously unseen postings for editorial review on later runs. The setup below explains scheduling, duplicate handling, export, and cost limits.

What you get

  • company, title, primary and secondary locations, department, and team
  • employment type, workplace type, and remote status when available
  • plain-text and HTML descriptions
  • canonical job and application URLs
  • compensation when the provider exposes it
  • publication and update timestamps
  • deterministic SHA-256 fingerprints for change detection
  • careers-URL auto-detection for supported provider URL formats
  • persistent newOnly mode for scheduled monitors
  • isolated board errors, so one invalid board does not discard successful results

Common use cases

  • power a niche job board or searchable jobs API
  • monitor target companies for hiring and expansion signals
  • create role, keyword, location, and remote-job alerts
  • normalize jobs before analytics, enrichment, or RAG ingestion
  • track new and changed postings across multiple ATS providers

Quick start

  1. Find the board token in the company's public careers URL.
  2. Add the provider, board name, and optional company display name.
  3. Add keyword, location, remote, or publication-date filters if needed.
  4. Run the Actor and open the normalized dataset.

Try the ready-to-run Anthropic AI jobs example.

{
"boards": [
{
"provider": "greenhouse",
"boardName": "anthropic",
"companyName": "Anthropic"
},
{
"provider": "lever",
"boardName": "leverdemo",
"companyName": "Lever",
"region": "global"
},
{
"provider": "ashby",
"boardName": "Ashby",
"companyName": "Ashby"
}
],
"searchTerms": ["engineer"],
"locations": ["remote", "New York"],
"remoteOnly": false,
"includeDescription": true,
"includeCompensation": true,
"publishedAfter": "2026-07-01",
"maxJobsPerBoard": 25,
"concurrency": 5,
"timeoutSeconds": 30
}

Lever supports global and eu regions. Board names are the public token or site name in the provider's careers URL.

Alternatively, paste official hosted careers URLs and let the Actor identify the provider and board without crawling the page:

{
"careerUrls": [
"https://boards.greenhouse.io/example",
"https://jobs.eu.lever.co/example",
"https://jobs.ashbyhq.com/example"
],
"newOnly": true,
"stateStoreName": "my-daily-job-monitor"
}

Auto-detection is deliberately limited to boards.greenhouse.io, job-boards.greenhouse.io, jobs.lever.co, jobs.eu.lever.co, and jobs.ashbyhq.com. It parses the URL locally and calls the provider's public JSON API; it does not scrape arbitrary company careers domains or follow redirects. For a custom careers domain, use its official hosted ATS link or enter the provider and board token under boards.

New-jobs-only scheduled runs

Set newOnly to true to persist stable hashes of provider, board, and source job ID in the named stateStoreName. The first run emits all matching jobs; later runs using the same store emit and charge only for previously unseen job IDs. Edits to a known posting do not make it new. Use a separate store name for each independent monitor and avoid concurrent runs against the same store, because key-value-store updates are not transactional. State retains the most recent 100,000 job identities. The default newOnly: false preserves the original behavior.

Daily jobs feed for AI-newsletter editors

Use this workflow when you check the same AI company's careers board every day and need a queue of new postings to review. This example monitors Anthropic's public Greenhouse board, including non-technical roles; it does not discover every AI employer or decide which jobs belong in your newsletter.

  1. Open the daily newsletter example and copy it into your account. Give stateStoreName a unique name for your newsletter and keep that name on later runs.
  2. Run once to collect the baseline. Inspect the dataset and the BOARD_ERRORS record in the run's key-value store. A successful run can still contain a board error, so check both before treating an empty dataset as "no new jobs."
  3. Run again with the same input and store. Previously stored job IDs should be absent; a genuinely new posting can still appear. Export the dataset as CSV for your editorial sheet, or read it through your existing integration. The Actor does not append to Sheets or send a newsletter itself.
  4. Once the baseline is complete, schedule your copied task daily in Apify Console, for example at 08:00 in your selected timezone. Keep runs sequential. Set a maximum charge in the task's run options and review the first scheduled results before relying on the feed.
{
"boards": [
{
"provider": "greenhouse",
"boardName": "anthropic",
"companyName": "Anthropic"
}
],
"newOnly": true,
"stateStoreName": "my-ai-newsletter-anthropic-v1",
"maxJobsPerBoard": 5000,
"includeDescription": false,
"includeCompensation": false,
"concurrency": 1,
"timeoutSeconds": 30
}

Why 5,000 instead of the default 25? The per-board limit is applied before previously seen IDs are removed. A low limit repeatedly examines only the first matching slice and can miss jobs outside it. This example uses the supported maximum for one board. It still cannot promise complete coverage above 5,000 matching jobs. A spending cap can also leave the baseline incomplete; inspect the run and output before turning on a schedule. If you change boards or filters, use a new state store when you want a fresh baseline.

Editorial handoff: use provider, boardName, and sourceJobId together as your destination's unique key. Review title, companyName, location, and jobUrl before publishing. Deduplicate at the destination too: interruptions between dataset writes and state saves can replay rows. A zero-row incremental run does not mean old jobs are still open. This feed does not emit removals or edits; verify the source link before including a job in an issue.

Budget example: a 500-job baseline represents $0.50 in result-event charges; 100 newly discovered jobs over the following month represent $0.10 more. These are price examples, not forecasts of Anthropic's posting volume or your final bill. The saved example uses a $5 maximum event charge per run, matching the 5,000-job output ceiling. Lower that ceiling in your task's run options if needed, while checking that the baseline remains complete. Check Apify's current account pricing and limits before scheduling.

Example result

{
"provider": "greenhouse",
"boardName": "anthropic",
"companyName": "Anthropic",
"sourceJobId": "4461450008",
"title": "Account Executive, AI Native",
"location": "San Francisco, CA | New York City, NY",
"secondaryLocations": [],
"remote": false,
"jobUrl": "https://job-boards.greenhouse.io/anthropic/jobs/4461450008",
"publishedAt": "2024-12-20T13:53:38-05:00",
"updatedAt": "2026-06-08T20:49:32-04:00",
"fingerprint": "cb3e2724e0fde508046d496236f32f598457dc566625918c48655cc80e836697",
"retrievedAt": "2026-07-06T17:33:19.395Z"
}

Run by API

Set APIFY_TOKEN in your environment and keep it out of source control.

cURL

curl -X POST \
"https://api.apify.com/v2/acts/rtworule~public-ats-job-feed-normalizer/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"boards":[{"provider":"greenhouse","boardName":"anthropic","companyName":"Anthropic"}],"remoteOnly":true,"maxJobsPerBoard":100}'

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('rtworule/public-ats-job-feed-normalizer').call({
boards: [{ provider: 'greenhouse', boardName: 'anthropic', companyName: 'Anthropic' }],
remoteOnly: true,
maxJobsPerBoard: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("rtworule/public-ats-job-feed-normalizer").call(run_input={
"boards": [{
"provider": "greenhouse",
"boardName": "anthropic",
"companyName": "Anthropic",
}],
"remoteOnly": True,
"maxJobsPerBoard": 100,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)

Pricing

This Actor uses pay per event. A job-normalized event costs $0.001 per stored job: 100 delivered jobs cost $0.10 and 1,000 cost $1.00 in event charges. The minimum configurable maximum-charge limit is $0.01, which is not a fixed $0.01 charge for every run. Filters, per-board limits, and newOnly mode help control output. The default input keeps the first run to 25 jobs per board; raise maxJobsPerBoard when you want a larger snapshot. The Actor stops storing results when the run's maximum total charge is reached. In newOnly mode, remembered postings are not emitted or charged as result events.

Integrations and automation

  • schedule with newOnly: true to receive and pay for only newly discovered jobs
  • compare the output fingerprint separately when you want to detect edits to known jobs
  • send matching jobs to Slack, email, Make, Zapier, n8n, or a webhook
  • load normalized jobs into a database, search engine, BI tool, or vector store
  • export CSV/XLSX to Sheets for research and editorial review
  • use publishedAfter, search terms, and locations to keep recurring runs focused

FAQ and troubleshooting

Is this scraping private candidate or recruiting data? No. It reads only public job-posting endpoints and does not access candidates, applications, internal postings, or authenticated recruiter systems.

Where do I find the board name? It is the company-specific token in the public Greenhouse, Lever, or Ashby careers URL—not necessarily the company's display name.

Why is a job or field missing? Filters may exclude it, the provider may omit the field, or the posting may have been removed. The Actor does not invent missing source data.

How do I avoid duplicate alerts? Enable newOnly and reuse the same stateStoreName on every scheduled run. The Actor then suppresses previously seen job IDs before charging or writing output. Keep newOnly disabled if you want a full snapshot and compare the output fingerprint in your destination to detect changed postings.

Why did one board fail while the run succeeded? Boards are isolated. Inspect the BOARD_ERRORS key-value-store record for an invalid token, provider response, timeout, or other board-specific error.

Data sources, responsible use, and limitations

The Actor uses public posting endpoints:

  • Greenhouse Job Board API: https://boards-api.greenhouse.io/v1/boards/{board}/jobs
  • Lever Postings API: https://api.lever.co/v0/postings/{site}
  • Ashby Job Postings API: https://api.ashbyhq.com/posting-api/job-board/{board}

Provider schemas, availability, and job content can change. Compensation, remote status, and timestamps are returned only when the source exposes enough information. Users remain responsible for their downstream use, retention, applicable terms, and compliance.

For a reproducible issue, open an issue from the Actor page with the run ID, provider, public board name, and expected behavior. Never include credentials, candidate data, or other sensitive information.

More tools from this developer