Greenhouse Jobs Scraper: $0.10 per Company, Up to 1,000 Jobs avatar

Greenhouse Jobs Scraper: $0.10 per Company, Up to 1,000 Jobs

Pricing

from $70.00 / 1,000 company lookups

Go to Apify Store
Greenhouse Jobs Scraper: $0.10 per Company, Up to 1,000 Jobs

Greenhouse Jobs Scraper: $0.10 per Company, Up to 1,000 Jobs

Get every open job from Greenhouse boards like Dropbox, Duolingo and Discord, with title, department, location, pay ranges and apply link. Flat $0.10 per company, up to 1,000 jobs included. Schedule it for new-job alerts. MCP-ready. No login or API key.

Pricing

from $70.00 / 1,000 company lookups

Rating

0.0

(0)

Developer

Don Mangu

Don Mangu

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 days ago

Last modified

Share

Greenhouse jobs API without a key: get every open job from any company's Greenhouse job board as JSON, CSV or Excel, with filters and daily new-job alerts.

Greenhouse Jobs Scraper & API gets every open job on the Greenhouse job boards of the companies you name, read live during your run: title, department, location, remote, pay ranges when published, posted date and apply link. Paste board links, company names or websites. You pay $0.10 per company, with up to 1,000 jobs included, and there is no API key or login.

The prefilled input reads three boards and costs $0.30 in total, so a first test is cheap. The price is flat per company ($0.09 on the Scale plan, $0.07 on Business). Per job, that is $2 per 1,000 jobs for a company with 50 open jobs, $0.50 for one with 200, and $0.10 for one with 1,000. To get only new and closed jobs, save the input as a task and schedule it. No API key, proxy or login. It does not search all Greenhouse jobs by keyword: you bring the list of companies.

What the Greenhouse jobs scraper returns

  • Pay ranges. salaryRanges lists every range the company adds to a job, such as one per pay zone. salaryMin, salaryMax, salaryCurrency and salaryPeriod hold the range in the currency of the job's country, else the first. With Include job description, pay written in the text fills the salary when a job has none (salarySource is text, else board).
  • Nested departments. departmentPath gives the full path and department the last level. Greenhouse has no team field.
  • Company fields. requisitionId, applicationDeadline when set, and updatedAt, the job's last change.
  • Language. Greenhouse gives each job's language, so that filter works without descriptions.
  • Own-site links. When a company shows its jobs on its own site, url and applyUrl point there, and companyDomain is its domain, such as dropbox.com.
  • Job type and remote. employmentType comes from the Employment Type and Time Type fields. A location that says "Remote" or "Hybrid" sets remote and workplaceType; on-site jobs stay null.

How to scrape Greenhouse jobs, step by step

  1. In Companies (companies), paste Greenhouse board links, company names or websites, up to 500. A job link reads the whole board. Or pick a list in Ready-made company lists (companyLists), such as tech-companies (204 on Greenhouse).
  2. Set filters if you need them, such as Title includes, Location or Posted since, and turn on Include job description for the full text.
  3. Run it. Each company costs $0.10, with up to 1,000 jobs included, also when the name is not on Greenhouse. Descriptions are free.
  4. Open the Jobs view of the results. Set Rows to return (outputMode) to companies for one summary row per company instead.
  5. To repeat it, save the input as a task and schedule it, as in Get only new and closed Greenhouse jobs on a schedule.

If a job's address on the company's careers page starts with boards.greenhouse.io/<name> or job-boards.greenhouse.io/<name>, paste it: a job link reads the whole board. Embed links work too. EU boards (job-boards.eu.greenhouse.io) are not supported yet. If the job opens on the company's own site with gh_jid= in the address, paste the website instead. Or type the name, such as discord.

A plain name can belong to another company. companyName is the name Greenhouse gives, and warning says when it differs from yours. matchedBy says how the board was found, and companySlug is its name.

Fields on every job

jobId, jobKey (the same in every run), locations, countryCodes, country, city and region from the location text, seniority and jobFunction from the title, employmentTypeNormalized (such as full_time), postedAt, and salaryAnnualMin and salaryAnnualMax (pay per year). With Include job description: description without email addresses, phone numbers or profile links, the tools it names, experienceYearsMin, experienceYearsMax, experienceLevel, educationMin, educationRequired, visaSponsorship, visaSponsorshipText and securityClearance. Rows also have the city's latitude, longitude and timeZone, remoteRegions, and ukVisaSponsor with ukSponsorRoutes.

Filters

Filters lower the price only above 1,000 jobs.

  • Words and places: titleIncludes and titleExcludes (whole words), department, location (a country name or code, else whole words), locationExcludes, remoteOnly, remoteRegions (where remote work may be done), and near with radiusKm (distance from one city).
  • Values: workplaceTypes, employmentTypes, seniorities, jobFunctions and languages. On Greenhouse, many jobs lack a workplace or job type, so those filters drop many.
  • Pay and dates: hasSalary, minAnnualSalary in minAnnualSalaryCurrency (no exchange rates), postedSince and postedBefore (a date or a period such as 7 days).
  • From the description: descriptionIncludes, skills (sets matchedSkills), maxExperienceYears and visaSponsorship turn on includeDescription and its price. descriptionFormat picks text, html or markdown.
  • Size: maxJobsPerCompany keeps the newest jobs.

A job without the value a filter needs is left out, and warning counts them. startUrls and urls are other names for companies. excludeCompanies leaves companies out. ukVisaSponsorOnly keeps companies on the UK visa sponsor register. companyLists adds ready-made lists of companies, such as tech-companies (204 on Greenhouse). Rows of list companies also end with their industry, headquarters country and size, in companyIndustry, companyCountry and companySizeBand, when known.

Input example

This is the input the form is filled in with when you open the Actor, as JSON. Paste it into the JSON tab of the input, or send it as the run input through the API. Fields you leave out keep their defaults. It reads the Greenhouse jobs of the companies listed in companies.

{
"companies": [
"https://boards.greenhouse.io/dropbox",
"https://job-boards.greenhouse.io/duolingo",
"https://boards.greenhouse.io/discord"
]
}

How much does the Greenhouse jobs API cost?

EventPriceWhat you get
Company lookup (company-lookup)$0.10 (Scale $0.09, Business $0.07)One company's job list, up to 1,000 jobs, including the first check with Only new jobs
Extra 1,000 jobs (extra-1000-jobs)$0.045 (see the Store page)Each further 1,000 job rows of the same company, or part of them
New jobs check (new-jobs-check)$0.002A later check with Only new jobs, per started 1,000 open jobs on the board

So 100 companies cost $10 ($7 on the Business plan). A daily Only new jobs check of them then costs $0.20.

A website that links no job board, and whose name is not on Greenhouse, costs the company price. A company over your spending limit is neither delivered nor charged.

Get only new and closed Greenhouse jobs on a schedule

Turn on Only new jobs since my last check (onlyNewJobs), save the input as a task, and schedule it. The first check of a company returns its full list for the company price. Later checks return new and closed jobs, with change set to new or closed and an alert line (alertText), for $0.002 per started 1,000 open jobs on the board.

Alert webhook URL (alertWebhookUrl) posts to Slack, Discord, Teams, Make, Zapier or n8n after a check with changes, not on quiet days (alertMaxJobs, alertOnFirstCheck).

Rows have firstSeenAt, closed rows closedAt and daysOpen. reposted marks a new job matching one closed within 30 days; skipReposts leaves those out, counted in skippedRepostsCount and skippedReposts. With includeUpdatedJobs, changed jobs come back as updated, with changedFields and previous values.

Each monitorName and filter set keeps its own memory in your Apify account.

Job board feed (XML)

This is for feeding a job board that imports XML or JSON feeds, or any tool that reads one. Set Output profile (outputProfile) to jobBoardFeed. Each job row then has the same flat fields in every run, and the description is turned on for you at no cost. The price does not change: it is still the company price, and no new events are added.

Fields of a feed row: guid (the job key, such as greenhouse:dropbox:8220578, the same in every run), title, company, location, url (the public job page), applyUrl (the apply link, else the job page), datePosted and dateUpdated (ISO 8601), descriptionHtml, descriptionText, employmentType, remote (true, false or null when unknown), workplaceType, department, country, salaryMin, salaryMax, salaryCurrency and salaryPeriod. A value the board does not give is null. Company and status rows are not changed, so a company with no jobs still gets its status row. Status rows have no guid, so skip rows without one when you import. With the default standard profile nothing changes.

Read the results of a run as XML with the dataset items endpoint. format=xml returns XML, xmlRoot names the root element (default items) and xmlRow names the element around each row (default item):

https://api.apify.com/v2/datasets/<datasetId>/items?format=xml&xmlRoot=jobs&xmlRow=job&clean=1&token=<YOUR_API_TOKEN>

To always read the newest run of this Actor, use the last run variant:

https://api.apify.com/v2/acts/<actorId>/runs/last/dataset/items?status=SUCCEEDED&format=xml&xmlRoot=jobs&xmlRow=job&clean=1&token=<YOUR_API_TOKEN>

Replace <datasetId> or <actorId> with your own, and <YOUR_API_TOKEN> with your own Apify API token from Console, Settings, API & Integrations. Never post a feed link with your real token in it where others can read it. clean=1 leaves out empty rows and hidden fields. For JSON, use format=json in the same URL.

To refresh the feed every day:

  1. Save the input you want as a task: open the Actor, fill in the companies, set Output profile to jobBoardFeed, and click Save as a new task.
  2. In Apify Console, open Schedules, click Create new, set the cron (for example 0 6 * * * for 06:00 every day), and add your task under Actors/Tasks.
  3. Point your job board's import at the last run URL of the task, or of this Actor, from above.

What it does not do: it does not post to any job board for you, and it does not check the import rules of any particular platform. Check what your board accepts for its feed and map the fields to it.

Integrations

Save your input as a task first: turn on Only new jobs since my last check, give it a Monitor name, and add a schedule. Each scheduled run then returns the new and closed jobs, with change set to new or closed.

Google Sheets. On your saved task's Integrations tab, add the Google Sheets Import & Export Actor, connect Google, pick a spreadsheet and set Mode to append. Each scheduled run adds its jobs as new rows, and the change column tells you which are new and which closed.

n8n. Add a Schedule Trigger, then the Apify node with Actor tasks and Run Task and Get Dataset, and pick your saved task. The node waits for the run and passes on each job as one item.

Make. The Apify app runs your task with Run a Task, and Get Dataset Items reads its jobs. To react to scheduled runs, start with Watch Task Runs.

Zapier. The Apify app has a Finished task run trigger and a Run Task action. Add Fetch dataset items to pass the jobs to the next step.

Webhooks. For a ready message, paste a Slack, Discord, Teams, Make, Zapier or n8n incoming webhook link into Alert webhook URL. It posts only after a check with new or closed jobs. To start your own system instead, add an HTTP webhook for Run succeeded on the task's Integrations tab. Apify then sends each run's details to your URL, including the defaultDatasetId that holds its jobs.

For AI agents

Use it to answer "is company X hiring for Y right now?" for companies on Greenhouse. Input (give companies or companyLists, up to 500 companies in all):

{"companies": ["https://boards.greenhouse.io/dropbox", "duolingo"], "jobFunctions": ["engineering"], "postedSince": "7 days", "maxJobsPerCompany": 50}

Output, one row per job: company, companyStatus, title, departmentPath, location, countryCode, remote, jobFunction, salaryMin, salaryMax, salaryCurrency, postedAt, url and more, plus description with includeDescription. A company without jobs gets a status row.

Price: $0.10 per company with up to 1,000 jobs, also when the name is not on Greenhouse. Descriptions are free. More in How much does the Greenhouse jobs API cost?.

Many companies, or companies on different job boards? ATS Jobs API reads Greenhouse and 21 other job boards in one run for $0.045 per company.

Use it from Claude, Cursor or another AI agent (MCP)

The Apify MCP server lets an AI agent run this Actor as a tool. Add this server URL to your MCP client, such as Claude Desktop, Cursor or VS Code:

{
"mcpServers": {
"greenhouse-jobs": {
"url": "https://mcp.apify.com?tools=conserving_celerytop/greenhouse-jobs-api"
}
}
}

On the first connection, your browser opens so you can sign in to Apify and approve access. The ?tools= part adds this Actor as a tool, and the Apify MCP server also adds tools to read the run and its dataset items. Setup steps for each client are in the Apify MCP server documentation.

Then ask in plain words, for example "Is Duolingo hiring data engineers right now?". The agent fills in the Actor's input. A good input for that question:

{
"companies": ["duolingo"],
"titleIncludes": ["data engineer"],
"postedSince": "30 days",
"maxJobsPerCompany": 20
}

Each company in companies costs $0.10 with up to 1,000 jobs included, the same as any other run, and a limit such as maxJobsPerCompany of 20 is enough for a quick question. Only companies or companyLists is needed; other fields such as jobFunctions, location and remoteOnly are optional filters. Each result row has title, departmentPath, location, salaryMin, salaryMax, salaryCurrency, postedAt and url. A company with no jobs returns a status row, so the agent can tell "not hiring" from "board not found" by companyStatus. See For AI agents for more input and output fields.

Output

A job row from a real run, shortened. Unknown values are null.

{
"rowType": "job",
"company": "https://boards.greenhouse.io/dropbox",
"ats": "greenhouse",
"companyName": "Dropbox",
"companyStatus": "ok",
"charged": true,
"requisitionId": "R11708",
"title": "Product Manager",
"departmentPath": "EPD > Product Team > Prod - DocSend (Sub Team)",
"location": "Remote - Canada: Select locations",
"countryCode": "CA",
"employmentType": "Regular, Full Time",
"salaryMin": 157300,
"salaryMax": 212700,
"salaryCurrency": "CAD",
"postedAt": "2026-09-23T19:29:14.000Z",
"url": "https://jobs.dropbox.com/listing/8220578?gh_jid=8220578"
}

Set Rows to return (outputMode) to companies for one summary row per company, or both. rowType is job, company or status. Summary rows have boardUrl, openJobs, jobsPostedLast7Days, jobsPostedLast30Days, jobsOpenOver90Days, newestPostedAt, oldestPostedAt, remoteJobs, remoteShare, engineeringShare, salesShare, salaryCoverage, salaryMedians, medianSalaryMin, medianSalaryMax, medianSalaryCurrency, medianSalaryPeriod, topDepartments, topLocations, countries, seniorityCounts, functionCounts, functionCountsLast30Days, leadershipRoles and firstHireRoles. Descriptions add topTools, toolCoverage, visaSponsorshipShare and medianExperienceYearsMin. Only new jobs adds newJobs, closedJobs, updatedJobs, repostedJobs, medianDaysOpen, newFunctions, newCountries and previousCheckAt.

The COMPANIES record has each company's status, with inputDomain, careerPageSource, fetchedAt, error, chargedEvent, chargedEventCount, extraJobBlocksCharged, upstreamCalls, companyTotalOpenJobs, companyMatchedJobs, companyJobsReturned, companyJobsWithoutDate, newJobsCount, closedJobsCount, updatedJobsCount and firstCheck.

Statuses and charges

companyStatusMeaningCharged
ok, no_matching_jobs, no_open_jobsThe board was readYes
not_foundGreenhouse has no board by this nameYes
source_errorGreenhouse failed or did not answerYes
no_job_board_foundThe website links no job board, and its name is not on GreenhouseYes
unsupported_job_boardAnother job board, linked or found on the website, or an EU board. error says whyNo
website_unavailableWe could not read the website, and its name is not on GreenhouseNo
invalid_input, duplicateNot a link, website or name, or the same board as another entryNo
skipped_time_limit, skipped_spending_limitOut of time, or over your spending limitNo
skipped_client_disconnectedOnly in Live Jobs HTTP API. Your client disconnected firstNo
internal_errorSomething failed on our sideOnly if it happened after we read the board

Other job boards: ATS Jobs API and more

This Actor reads only Greenhouse. The same list of companies works in our other job Actors:

Closest to this one:

More Actors from the same developer:

Job data

Company and salary research

Content, media and research

FAQ

Is this an official Greenhouse API, and is it legal to collect these jobs? No, it is not official. It reads the public Greenhouse job board API, with no login. Greenhouse's own documentation says: "Job Board data is publicly available, so authentication is not required for any GET endpoints." This Actor reads the jobs companies publish on their public Greenhouse boards, and it returns descriptions without email addresses, phone numbers or profile links. It is not affiliated with or endorsed by Greenhouse, whose name is a trademark of its owner. We cannot give legal advice, so check that your use follows the laws and terms that apply to you.

How do I find a company's Greenhouse board link, and why did a name return not_found? Open a job on the company's careers page and look at its address. If it starts with boards.greenhouse.io/<name> or job-boards.greenhouse.io/<name>, paste it: a job link reads the whole board, and <name> is the board name (Greenhouse's documentation calls it the board token). If the job opens on the company's own site with gh_jid= in the address, paste the website instead. Or type the name, such as discord. EU boards (job-boards.eu.greenhouse.io) are not supported yet. Board names often differ from brand names, so a name can return not_found (Greenhouse has no board by that name, and the lookup is charged) or match another company. Check companyName, the name Greenhouse gives, and warning, which says when it differs from yours. matchedBy says how the board was found. If a name fails, paste a job link or the company's website.

Does it search all Greenhouse jobs by keyword? No. You bring the companies: paste board links, names or websites (up to 500), or pick a ready-made list in Ready-made company lists (companyLists): ai-companies, tech-companies, remote-first, europe-tech or startups. Filters then narrow each company's jobs, for example titleIncludes, location, remoteOnly, jobFunctions, postedSince or hasSalary. Each company in a list is one lookup at the company price, also when no job matches its filters. To look across many companies for one role, pick a list and set Title includes.

How fresh are the jobs, and how do I get new jobs every day? The Actor reads each company's board when you run it, so you get the jobs the board shows at that moment. fetchedAt is when the lookup started, postedAt is when the job was first published on Greenhouse and updatedAt is its last change. For a daily check, turn on Only new jobs since my last check (onlyNewJobs), save the input as a task and schedule it. The first check of a company returns its full list for the company price. Later checks return the new and closed jobs, with change set to new or closed and an alert line (alertText), for $0.002 per started 1,000 open jobs on the board. Add an Alert webhook URL (alertWebhookUrl) to get a Slack, Discord, Teams, Make, Zapier or n8n message after a check with changes, and none on quiet days. More in Get only new and closed Greenhouse jobs on a schedule.

Will I get duplicates or reposted jobs? Every job has a jobKey that stays the same in every run, such as greenhouse:dropbox:8220578, so you can match rows across runs. If two entries point to the same board, the board is read and charged once, and the second entry gets the status duplicate at no charge. A company that is in two lists, or in a list and in Companies, is also read and charged once. With Only new jobs, you receive only jobs you have not received before, plus jobs that closed. A job that comes back under a new id is marked reposted when a job with the same title and location closed in the last 30 days. Turn on Skip reposted jobs (skipReposts) to leave those out.

How many jobs do I get per company, and what does it cost? All open jobs of the company, up to 1,000 jobs for the company price of $0.10 ($0.09 on the Scale plan, $0.07 on Business). Each further block of up to 1,000 jobs costs $0.045, and a company can return up to 10,000 jobs. To cap it, set Max jobs per company (maxJobsPerCompany), which keeps the newest jobs, for example 50. A value of 1,000 or less never pays the extra block. Filters lower the price only above 1,000 jobs, and descriptions are free. The prefilled input reads three boards and costs $0.30.

Why does a company return no jobs, or no salary? A company with no job rows gets one status row (rowType is status) with a companyStatus. no_open_jobs means the board was read and nothing is open. no_matching_jobs means jobs exist but your filters left none. not_found and no_job_board_found mean no Greenhouse board was found. All of these are charged, and Statuses and charges lists every status. The COMPANIES record in the run's key-value store shows companyTotalOpenJobs and companyMatchedJobs for each company. A filter drops jobs that lack the value it needs, and warning counts them. Pay shows only when the company adds a pay range to the job on Greenhouse: salaryMin, salaryMax, salaryCurrency and salaryPeriod hold the range in the currency of the job's country, else the first range, salaryRanges lists all of them, and salaryAnnualMin and salaryAnnualMax give pay per year when the period is known. Turn on Include job description to fill the salary from pay written in the text, shown by salarySource set to text. Descriptions are free.

Found a problem? Open an issue under Issues.

Related Actors. Live Jobs HTTP API returns jobs in one HTTP response, at its own prices plus platform usage. Tech Jobs Search searches the open jobs of 824 companies by keyword.