# BambooHR Jobs Scraper (`deriverge/bamboohr-jobs-scraper`) Actor

Open jobs from any BambooHR careers page with department, employment status, location, posting date and the pay the employer enters. List board names, links or company domains, or leave the list empty to search more than 40,000 open BambooHR jobs in our daily index.

- **URL**: https://apify.com/deriverge/bamboohr-jobs-scraper.md
- **Developed by:** [deriverge s.r.o.](https://apify.com/deriverge) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 85.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 jobs

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

## BambooHR Jobs Scraper

BambooHR Jobs Scraper returns the open jobs from the BambooHR careers pages you list, one row per job: title, department, employment status, location, posting date and the pay the employer typed into BambooHR's compensation field. Enter board names such as `atlas` or links such as `https://atlas.bamboohr.com/careers` in **Career sites** and click **Start**. Leave the list empty to search our daily index of more than 40,000 open BambooHR jobs instead. BambooHR boards publish no team, workplace type or update date. It costs $1.80 per 1,000 jobs on the Free plan ($0.90 on Business), and the $5 of monthly credit in Apify's Free plan covers about 2,700 jobs.

### What data does it return?

| Field | Description |
|---|---|
| `title`, `department` | Job title and the BambooHR department, such as `Corporate` or `Engineering - R&D`. |
| `employmentType`, `employmentTypes` | The employment status in the company's own words (`FT`, `Full-Time`, `India - Salaried`) and the normalized `full-time`, `part-time`, `contract` or `internship`. |
| `locations`, `countries` | City and state as BambooHR lists them, such as `Clovis, California`, and the country codes read from them. A location that names no country, such as `Tokoroa, Waikato`, leaves `countries` empty. |
| `salaryText` | The compensation field as the employer wrote it: `$90,000 - $120,000`, `$37-48` or `$22 - $25 Hourly DOE`. |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | The same pay as numbers, with the currency and a period such as `year` or `hour`. When the text names no period, the size of the amount decides: `$37-48` is read as hourly, `$90,000 - $120,000` as yearly. |
| `salaryYearlyMin`, `salaryYearlyMax` | The pay converted to a year (hourly times 2,080), to compare hourly and salaried jobs. |
| `postedAt` | The day the job was posted on BambooHR, as midnight UTC. |
| `companyName` | The company name from the careers page, such as `Provost & Pritchard`. |
| `url` | The job page, `https://<board>.bamboohr.com/careers/<id>`, which also holds the application form. |
| `remote`, `workArrangement` | `remote` is `true` only when BambooHR flags the job as remote, otherwise `null`. `workArrangement` is `remote`, `hybrid` or `onsite`, read from the location and from clear sentences in the ad. |
| `description`, `language` | The ad as plain text and its language code, with **Include the full job description** on. |
| `skills`, `experienceYearsMin`, `experienceYearsMax`, `educationLevel`, `visaSponsorship` | Read from the ad: tools and certifications such as `GAAP` or `QuickBooks`, years of experience asked for, the lowest degree mentioned and any statement on visa sponsorship. |
| `seniority`, `jobCategory` | Level and category read from the title, such as `mid` and `finance`. |
| `key`, `jobId`, `company`, `input`, `reference`, `firstSeenAt` | Stable key `bamboohr:<board>:<id>`, BambooHR's job number, the board name, your input line, your own label for the company and when this run read the job. |
| `team`, `workplaceType`, `updatedAt`, `companyWebsite`, `applyUrl` | Always empty when you list boards: BambooHR does not publish the first four, and the form is on the page in `url`. |

### How to scrape BambooHR jobs

1. Put each company on its own line in **Career sites**: the board name (`atlas`), the board link (`https://atlas.bamboohr.com/careers`) or the company's domain. A domain works when the company's careers page links to its BambooHR board. Lines that lead to another applicant tracking system are skipped and listed in `SUMMARY`.
2. Filter if you need to: **Title keywords (any of)** and **Exclude title keywords** look at the title, department and team, **Countries** takes names or codes such as `US` or `Canada`, and **Seniority**, **Job category**, **Work arrangement**, **Minimum yearly salary** and **Posted within the last N days** narrow it further.
3. Turn on **Include the full job description** for the ad text and the skills, experience and education read from it. The actor opens every job's detail page anyway to get its date and pay, so this adds no requests.
4. Click **Start**. The **Output** tab lists the jobs for export as CSV, Excel or JSON, and `SUMMARY` in the key-value store gives the number of jobs per board.

From the API, US jobs at three companies with their descriptions, paying at least $80,000 a year:

```json
{
  "companies": ["ppeng", "https://sunayu.bamboohr.com/careers", "alkira"],
  "countries": ["US"],
  "minYearlySalary": 80000,
  "includeDescription": true
}
```

### Example output

A job from a run on 11 October 2026 over four boards with descriptions on. The `description` is cut after its first sentence here, marked ` ...`.

```json
{
  "key": "bamboohr:ppeng:119",
  "ats": "bamboohr",
  "company": "ppeng",
  "companyName": "Provost & Pritchard",
  "jobId": "119",
  "title": "Assistant Controller",
  "locations": [
    "Clovis, California"
  ],
  "remote": null,
  "department": "Corporate",
  "team": null,
  "employmentType": "FT",
  "workplaceType": null,
  "salaryText": "$90,000 - $120,000",
  "postedAt": "2026-10-08T00:00:00.000Z",
  "updatedAt": null,
  "url": "https://ppeng.bamboohr.com/careers/119",
  "applyUrl": null,
  "description": "Summary\n\nProvost & Pritchard is looking for an Assistant Controller to play a key role in protecting the financial integrity and supporting the operational efficiency of the organization. ...",
  "language": "en",
  "reference": null,
  "input": "bamboohr:ppeng",
  "firstSeenAt": "2026-10-11T16:32:22.334Z",
  "seniority": "mid",
  "jobCategory": "finance",
  "employmentTypes": [
    "full-time"
  ],
  "workArrangement": "onsite",
  "countries": [
    "US"
  ],
  "salaryMin": 90000,
  "salaryMax": 120000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryYearlyMin": 90000,
  "salaryYearlyMax": 120000,
  "visaSponsorship": null,
  "skills": [
    "GAAP",
    "CPA",
    "Excel",
    "QuickBooks",
    "Power BI"
  ],
  "experienceYearsMin": null,
  "experienceYearsMax": null,
  "educationLevel": "bachelor"
}
```

### How much does it cost to scrape BambooHR jobs?

| | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| 1,000 jobs | $1.80 | $1.44 | $1.17 | $0.90 |

You pay only for the events in the table. There is no start fee, and compute time and proxies are included.

Four boards (Provost & Pritchard, Sunayu, Alkira and Gold Coast Dental) had 126 open jobs on 11 October 2026, which cost $0.2268 on the Free plan and $0.1134 on Business. Jobs your filters remove, jobs the new-only mode has already sent and inputs that turn out to be on another system cost nothing.

### Limits

- Detail pages are read 5 at a time, for up to 300 jobs per board. The four boards above took 27 seconds with descriptions, and the two prefilled boards, 31 jobs, 5 seconds.
- Pay is free text. 108 of the 126 jobs above had it. Entries without a currency sign (`80,000-150,000`), shares such as `42% of collections` and words such as `DOE` stay in `salaryText` without numbers, and `$800` for a weekend dentist shift is read as a monthly amount.
- Some employers enter no office address for remote jobs, and those jobs come with empty `locations`: 18 of 27 jobs on Alkira's board in October 2026.
- A company domain is matched only through a link on its careers page. If that fails, as it did for anchorqea.com, enter the board name from the BambooHR link.
- A board that its owner has closed to the public answers HTTP 401, and `SUMMARY` names it with no jobs.

### Searching all BambooHR jobs

With **Career sites** empty, the actor searches our index of BambooHR boards, rebuilt every night: on 11 October 2026 it held 42,467 open jobs from 5,923 companies. Title keywords then match the title only, the newest jobs come first and **Maximum jobs (index search)** stops the run at 1,000 unless you change it. Index rows name the company in `company` and the board in `companySlug` and `careerSiteUrl`.

The index has no posting dates or pay for BambooHR, so without descriptions those fields are empty and **Posted within the last N days** cannot remove anything. With **Include the full job description** on, every board in the result is read again during the run, which fills dates, pay and `applyUrl` and leaves out jobs closed since the night before. In our runs, `engineer` or `developer` in US jobs returned 300 rows from the index in 11 seconds, and 100 healthcare jobs read live from 68 boards took 29 seconds.

### FAQ

#### Is it legal to scrape BambooHR careers pages?

Companies publish these job boards so that anyone can read and apply, and the actor reads the same public job data the pages load, as their robots.txt allows. It collects nothing about applicants or employees. You are responsible for how you use the jobs, including any republishing.

#### Can I get alerts when a company posts a new job?

Yes. Save the boards as a task, turn on **Return only jobs posted since the last run** and schedule it daily. Every run then returns only jobs that were not on the boards the time before, and the `CHANGES` record counts the ones that closed. A task keeps its own snapshot; for runs started from the API, give a **Watch name**.

### Related scrapers

- [Career Site and ATS Jobs API](https://apify.com/deriverge/career-site-jobs-search)
- [Career Site Jobs Scraper](https://apify.com/deriverge/greenhouse-lever-workday-jobs-scraper)
- [Ashby Jobs Scraper](https://apify.com/deriverge/ashby-jobs-scraper)
- [Workable Jobs Scraper](https://apify.com/deriverge/workable-jobs-scraper)
- [Lever Jobs Scraper](https://apify.com/deriverge/lever-jobs-scraper)

### Support

This actor is built and maintained by deriverge s.r.o., a software company based in the Czech Republic. If a run fails or a field you need is missing, please open an issue in the **Issues** tab or write to us at info@deriverge.com. We respond in English and Czech. Runs can be scheduled in Apify Console or started from the **API** tab, which has examples for Python, JavaScript and cURL and works with Make, Zapier, n8n and the Apify MCP server. If the actor saves you time, a short review helps other people find it.

# Changelog

This Actor's version history is a separate document: https://apify.com/deriverge/bamboohr-jobs-scraper/changelog.md

# Actor input Schema

## `companies` (type: `array`):

One entry per company: the BambooHR subdomain (atlas), the BambooHR URL (https://atlas.bamboohr.com/careers), or just the company domain, which the actor resolves to the right careers page before it scrapes. Inputs pointing at another applicant tracking system are skipped and listed in the run summary. Leave this empty to search every open BambooHR job in our daily index instead, by keywords, country, seniority and the other filters below.

## `keywords` (type: `array`):

Keep only jobs whose title, department or team contains at least one of these words, case-insensitive. In the daily index search, when Career sites is left empty, only the title is matched. Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Drop jobs whose title, department or team contains any of these words. In the daily index search, when Career sites is left empty, the title and the company name are checked instead.

## `locations` (type: `array`):

Keep only jobs whose location contains one of these strings, for example "London", "United States", "Remote".

## `countries` (type: `array`):

Keep only jobs in these countries: English names or two-letter codes, for example United States, Germany, UK or DE. Read from the job location, so "Austin, TX" counts as United States.

## `remoteOnly` (type: `boolean`):

Keep only jobs the ATS marks as remote or whose location says remote.

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

Drop jobs older than this many days when the ATS provides a posting date. Leave empty for no limit.

## `seniority` (type: `array`):

Read from the job title in English, German, French, Spanish and more. Titles without a level count as mid.

## `categories` (type: `array`):

Read from the job title (and the department when the title says nothing), for example software, healthcare, sales or logistics. Jobs whose title fits no category are left out when this filter is on.

## `workArrangement` (type: `array`):

From the workplace field, the location and clear sentences in the description. Jobs with a place and no remote or hybrid mention count as on-site.

## `employmentTypes` (type: `array`):

Only jobs whose employment field or title states one of these types.

## `hasSalary` (type: `boolean`):

Only jobs that state pay, from the salary field or a pay range in the description (turn on the description to catch more).

## `minYearlySalary` (type: `integer`):

Only jobs whose pay, converted to a year (hourly × 2,080, monthly × 12), reaches this amount in the currency below, for example 120000.

## `salaryCurrency` (type: `string`):

Currency of the minimum yearly salary: USD, EUR, GBP, CAD, AUD and so on.

## `visaSponsorship` (type: `boolean`):

Only jobs whose description says the company sponsors visas. Reads the description.

## `descriptionKeywords` (type: `array`):

Only jobs whose title or description contains any of these, for example "python" or "SAP". Reads the description.

## `excludeDescriptionKeywords` (type: `array`):

Drop jobs whose title or description contains any of these, for example "security clearance".

## `skills` (type: `array`):

Only jobs that ask for all of these skills, for example Python, AWS or Salesforce. Known tools, languages and certifications match their other spellings (golang, k8s, postgres); anything else is matched as a whole word in the title or description.

## `maxYearsOfExperience` (type: `integer`):

Leave out jobs whose description asks for more years of experience than this, for example 2 for junior roles. Jobs that do not state years are kept.

## `languages` (type: `array`):

Only jobs written in these languages, as two-letter codes or names, for example en or English to find English-language jobs in Germany. Detected from the description.

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

Adds the job description as plain text. Costs one extra request per job on SmartRecruiters, Workable, Workday and BambooHR, so runs take longer there.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only jobs that were not in the previous snapshot. Schedule the task daily and you get a hiring-signal feed: every new opening, once, the day it appears. Closed jobs are counted in the CHANGES record.

## `watchName` (type: `string`):

Name of the snapshot used by the new-only mode, for example "competitors". Runs from a saved task get a snapshot automatically even without a name.

## `maxJobsPerCompany` (type: `integer`):

Caps the number of jobs returned per career site. Leave empty for all.

## `maxItems` (type: `integer`):

Cap on jobs returned when Career sites is empty and the daily index is searched, newest first; empty means 1,000.

## Actor input object example

```json
{
  "companies": [
    "atlas",
    "pinnacle"
  ],
  "remoteOnly": false,
  "hasSalary": false,
  "salaryCurrency": "USD",
  "visaSponsorship": false,
  "includeDescription": false,
  "newOnly": false
}
```

# Actor output Schema

## `jobs` (type: `string`):

One row per job with the unified schema: title, locations, remote, department, employment type, salary text where the ATS provides it, posting date, links and optional description.

## `changes` (type: `string`):

New, closed and retitled jobs compared with the previous snapshot of the same watch name or task.

## `summary` (type: `string`):

Per-company counts, skipped inputs with reasons, and totals.

# 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 = {
    "companies": [
        "atlas",
        "pinnacle"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("deriverge/bamboohr-jobs-scraper").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 = { "companies": [
        "atlas",
        "pinnacle",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("deriverge/bamboohr-jobs-scraper").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 '{
  "companies": [
    "atlas",
    "pinnacle"
  ]
}' |
apify call deriverge/bamboohr-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deriverge/bamboohr-jobs-scraper"
        }
    }
}
```

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/f4V3h2TAh6q0iaJrU/builds/goW0dWW3FTCoNEyWM/openapi.json
