Greenhouse Jobs Scraper — Salary Ranges by Company avatar

Greenhouse Jobs Scraper — Salary Ranges by Company

Pricing

from $30.00 / 1,000 results

Go to Apify Store
Greenhouse Jobs Scraper — Salary Ranges by Company

Greenhouse Jobs Scraper — Salary Ranges by Company

Every open role from any company's Greenhouse job board, with the disclosed salary range parsed into payMin / payMax / currency / period. Pass company names, board tokens or board URLs. Departments, offices, remote flag, posting age. Re-run on a schedule. Company-level data only.

Pricing

from $30.00 / 1,000 results

Rating

0.0

(0)

Developer

mochi

mochi

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

Greenhouse Jobs Scraper — open roles + disclosed salary ranges

Pull every open role from any company's Greenhouse job board, with the disclosed salary range parsed into numberspayMin, payMax, payCurrency, payPeriod — instead of buried in a paragraph of HTML.

Give it company names, Greenhouse board tokens, or board URLs. Re-run it on a schedule to watch a market's hiring and pay move.

Input: ["Scale AI", "gitlab", "https://job-boards.greenhouse.io/figma"]
Output: one row per open posting, with the pay band already parsed

What you get per posting

FieldExampleNotes
company · boardTokenScale AI · scaleaiBoard name as Greenhouse reports it
requestedAs · matchConfidenceScale AI · exactHow your input mapped to the board — see Company matching
title · jobUrl · jobId · requisitionIdDevOps Engineer, Infrastructure & SecurityrequisitionId is the employer's own req number where they publish it
location · offices[] · isRemoteSan Francisco, CA • New York, NY · ["US"] · falseisRemote is derived from the location text
departments[] · department["Sales"] · Salesdepartment is the first of the list
payMin · payMax198400 · 311000Numbers, not strings
payCurrency · payCurrencySymbolUSD · $ISO-4217
payPeriod · payPeriodInferredyear | hour | month · falseSee How the period is decided
payIsOtetrueThe posting quoted On-Target Earnings, not base
paySourcestructured | proseWhere the range was found
payRangeRaw$198,400 — $311,000 USDThe exact source text, so every number is auditable
payRangeCount3More than one band quoted — see Multi-band postings
firstPublished · updatedAtISO timestamps
daysSinceFirstPublished · daysSinceUpdated61 · 6The hiring-signal fields: how long a req has been open
descriptionTextfull posting textOnly when includeDescription is on

Measured pay-range coverage — read this before you buy

Most postings on most boards do not disclose pay. Measured across 3,064 live postings on 10 boards:

BoardPostings with a parsed range
Duolingo67 / 67 — 100%
Anthropic351 / 400 — 88%
Robinhood113 / 128 — 88%
Discord43 / 45 — 96%
Figma109 / 176 — 62%
Databricks426 / 803 — 53%
Datadog204 / 429 — 48%
GitLab72 / 184 — 39%
Cloudflare104 / 284 — 37%
Stripe19 / 548 — 3%
Total1,508 / 3,064 — 49%

That spread is the employer's choice, not a parser limitation — US pay-transparency law only binds certain roles and locations, so a company can post hundreds of roles and disclose on a handful. Set onlyWithPayRange to keep just the rows that carry a number.

Currencies seen in that sample: USD 1,421 · EUR 34 · GBP 27 · CAD 21 · CNY 3 · JPY 2.


Who this is for

  • Compensation benchmarking — pull a peer set every month and see where your bands sit. payMin/payMax/payPeriod are already normalised, so it drops straight into a sheet.
  • Recruiting and talent intel — what a competitor is paying, in which offices, for which levels.
  • Sales / GTM signaldaysSinceFirstPublished and department mix tell you who is expanding which function. A req that has been open 200 days is a different signal from one opened last week.
  • Market research — remote mix, office footprint, department growth over time.

The data changes constantly: postings open, close and get re-published. This is built to be re-run on a schedule — set postedWithinDays to pick up only what is new since your last run.


Input

InputDefaultWhat it does
companies6 sample boardsCompany names, board tokens, or board URLs
maxResults20Total cap, shared round-robin across the companies you list so the last company is never starved
onlyWithPayRangefalseKeep only postings that disclose pay
titleKeywords[]Case-insensitive substring match on the title
locationKeywords[]e.g. Remote, London
departments[]e.g. Engineering, Sales
postedWithinDays0Only roles first published in the last N days. 0 = no filter
includeDescriptionfalseAdds descriptionText. Off by default — it multiplies dataset size ~20x
allowUnverifiedMatchesfalseSee below

Company matching, and why it can refuse

You can pass a plain company name. It is normalised to a candidate board token and looked up — but the board's own company name is then checked against what you asked for.

This exists because of a real trap. The company "Remote" maps to the board token remote, which belongs to "General Assembly Remote Jobs". Returning another company's open roles as if they were yours would quietly corrupt a benchmark, so by default that input is skipped and reported:

! "Remote" -> board "remote" exists but is named "General Assembly Remote Jobs" — not confident it is "Remote"

Every row carries matchConfidence: token (you gave a token or URL), exact, or fuzzy. Set allowUnverifiedMatches to accept doubtful matches anyway.

If a company comes back unresolved, the usual reason is that it is not on Greenhouse at all — plenty of companies use a different ATS. Passing the board URL from their careers page always works.


How the period is decided

payPeriod is read from the label the employer put next to the number — "Annual Base Salary Range", "Hourly Base Pay Range", "Gross Monthly Pay Range". Across the 1,508 ranges in the sample, every one was resolved from the text; payPeriodInferred was false on all of them. If a posting ever gives a number with no period wording at all, the field falls back to magnitude and payPeriodInferred is set to true so you can filter those rows out.

Multi-band postings

Some employers publish a separate band per pay zone — Robinhood quotes three on many roles. payMin/payMax are the first band and payRangeCount tells you how many there were, so you can spot those rows rather than silently treating a three-zone posting as a single band. Turn on includeDescription to read the rest.

What the parser refuses to do

It will not invent a salary. Each of these appears in real postings and each produced a bogus number until it was fixed:

  • 500-5000 FTE — a customer headcount band, not 500–5000 in a currency called "FTE"
  • 1-7, BGP — a routing protocol in a networking role
  • 3 - 5 years of experience
  • $231,000-$275,000 OTE — a real range, but "OTE" is not a currency code

A range is only accepted if it carries a real currency symbol or a valid ISO-4217 code, and the parser scans the whole posting rather than stopping at the first number-shaped thing it sees.


Source, limits and compliance

  • Source: Greenhouse's documented public Job Board APIhttps://boards-api.greenhouse.io/v1/boards/<token>/jobs. No key, no login, no browser. boards-api.greenhouse.io/robots.txt restricts only /embed/.
  • Greenhouse boards only. Lever and Ashby are deliberately not supported; each of them restricts automated access in a way we will not work around. If the company you want is not on Greenhouse, this actor will tell you so rather than return nothing silently.
  • Only open, published roles. There is no history: a role that closed yesterday is gone. To build a time series, run on a schedule and keep your datasets.
  • Organisation-level data only. Company, role, office, department, pay band. No applicant or employee identity is read or emitted — the endpoint exposes none.
  • Every run prints a full tally: written · with a pay range · postings seen · filtered out · unresolved companies · board fetch failures. A short run always has a stated reason.