# Career Site Jobs: Greenhouse, Lever, Ashby, Teamtailor & more (`steadydata/company-career-site-jobs`) Actor

Open jobs from company boards on Greenhouse, Lever, Ashby, Workday, Workable, SuccessFactors, iCIMS, UKG, Oracle, Dayforce, JazzHR, BambooHR, Breezy, Paylocity, Teamtailor and Recruitee, up to 200 boards a run: title, department, location, workplace type, posting date, salary and apply link.

- **URL**: https://apify.com/steadydata/company-career-site-jobs.md
- **Developed by:** [Steadydata Team](https://apify.com/steadydata) (community)
- **Categories:** Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.55 / 1,000 job listeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Career Site Jobs: Greenhouse, Lever, Ashby, Teamtailor & more

Name the companies you care about and get their open jobs straight from their own board,
**up to 200 boards per run across sixteen ATS systems**: title, department, location, workplace
type, posting date, salary where the company publishes one, and the apply link. Filter on
posting date and answer the question this niche is really about: **which of these companies
started hiring this week?** You pay per delivered job.

### Why this scraper

- **BambooHR boards included (16-09-2026).** Paste the board link (`<company>.bamboohr.com/careers`); the board's own list gives title, department, contract label, city, state and remote flag. With a date filter or `includeDescription` on, each opening's detail adds the posting date, country and the full description.

- **JazzHR boards included (16-09-2026).** Paste the board link (`<company>.applytojob.com/apply/jobs`); the board table gives title, department, location and the creation time of each posting. With a date filter or `includeDescription` on, each job page's structured posting adds the publication date, contract type, employer name, remote flag, salary where published and the full description.

- **Dayforce career portals included (16-09-2026).** Paste the portal link (`jobs.dayforcehcm.com/en-US/<company>/CANDIDATEPORTAL`); the portal's own search is used with its session and CSRF token, newest first, 25 per page, with city, state and country per posting, the posting date and the full description (delivered with `includeDescription` on).

- **Oracle Cloud HCM career sites included (16-09-2026).** Paste the site link (`<tenant>.fa.<region>.oraclecloud.com/hcmUI/CandidateExperience/en/sites/<site>`); the site's own requisition resource is read newest first, 25 per page, with primary and secondary locations, country, schedule and a short description. With `includeDescription` on, the full description, responsibilities and qualifications come from the requisition details. The company column shows the legal employer where the tenant publishes it, otherwise the tenant code.

- **UKG Pro job boards included (16-09-2026).** Paste the board link (`recruiting.ultipro.com/<company>/JobBoard/<id>/`); the board's own search is used, newest first, fifty per page, with requisition number, category, locations with city, state and country, full-time flag and a short description. The company column carries the board's client code, as UKG publishes no company name.

- **Breezy and Paylocity boards included (16-09-2026).** A Breezy board (`company.breezy.hr`) publishes its positions as a JSON feed with department, location, employment type and posting date; a Paylocity board (`recruiting.paylocity.com/recruiting/jobs/All/<id>/<company>`) carries its jobs in the page itself. Paste the board link; Breezy also works as a bare name. Breezy's position pages refuse datacenter traffic (measured 16-09-2026: HTTP 403), so `includeDescription` cannot add the full text for Breezy boards; the feed fields (title, department, location, type, date, link) are complete.

- **iCIMS portals included (16-09-2026).** Paste the portal (for example `careers-peraton.icims.com`); the job cards of the search pages carry title, location, exact posting time, requisition id and a snippet, newest first, 20 to 50 per page. Portals name their fields differently and some hide the posting date; what the portal shows is what you get. With `includeDescription` on, the full job text is read from the job page.

- **SuccessFactors career sites included (16-09-2026).** Paste the site (for example `https://jobs.sap.com` or `https://careers.ey.com`); the site is recognised by its search page, read newest first, 25 per page, every fetch checked against robots.txt. The list carries no dates, so with `postedWithinDays` or `includeDescription` the job pages are read too (one request per job) for the exact posting date, company, employment type and description.

- **Workable accounts included (16-09-2026).** Paste the apply.workable.com link or the bare account name; the hosted career site's own JSON is read, drafts are skipped, and with `includeDescription` on the description, requirements and benefits come along, one request per job.

- **Workday career sites included (16-09-2026).** Paste the site URL (for example `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`); the list is read newest first, twenty per page. Workday's list only knows the posting day (`Posted 3 Days Ago`, and `30+` is written as 31 days); with `includeDescription` on, every job also gets its exact posting date, time type and description from the job page, one request per job.

- **Ashby boards included (16-09-2026).** Ashby's documented Job Posting API adds the published salary range, workplace type and every secondary location per job; paste a jobs.ashbyhq.com link or the bare board name.

- **It reads the company's own board, not an index.** Greenhouse, Lever, Teamtailor and
  Recruitee all publish their boards through official, public, key-less API's, and that is
  what this actor reads. No search page in between, nothing to rank, nothing that goes
  stale: what the company published this morning is in your run this morning.

- **Fourteen boards, one row shape.** Greenhouse keeps departments in `departments` and dates in
  `first_published`, Lever keeps them in `categories` with an epoch in milliseconds,
  Teamtailor ships a JSON Feed with a schema.org JobPosting inside, Recruitee writes
  `2026-09-11 15:16:33 UTC`. You should not have to care, so every job becomes the same 23
  columns, with `boardType` saying where it came from and every date normalised to UTC.

- **Salary when the company publishes one.** Recruitee carries a structured range, so
  `salaryMin`, `salaryMax`, `salaryCurrency` and `salaryPeriod` come through as real
  numbers (measured: 115000 to 130000 EUR per year on a live board). The other three
  systems do not publish a salary field, so those columns stay empty there.

- **A hiring-signal filter, not just a dump.** `postedWithinDays: 7` over 200 boards is a
  weekly answer to who is expanding and where. `titleContains` and `locationContains` narrow
  it further, and because they run before delivery, a narrow question is also a cheap one.

- **Measured on 14-09-2026:** twelve boards across the first four systems, 173 jobs, 36 seconds; Ashby added 16-09-2026 (ramp, linear, supabase measured).
  Title, location, posting date, company and apply link filled on 100% of the rows,
  department on 82%.

- **Only delivered jobs are charged.** A board that does not exist, a company page without a
  board, a typo in your list: all free error records.

### Who this is for

Recruiters and sourcers tracking who is hiring in their market. Sales and partnership teams
using job postings as a buying signal (a company hiring six data engineers is building
something). Competitive intelligence, market research, and anyone maintaining a job board
for a niche.

### Who this is not for

**Read this before you buy.**

- **Sixteen ATS systems, not forty.** Greenhouse, Lever, Ashby, Workday, Workable, SuccessFactors, iCIMS, UKG, Oracle, Dayforce, JazzHR, BambooHR, Breezy, Paylocity, Teamtailor and Recruitee. Companies
  on SmartRecruiters, Personio, Taleo or a home-built board are not covered.
  SmartRecruiters is deliberately excluded: its robots rules do not permit it, and that is
  not something this portfolio works around. Personio answers automated reads with rate
  limits on most boards, so it is left out rather than delivered half the time. If you need one specific company,
  check its board first; it takes one run and a failed board costs nothing.
- **A career page is not always enough.** Give it `company.com/careers` and the page is
  fetched and searched for a board link. Measured over six career pages, one linked its
  board in the HTML and five build it with JavaScript. So discovery is a convenience, not a
  promise: pass the board URL or board name for a result you can rely on.
- **It reports the posting, not the people.** There are no recruiter names, hiring-manager
  names or contact details in the output, and there is no way to switch them on. Those
  fields are not in the source and are not wanted here.
- **Salary is the exception, not the rule.** Only Recruitee publishes a structured range,
  and only when the company filled it in. On the other three, pay sits inside the
  description text if it is mentioned at all.
- **Not every column is filled by every board.** Teamtailor's feed carries no department, so
  that column is empty on Teamtailor rows. `team` comes from Lever and Greenhouse only.
  `country` is absent on Greenhouse. That is each board's own choice, not a gap in what was
  requested, and `boardType` tells you which rules apply to a row.

### Input example

```json
{
    "boards": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://polestar.teamtailor.com/jobs",
        "https://channable.recruitee.com",
        "gitlab",
        "vercel.com/careers"
    ],
    "maxJobsPerBoard": 25,
    "postedWithinDays": 7,
    "titleContains": "engineer",
    "includeDescription": false
}
```

A bare name such as `gitlab` is tried on Greenhouse, then Lever, then Teamtailor, then
Recruitee; the first board that answers wins. `maxJobsPerBoard` is your cost ceiling per
company, newest posting first.

### Output example

```json
{
    "board": "spotify",
    "boardType": "lever",
    "companyName": "spotify",
    "jobId": "281e7db9-86ba-4a1c-8773-c23b96ed32dc",
    "title": "Staff Machine Learning Engineer, Home Surfaces",
    "department": "Engineering",
    "team": "Experience",
    "location": "New York, NY",
    "allLocations": ["New York, NY", "Stockholm"],
    "country": "US",
    "workplaceType": "remote",
    "employmentType": "Permanent",
    "salaryMin": null,
    "salaryMax": null,
    "salaryCurrency": null,
    "salaryPeriod": null,
    "postedAt": "2026-09-10T20:25:45Z",
    "updatedAt": null,
    "applyUrl": "https://jobs.lever.co/spotify/281e7db9-86ba-4a1c-8773-c23b96ed32dc/apply",
    "jobUrl": "https://jobs.lever.co/spotify/281e7db9-86ba-4a1c-8773-c23b96ed32dc",
    "description": null,
    "position": 1,
    "discovered": false,
    "status": "ok"
}
```

`discovered` is `true` when you passed a company page and the board was found for you.
Lever publishes no company name of its own, so `companyName` is the board name there. A
Recruitee row fills the salary block where the company published one, for example
`"salaryMin": 115000, "salaryMax": 130000, "salaryCurrency": "EUR", "salaryPeriod": "year"`.

Error codes: `INVALID_BOARD`, `BOARD_NOT_FOUND`, `NO_JOBS`, `ROBOTS_DISALLOWED`,
`FETCH_FAILED`, `BLOCKED`. None of them are charged. `INPUT_TRUNCATED` appears once when your input is longer than this actor accepts.

### Related actors from steadydata

- [google-jobs-reliable](https://apify.com/steadydata/google-jobs-reliable): the aggregated view, for companies not on these boards
- [website-tech-stack](https://apify.com/steadydata/website-tech-stack): what the hiring company's site runs on
- [domain-dns-ssl-report](https://apify.com/steadydata/domain-dns-ssl-report): a quick health check of the same company's domain

### Pricing

Pay per event: one `job-listed` event per delivered job. No start fee, no separate
platform-usage surcharge, and no charge for a board that fails or a filter that matches
nothing.

**Free Apify plan:** this actor delivers up to 25 rows per run for accounts on the Apify free
plan, and then stops with a message. That limit is set by us, not by Apify. It exists so the
actor keeps paying for itself for the people who do pay. Any paid Apify plan runs it at full
size, billed per delivered row, with failed rows never charged.

**Reviews:** if this actor saves you time, a short review on this page is the one thing that
helps most. Ratings are what other buyers look at first, and we have no other way to ask.

### FAQ

**How do I find a company's board name?**
It is in the URL of its job list: `boards.greenhouse.io/<name>`, `jobs.lever.co/<name>`,
`<name>.teamtailor.com` or `<name>.recruitee.com`. Paste that URL, or just the name. If a
company's careers page links its board, the page address works too.

**How do I keep a daily run cheap?**
Combine `postedWithinDays: 1` with `maxJobsPerBoard`. Only genuinely new postings are
delivered, so a daily watch over 200 companies costs a handful of events on most days
instead of the full board every morning.

**Do I get the same job twice tomorrow?**
Yes, if it still matches your filters: every run reads the board as it stands. `jobId` is
stable per board, so deduplicating on your side is one key lookup, and `postedWithinDays`
is the cheaper way to ask for new postings only.

**Why is `description` empty?**
Because it is off by default; the dataset stays small and the apply link points at the full
posting. Switch `includeDescription` on to receive the description as plain text.

**Is personal data collected?**
No. A job posting is company information. Recruiter and hiring-manager fields are not in
these responses, are never requested, and are not delivered.

**What happens when a board changes?**
Boards change from time to time; that is the nature of this work. The actor is run against
real boards daily and fixed fast, and while it is broken you are not charged, because only
delivered results cost anything.

# Changelog

This Actor's version history is a separate document: https://apify.com/steadydata/company-career-site-jobs/changelog.md

# Actor input Schema

## `boards` (type: `array`):

Job board addresses, one per row, up to 200. A Greenhouse, Lever, Ashby, Workday, Workable, SuccessFactors, iCIMS, UKG, Oracle, Dayforce, JazzHR, BambooHR, Breezy, Paylocity, Teamtailor or Recruitee board URL, a bare board name such as stripe, or a company career page that links its board.

## `maxJobsPerBoard` (type: `integer`):

Cost ceiling per board, newest posting first. One delivered job is one charged event.

## `postedWithinDays` (type: `integer`):

0 keeps every open job. Use 7 to see which companies started hiring this week. Jobs without a posting date are always kept.

## `titleContains` (type: `string`):

Optional filter, case-insensitive. Only jobs whose title contains this text are delivered and charged, so a narrow search stays cheap.

## `locationContains` (type: `string`):

Optional filter, case-insensitive, matched against every location on the job.

## `includeDescription` (type: `boolean`):

On, the full description text is delivered as well. Off keeps the dataset small; the apply link always points at the full posting.

## Actor input object example

```json
{
  "boards": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://channable.recruitee.com",
    "gitlab"
  ],
  "maxJobsPerBoard": 100,
  "postedWithinDays": 0,
  "includeDescription": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "boards": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://channable.recruitee.com",
        "gitlab"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadydata/company-career-site-jobs").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "boards": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://channable.recruitee.com",
        "gitlab",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("steadydata/company-career-site-jobs").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "boards": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://channable.recruitee.com",
    "gitlab"
  ]
}' |
apify call steadydata/company-career-site-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadydata/company-career-site-jobs"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/1MC5ildsaJJRHKAxa/builds/VzpVbQICfxsxZrPAw/openapi.json
