Guide ยท Jobs data

How to scrape Greenhouse jobs without a headless browser

If you're about to point Playwright or Selenium at a Greenhouse careers page, stop. Every Greenhouse job board is backed by a public JSON API that returns the same jobs the page shows. You don't need a browser, a login or an API key. The only hard part is finding the company's board token.

Step 1: find the board token

The token is the slug Greenhouse uses for the company's board. Look for it in these places, in this order:

  1. The board URL. boards.greenhouse.io/figma or job-boards.greenhouse.io/figma means the token is figma.
  2. Links on the company's own careers page. Many companies host jobs on their own domain but link each job to boards.greenhouse.io/{token}/jobs/{id}, or add ?gh_jid={id} to their own URLs. Either one tells you it's Greenhouse.
  3. The embed script. Embedded boards load boards.greenhouse.io/embed/job_board/js?for={token}. The for= value is the token.
  4. A guess from the domain. figma.com โ†’ figma often works, but a match on a generic name could be a different company. Check it (see below).

Confirm a token by calling GET https://boards-api.greenhouse.io/v1/boards/{token}. It returns the board's name, so you can check that it's the company you meant. A wrong token returns 404.

Step 2: read the jobs

GET https://boards-api.greenhouse.io/v1/boards/{token}/jobs returns every published job, with meta.total as the count. Add content=true for the description, departments and offices. For pay ranges, call /jobs/{id}?pay_transparency=true per job.

import re, requests

LINK = re.compile(r"(?:boards|job-boards)(?:\.eu)?\.greenhouse\.io/(?:embed/job_board(?:/js)?\?for=)?([A-Za-z0-9_-]+)")

def find_token(careers_url):
    html = requests.get(careers_url, timeout=20, headers={"User-Agent": "Mozilla/5.0"}).text
    for token in dict.fromkeys(LINK.findall(html)):
        if token in ("embed", "v1"):
            continue
        r = requests.get(f"https://boards-api.greenhouse.io/v1/boards/{token}", timeout=20)
        if r.status_code == 200:
            return token, r.json().get("name")
    return None, None

token, name = find_token("https://www.figma.com/careers/")
print(token, name)
if token:
    jobs = requests.get(f"https://boards-api.greenhouse.io/v1/boards/{token}/jobs",
                        timeout=20).json()
    print(jobs["meta"]["total"], "jobs on the board")

Gotchas

The same pattern works for Lever and Ashby. Workday is different. All of them are covered on our Greenhouse, Lever, Ashby and Workday jobs API page.

We built this

Disclosure: Your Evenings Ltd built and sells this. If you have a list of domains rather than tokens, Greenhouse, Lever & Ashby Jobs API on the Apify Store does the token hunt for you:

Worked example with filters and completeness checks: Get only the jobs you want from Greenhouse, Lever and Ashby boards (and prove you didn't miss any) on dev.to.

FAQ

Do I need a browser to scrape Greenhouse jobs? No. The public Job Board API returns the published jobs as JSON with a plain GET request.

How do I find a company's Greenhouse board token? From its board URL, from Greenhouse links or gh_jid parameters on its careers page, or from the for= value in the embed script. Confirm it with /v1/boards/{token}.

Why does the API return 404? The token is wrong, or the company doesn't use Greenhouse.

Product names and logos belong to their owners. Your Evenings Ltd is not affiliated with or endorsed by them.