Greenhouse Jobs Scraper (Fast API & Salaries) avatar

Greenhouse Jobs Scraper (Fast API & Salaries)

Pricing

from $0.70 / 1,000 results

Go to Apify Store
Greenhouse Jobs Scraper (Fast API & Salaries)

Greenhouse Jobs Scraper (Fast API & Salaries)

Fast 128MB HTTP scraper for Greenhouse job boards (US & EU). Extracts job listings, structured salaries (pay_transparency), locations, departments, screening questions, and tracks new jobs across scheduled runs. 100% drop-in compatible.

Pricing

from $0.70 / 1,000 results

Rating

0.0

(0)

Developer

Data Goose

Data Goose

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

20 hours ago

Last modified

Security

Limited permissions

Share

Pull every open job from any Greenhouse job board (US and EU) in seconds: structured salaries, locations, departments, workplace type, screening questions, and only the new jobs since your last scheduled run.

Runs as plain HTTP against the official Greenhouse Job Board API, so it needs 128 MB of memory and no browser.


Which companies can I scrape?

Any company that posts its jobs on Greenhouse, not just the ones in our built-in list. Add as many as you like to urls, in any of these forms:

You pasteExample
The company's Greenhouse board URLhttps://boards.greenhouse.io/stripe
Just the company's slugstripe
A single job URLhttps://boards.greenhouse.io/stripe/jobs/6012345

Finding the slug: open any job on the company's careers page and look at the address bar. The slug comes right after the domain: job-boards.greenhouse.io/stripe/jobs/123. Company career sites that embed Greenhouse (links containing ?gh_jid=) work too.

What's the built-in directory? An optional shortcut. Turn on includeBuiltInTechDirectory to also scan 45+ well-known tech companies without typing anything. It's off by default and never limits what you can scrape.

Optional Starter Directory (Any Greenhouse Board URL or Slug Works in urls)

You can scrape any company that uses Greenhouse by pasting its board URL or company slug into urls. The 48 companies below are only the optional built-in starter list (scanned when you turn on "includeBuiltInTechDirectory": true)—they never restrict which companies you can scrape:

stripe (Stripe — stripe.com), anthropic (Anthropic — anthropic.com), cloudflare (Cloudflare — cloudflare.com), databricks (Databricks — databricks.com), figma (Figma — figma.com), intercom (Intercom — intercom.com), mongodb (Mongodb — mongodb.com), datadog (Datadog — datadoghq.com), airtable (Airtable — airtable.com), gusto (Gusto — gusto.com), okta (Okta — okta.com), carta (Carta — carta.com), toast (Toast — toasttab.com), airbnb (Airbnb — airbnb.com), coinbase (Coinbase — coinbase.com), gitlab (Gitlab — gitlab.com), vercel (Vercel — vercel.com), scaleai (Scaleai — scale.com), brex (Brex — brex.com), robinhood (Robinhood — robinhood.com), duolingo (Duolingo — duolingo.com), discord (Discord — discord.com), reddit (Reddit — reddit.com), pinterest (Pinterest — pinterest.com), lyft (Lyft — lyft.com), instacart (Instacart — instacart.com), asana (Asana — asana.com), twilio (Twilio — twilio.com), elastic (Elastic — elastic.co), cockroachlabs (Cockroachlabs — cockroachlabs.com), chime (Chime — chime.com), coursera (Coursera — coursera.org), dropbox (Dropbox — dropbox.com), affirm (Affirm — affirm.com), flexport (Flexport — flexport.com), gongio (Gongio — gong.io), klaviyo (Klaviyo — klaviyo.com), lattice (Lattice — lattice.com), launchdarkly (Launchdarkly — launchdarkly.com), netlify (Netlify — netlify.com), newrelic (Newrelic — newrelic.com), pagerduty (Pagerduty — pagerduty.com), rubrik (Rubrik — rubrik.com), samsara (Samsara — samsara.com), squarespace (Squarespace — squarespace.com), udemy (Udemy — udemy.com), zscaler (Zscaler — zscaler.com), algolia (Algolia — algolia.com)

Scraping companies across multiple ATS platforms? Combine this Actor with our other live 31-field job scrapers (All-in-One ATS Job Scraper, Workday Jobs Scraper, Lever Jobs Scraper, Ashby Job Scraper, SmartRecruiters Jobs Scraper, Rippling Jobs Scraper, Workable Jobs Scraper, Recruitee Jobs Scraper, Breezy HR Jobs Scraper)—all sharing the exact same 31-field output schema (companyDomain, salaryMin, salaryMax, recruiterEmails, isNew) so they plug into a single n8n, Make, Clay, or Python pipeline with zero field-mapping changes.


Quick Start — 3 Common Workflows

Click Save & Start in Apify Console to run the prefilled sample immediately, or copy one of these ready-to-run JSON inputs:

{
"urls": ["stripe", "anthropic", "airbnb"],
"keywordFilter": "engineer, ai, -intern",
"remoteOnly": true,
"maxJobsPerCompany": 25
}

2. Scheduled Daily Change Monitor (Emit Only Net-New Jobs)

Run on an hourly or daily schedule—the first run establishes your baseline, and every subsequent run outputs only newly posted jobs (while logging closed/expired job IDs to RUN_SUMMARY):

{
"urls": ["stripe", "anthropic", "airbnb"],
"onlyNewJobs": true,
"monitorName": "daily-watchlist",
"maxJobsPerCompany": 50
}

3. Zero-Input Built-In Directory Scan (B2B Hiring Signals & Clay / CRM Enrichment)

Scan our built-in directory of verified companies without hunting down board URLs—every output record includes companyDomain, salaryFormatted, and recruiterEmails:

{
"urls": [],
"includeBuiltInTechDirectory": true,
"deduplicateMultiLocationJobs": true,
"maxJobsPerCompany": 15,
"maxTotalJobs": 300
}

Why developers switch to this Actor

This ActorTypical HTML / browser scrapers
ArchitecturePure HTTP + JSON, 128 MB RAM, large payloads streamed to diskHeadless Chrome, 1–4 GB RAM
Redirected boards (e.g. Stripe → stripe.com/jobs)✅ Works. It reads the API, not the redirected HTML❌ Breaks or returns 0 jobs
US + EU data centers✅ boards-api.greenhouse.io + boards-api.eu.greenhouse.io with automatic fallback❌ Usually US only
Structured salaries✅ pay_transparency=true → salaryMin, salaryMax, salaryCurrency, all ranges, plus a regex fallback that reads the description❌ Free-text only, if anything
Change monitoring✅ onlyNewJobs keeps state between scheduled runs and returns only net-new jobs❌ You dedupe it yourself
InputsBoard URLs, custom career URLs, single job URLs (?gh_jid=), bare slugsBoard URLs only

What else it does:

  • Custom career domains get resolved. For https://www.cloudflare.com/careers it tries the domain name as a board token in both regions. If that fails, it scans the page HTML for an embedded Greenhouse board.
  • Single job URLs work. .../jobs/1234567, ?gh_jid=1234567 and embed/job_app?for=x&token=1234567 each return that one job, with its screening questions.
  • Built-in tech directory. Turn on includeBuiltInTechDirectory to scan 45+ well-known tech boards (Stripe, Anthropic, Airbnb, Coinbase, GitLab, Vercel, Figma, Scale AI, Reddit, Duolingo…).
  • Filters. Keyword or regex, department, location, remote only, and published/updated after a date.
  • Retries. Exponential backoff on HTTP 429/5xx. A board that fails is logged and skipped, and the rest of the run carries on.

Drop-in migration from older Greenhouse scrapers

Switching from bytepulselabs/greenhouse-job-scraper or a similar Actor needs no changes to your input or downstream code:

  • Input: the same urls field is accepted, as plain strings or legacy request-list objects ([{"url": "https://..."}]). The aliases boards, boardUrls and companies are merged in too. A proxy key is accepted and ignored, because the public API doesn't need proxies.
  • Output: every record keeps the same 9 base fields: id, type, title, description, locations, department, postingUrl, applyUrl, publishedAt. The 19 enriched fields are added alongside them, so existing mappings in n8n, Make, Zapier or your database keep working.
{
"urls": [
{ "url": "https://job-boards.greenhouse.io/stripe" },
"https://stripe.com/jobs",
"anthropic",
"https://job-boards.eu.greenhouse.io/someeucompany",
"https://job-boards.greenhouse.io/anthropic/jobs/5555555"
],
"proxy": { "useApifyProxy": true }
}

Input

FieldTypeDefaultDescription
urlsarray5 sample boardsBoard URLs, custom career URLs, single job URLs, or slugs
includeBuiltInTechDirectorybooleanfalseAlso scan the built-in list of 45+ tech companies
keywordFilterstring–Case-insensitive keyword or regex, matched against title and description
departmentFilterstring–Substring match on department names
locationFilterstring–Substring match on locations and offices (Remote, EMEA, New York…)
remoteOnlybooleanfalseOnly jobs classified as Remote
publishedAfterstring–YYYY-MM-DD. Keeps jobs published or updated on or after this date
onlyNewJobsbooleanfalseChange monitor: only output jobs not seen in earlier runs
monitorNamestringdefaultSeparate state key for each watchlist or scheduled task
includeApplicationQuestionsbooleanfalseFetch each matched job's application form fields
maxJobsPerCompanyinteger0Cap per board. 0 = automatic fair share: maxTotalJobs is split evenly across boards (at least 10 each), so large boards can't crowd out smaller ones. The newest jobs are kept first
maxTotalJobsinteger1000Cap across the whole run

Filters apply to full boards. A single job URL is always returned, because you asked for that job explicitly.

Change monitor (onlyNewJobs)

Seen job keys ({token}:{jobId}) are kept in the named Key-Value Store greenhouse-job-monitor-state under the key seen_{monitorName}. The state is saved after each successful board, so a network failure partway through a run never corrupts it. Each full-board scan snapshots all currently open job IDs on that board (and prunes closed jobs automatically), so subsequent scheduled runs emit only genuine net-new postings—even when your first baseline run used maxJobsPerCompany or maxTotalJobs.

The first run outputs every matching job. Later scheduled runs output only net-new postings.


Output

Each dataset item looks like this:

{
"id": "6123456",
"type": "Full-time",
"title": "Backend Engineer, Payments",
"description": "Who we are\nAbout Stripe\nStripe is a financial infrastructure platform for businesses...",
"locations": ["San Francisco, CA", "Seattle, WA"],
"department": "Engineering",
"postingUrl": "https://stripe.com/jobs/search?gh_jid=6123456",
"applyUrl": "https://boards.greenhouse.io/embed/job_app?for=stripe&token=6123456",
"publishedAt": "2026-10-21T14:02:11-04:00",
"ats": "greenhouse",
"companyToken": "stripe",
"companyName": "Stripe",
"companyDomain": "stripe.com",
"internalJobId": 5987654,
"requisitionId": "R-12345",
"updatedAt": "2026-11-02T09:15:40-05:00",
"isRemote": false,
"workplaceType": "On-site",
"departments": ["Engineering"],
"offices": ["San Francisco", "Seattle"],
"salaryMin": 185000.0,
"salaryMax": 245000.0,
"salaryCurrency": "USD",
"salaryInterval": "year",
"salaryFormatted": "USD 185,000 - 245,000 / year",
"salaryRanges": [
{
"min": 185000.0,
"max": 245000.0,
"currency": "USD",
"interval": "year",
"title": "San Francisco / Seattle",
"blurb": "The annual US base salary range for this role is $185,000 - $245,000.",
"formatted": "USD 185,000 - 245,000 / year",
"source": "pay_transparency"
}
],
"recruiterEmails": [],
"metadata": { "Employment Type": "Full-time" },
"isNew": true,
"descriptionHtml": "<h2>Who we are</h2><p>About Stripe...</p>",
"questions": null
}

Field notes:

  • salaryRanges[].source tells you where each salary came from:
    • pay_transparency: structured Greenhouse ranges.
    • description: a range the regex fallback found in the job text ($150,000 - $210,000, USD 140,000 - 180,000, $160k - $190k, $45 - $65/hr…).
    • description_single: an explicit single figure such as "pay rate of $60 per hour" → USD 60 / hour. In this case salaryMin and salaryMax are equal.
  • salaryInterval is hour or year (or month when the text says so).
  • workplaceType is Remote, Hybrid or On-site, based on the location, offices, workplace metadata and title.
  • questions is a list of {label, required, description, fields: [{name, type, options}]}. It's filled when includeApplicationQuestions is on or the input is a single job URL, and is null otherwise.
  • isNew is true for every job that wasn't in the change monitor state. With monitoring off there is no earlier state, so every job counts as new.
  • applyUrl opens the Greenhouse application form directly, even when the board redirects to a custom career site.

Run summary (RUN_SUMMARY)

At the end of every run, a RUN_SUMMARY record is saved to the run's default Key-Value Store. You can use it for dashboards or alerting without downloading the whole dataset:

{
"finishedAt": "2026-11-05T07:34:58.090748+00:00",
"boardsRequested": 2,
"boardsResolved": 2,
"boardsSucceeded": ["figma", "anthropic"],
"boardsSkippedOr404": [],
"totalJobsFetchedRaw": 826,
"totalJobsPushed": 10,
"salariesExtractedCount": 7,
"remoteJobsCount": 0,
"newJobsCount": 10
}

The Console status bar also updates live (Scanning 5 Greenhouse boards...) and ends with a summary such as Done: 120 jobs (84 with salaries, 22 remote) across 5 boards.


Pricing (Pay-Per-Event — No Monthly Subscription)

This Actor uses transparent Pay-Per-Event pricing. You only pay for jobs actually written to your dataset—filtered-out records and already-seen records (onlyNewJobs: true) cost $0.

Plan TierPer Job (apify-default-dataset-item)Cost per 1,000 JobsActor Start Fee (apify-actor-start)Proxy Cost
Free$0.00120$1.20$0.005$0 (no proxy needed)
Bronze$0.00100$1.00$0.005$0
Silver$0.00085$0.85$0.005$0
Gold / Platinum / Diamond$0.00070$0.70$0.005$0
  • 128 MB Memory Footprint: Runs in pure async HTTP (128 MB RAM instead of 1–4 GB headless browsers), reducing Apify compute usage by 8x–32x.
  • Built-in Spend Cap Protection: Use maxTotalJobs / maxJobsPerCompany or Apify's Maximum cost per run setting to cap spend to the exact cent.

API usage

The examples below call the Actor as data-goose~greenhouse-job-scraper and read your API token from the APIFY_TOKEN environment variable. You can find the token under Apify Console → Settings → API & Integrations.

Python (apify-client)

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("data-goose/greenhouse-job-scraper").call(run_input={
"urls": ["stripe", "https://job-boards.greenhouse.io/anthropic"],
"keywordFilter": "engineer|developer",
"remoteOnly": True,
"onlyNewJobs": True,
"monitorName": "remote-eng",
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["companyName"], "|", job["title"], "|", job["salaryFormatted"], "|", job["applyUrl"])

n8n / Make (HTTP request)

Add an HTTP Request node (n8n) or HTTP → Make a request module (Make):

  • Method: POST
  • URL: https://api.apify.com/v2/acts/data-goose~greenhouse-job-scraper/run-sync-get-dataset-items
  • Headers: Authorization: Bearer {{APIFY_TOKEN}}, Content-Type: application/json
  • Body:
{
"urls": ["stripe", "anthropic", "https://www.cloudflare.com/careers"],
"departmentFilter": "Engineering",
"publishedAfter": "2026-10-01",
"onlyNewJobs": true,
"monitorName": "n8n-daily"
}

The response is a JSON array of job records. Put a Schedule trigger in front of it (hourly or daily) with onlyNewJobs: true, and each run returns only fresh postings, ready to send to Slack, Airtable, Google Sheets or your CRM.

cURL

curl -X POST "https://api.apify.com/v2/acts/data-goose~greenhouse-job-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls": ["stripe", "anthropic"], "maxJobsPerCompany": 50}'

Explore the Data Goose Scraper Suite (128 MB Pure-HTTP)

All published Actors below run in 128 MB RAM with zero browser overhead and deterministic schemas (all ATS & Job scrapers share the exact same 31-field output schema):

ActorTarget Platform & Primary Use Case
All-in-One ATS Job Scraper (9 Platforms) (data-goose/career-site-job-scraper)All-in-One Router: auto-detects & scrapes all 9 ATS platforms from any company domain or URL
Workday Jobs Scraper: Unlimited API & Salaries (data-goose/workday-job-scraper)Workday: Fortune 500 & global enterprises (>2,000 facet bypass + 100+ built-in boards)
Greenhouse Jobs Scraper (Fast API & Salaries) (data-goose/greenhouse-job-scraper)Greenhouse: High-growth tech & unicorns (US + EU API, pay_transparency salaries)
Lever Jobs Scraper (US & EU Postings API) (data-goose/lever-job-scraper)Lever: Tech & scaleups (US + EU fallback, native salaryRange + combined lists)
Ashby Job Scraper (YC Startups & Salaries) (data-goose/ashby-job-scraper)Ashby: AI startups & YC companies (includeCompensation=true structured salary tiers)
SmartRecruiters Jobs Scraper (Enterprise API & Salaries) (data-goose/smartrecruiters-job-scraper)SmartRecruiters: Global enterprises (ServiceNow, Bosch, Experian, Eurofins)
Rippling Jobs Scraper (ATS Boards & Salaries) (data-goose/rippling-job-scraper)Rippling ATS: Modern startups & scaleups (/api/v1/board/{slug}/jobs + pay ranges)
Workable Jobs Scraper: Direct API & Salaries (data-goose/workable-job-scraper)Workable: Mid-market & European tech (v3 list + v2 detail orchestration)
Recruitee Jobs Scraper (Bulk API, Salaries & Emails) (data-goose/recruitee-job-scraper)Recruitee: European & remote-first companies (single-call /api/offers JSON)
Breezy HR Jobs Scraper (Salaries & Hiring Emails) (data-goose/breezyhr-job-scraper)Breezy HR: SMB & agencies (live /json feeds + full descriptions, no 100-item cap)

Looking for our E-Commerce, Lead Enrichment, Financial & Trend Scrapers? Browse all published 128 MB pure-HTTP scrapers on the Data Goose Apify Store Profile.


Support & Custom Contracting

  • 🐛 Bugs and feature requests: open an issue on the Actor's Issues tab, or email us.
  • 🧩 Custom integrations: private ATS scrapers (Workday, SmartRecruiters, iCIMS, Lever, Ashby…), custom output schemas, webhook and CRM pipelines, and enterprise schedules.
  • 📧 datagoosedev@gmail.com. We usually reply within one business day.