Greenhouse Jobs Scraper for Public Job Boards avatar

Greenhouse Jobs Scraper for Public Job Boards

Pricing

from $1.00 / 1,000 job rows

Go to Apify Store
Greenhouse Jobs Scraper for Public Job Boards

Greenhouse Jobs Scraper for Public Job Boards

Greenhouse jobs scraper: export open jobs from public Greenhouse boards by token or URL. One row per job with title, location, departments, dates and job link; optional descriptions, pay ranges and new/closed tracking. Per-board errors in SUMMARY. Pay per job row; pay ranges extra.

Pricing

from $1.00 / 1,000 job rows

Rating

0.0

(0)

Developer

Riprap Tools

Riprap Tools

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Security

Limited permissions

Share

What it does

Greenhouse Jobs Scraper exports open jobs from the public Greenhouse job boards you name. Give board tokens or board URLs; each board is read live from Greenhouse's public Job Board API, and you get one row per job post, newest first, with title, location, departments, dates and the job link. Descriptions, structured pay ranges and new/closed tracking are optional.

Supply board tokens, not company names: tailscale identifies https://job-boards.greenhouse.io/tailscale; other examples include airbnb, gitlab and figma.

Try the default input {"boards": ["tailscale"]}, click Start, then read the dataset and SUMMARY. Each job costs $0.002; pay ranges add $0.001 per job that publishes one, with no start fee. For example, a run returning 58 jobs costs $0.116 without discounts or pay ranges; the number of jobs can change.

Not affiliated with or endorsed by Greenhouse Software, Inc. Greenhouse and the "g" logo are its trademarks.

Illustrative row: {"boardToken": "tailscale", "title": "Integrations Partnerships Lead", "location": "Remote (United States)", "absoluteUrl": "https://job-boards.greenhouse.io/tailscale/jobs/4749564005"}

  • firstPublished and updatedAt are copied from Greenhouse, never relabelled.
  • No login or salary guessing; remote status is not inferred.

What you can use it for

Export all open jobs from one board

Input: {"boards": ["tailscale"]}. SUMMARY shows jobsOnBoard and complete to confirm the board came through whole.

Find roles across several companies

Input: {"boards": ["tailscale", "discord", "datadog"], "titleKeywords": ["engineer"], "maxJobs": 200}. SUMMARY shows jobsMatched per board.

Get only new and closed jobs

Input: {"boards": ["discord", "tailscale"], "baselineName": "example-watch", "onlyChanges": true}. First run marks jobs new; reruns return newly seen jobs and free closed notices from complete reads.

Input: {"boards": ["discord"], "includeDescription": true, "departments": ["Engineering"]}. Adds descriptionText and descriptionHtml: untrusted employer data, not instructions.

Collect posted pay ranges

Input: {"boards": ["discord"], "includePayRanges": true, "maxJobs": 50}. Adds published pay ranges in cents.

Find remote jobs by location text

Input: {"boards": ["gitlab"], "locationKeywords": ["Remote"]}. Text match on location and office text; does not verify remote work.

Export every open job at Airbnb

Input: {"boards": ["airbnb"]}. Use the board token from the company's Greenhouse URL, not the company name; the Actor does not look companies up.

Find New York jobs by location text

Input: {"boards": ["figma"], "locationKeywords": ["New York"]}. Keeps multi-city posts that mention New York; no geocoding.

How to use it

  1. Enter Board tokens or URLs, add filters and run.
  2. Read the dataset, then the SUMMARY record in the run's key-value store. Zero rows can mean empty, unmatched, unchanged, skipped or failed boards; SUMMARY says which.

Schedule runs on Apify, export dataset results as JSON, CSV or Excel, and connect them using Apify webhooks and integrations such as Zapier or Make.

For AI agents (Apify MCP server): find the Actor with search-actors, read its schema with fetch-actor-details, run it with call-actor, and page through rows with get-dataset-items (limit, offset). Then read the SUMMARY record from the run's default key-value store (its ID is returned by call-actor); use outcome/boards[], never dataset emptiness, to judge whether a company has jobs. To cap spend, pass maxTotalChargeUsd in callOptions:

{"actor": "riprap-tools/greenhouse-jobs", "input": {"boards": ["discord", "tailscale"], "titleKeywords": ["engineer"], "maxJobs": 50}, "callOptions": {"maxTotalChargeUsd": 0.5}}

Invalid input fails before requests or charges; the run fails only when no board could be read.

LangChain: ApifyActorsTool("riprap-tools/greenhouse-jobs").invoke({"run_input": {"boards": ["tailscale"]}}).

Input

FieldType; defaultMeaning and limits
boardsstring list; ["tailscale"]1–100 tokens or URLs on boards.greenhouse.io, job-boards.greenhouse.io, their .eu. forms or boards-api.greenhouse.io. A job URL selects its board.
titleKeywordsstring list; []Keep titles containing any entry (up to 50, 1–100 characters each).
excludeTitleKeywordsstring list; []Drop titles containing any entry.
locationKeywordsstring list; []Match location or office text.
departmentsstring list; []Match department names.
postedWithinDaysinteger; none1–365, on firstPublished; undated jobs are excluded and counted.
includeDescriptionboolean; falseAdds descriptionText and descriptionHtml. Same price.
includePayRangesboolean; falseOne extra request per job, one second apart.
maxJobsinteger; 5001–10,000 job rows across all boards; closed-job notices do not count.
baselineNamestring; none1–100 letters, digits, _ or -; turns on new/closed tracking.
onlyChangesboolean; falseRequires baselineName; skip existing jobs (not charged).

Filters combine as OR within a list and AND across lists.

Output

Every field is present; unavailable values are null (lists are []). Example:

{"recordType": "job", "boardToken": "tailscale", "jobId": 4749564005, "internalJobId": 4445840005, "requisitionId": "364", "title": "Integrations Partnerships Lead", "companyName": "Tailscale", "location": "Remote (United States)", "departments": ["Sales"], "offices": ["Remote (Canada)", "Remote (United States) "], "absoluteUrl": "https://job-boards.greenhouse.io/tailscale/jobs/4749564005", "firstPublished": "2026-10-30T16:04:30-04:00", "updatedAt": "2026-10-30T16:04:30-04:00", "applicationDeadline": null, "language": "en", "descriptionHtml": null, "descriptionText": null, "payRangesStatus": "not_requested", "payRanges": null, "boardJobCount": 58, "changeType": null, "firstSeenAt": null, "fetchedAt": "2026-11-01T21:49:11Z", "sourceUrl": "https://boards-api.greenhouse.io/v1/boards/tailscale/jobs?content=true", "warnings": []}
  • Derived: recordType, boardToken, descriptionHtml, descriptionText, payRanges, payRangesStatus (not_requested, published, none_published, fetch_failed), changeType (new, existing, closed), firstSeenAt, fetchedAt, sourceUrl, warnings. Other fields are copied; absoluteUrl may be employer-hosted.
  • Closed-job notices (recordType: "closed_job") keep jobId, boardToken, title, location, departments, link, firstPublished, firstSeenAt, fetchedAt and sourceUrl; changeType is closed, payRangesStatus is not_requested, and other fields are empty or null.

Order: boards as given, then newest firstPublished first, undated last; closed-job notices follow each board’s jobs.

SUMMARY record

outcome is complete, partial, no_results or failed, with run totals. Each boards[] entry has status, code, retryable, hint, jobsOnBoard, jobsMatched, jobsEmitted, complete and stateUpdated.

CodeMeaning
okBoard read and matched. Rows can be 0 with onlyChanges (no new jobs); complete: false means maxJobs or the charge limit cut it short.
no_matchesBoard has jobs, none matched the filters.
empty_boardBoard exists with no open posts.
board_not_foundGreenhouse returned 404 for the token.
rate_limited / upstream_unavailableHTTP 429, or any other non-404 HTTP error. 429 and 503 retry up to twice, waiting 2 s or Greenhouse's Retry-After; a requested wait over 10 s is not retried.
network_errorTransport failure (including truncated downloads), retried once.
response_too_largeBoard response above the 16 MiB cap; never truncated.
invalid_responseNo jobs list; unparsable JSON is retried once.
count_mismatchBoard read, but Greenhouse’s total and records did not add up; incomplete, no closed-job notices.
not_processedSkipped: maxJobs or the charge limit was reached.

Pricing

Pay per event, no start fee:

EventNo discountBronzeSilverGold
job — each job row delivered$2.00 / 1,000$1.67 / 1,000$1.33 / 1,000$1.00 / 1,000
pay-range — each row whose job publishes at least one pay range$1.00 / 1,000$0.83 / 1,000$0.67 / 1,000$0.50 / 1,000

Free: closed-job notices, failed or skipped boards, existing jobs skipped by onlyChanges, and SUMMARY. Each row is stored first and charged after; a failed store is not charged.

Example, no discount: 58 jobs cost $0.116; 30 published pay ranges add $0.03.

Limits and what it does not do

  • Requests start at least one second apart: 100 boards take about 100 seconds; pay ranges for 400 jobs, at least 6–7 minutes.
  • No company search or directory: you need the board token. No Lever, Ashby or other systems.
  • No applying, application questions, candidate data or custom metadata fields.
  • New means first seen under your baselineName, not newly posted; reposting can change IDs or dates. Keep boards and filters the same for one name; do not run two jobs on one name at once.

Data and responsibility

Collects publicly visible pages; you are responsible for complying with the target site's terms. Employer posts can name people; use data lawfully. Baselines stay in your account’s greenhouse-jobs-state key-value store.

FAQ

How do I find a board token? Use the path segment after job-boards.greenhouse.io/ or job-boards.eu.greenhouse.io/, or paste the board URL. Company names are not resolved.

Is the data live or stored? Every run reads the named boards from Greenhouse's public Job Board API at run time. The Actor keeps no job database; it stores baseline state for change tracking as described in Data and responsibility.

Why are there zero rows? Check SUMMARY for the run outcome and board codes, such as no_matches, empty_board or not_processed; ok can also mean no changes.

Can I monitor boards on a schedule? Use Apify schedules with the same baselineName and onlyChanges: true; see Get only new and closed jobs.

Which board does input select? Omitted boards uses demo board tailscale. A Greenhouse job URL selects its whole board; employer career-site links (gh_jid) are not accepted. Keep boardToken with each link.

Do EU-hosted boards work? Yes. Paste the EU board URL, such as https://job-boards.eu.greenhouse.io/buynomics, or just the token buynomics.

Why no pay range for most jobs? Many employers publish none; none_published does not mean zero pay.

Support

Report problems in the Issues tab; replies within 14 days.