# Greenhouse, Lever & Ashby Jobs Scraper: Career Site Jobs API (`meskaoui.azeddine/career-site-jobs-scraper`) Actor

Scrape every open job from company career sites on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee. One clean format: title, location, remote flag, salary when published, full description, apply link. $3 per 1,000 jobs, no proxy, no login. CSV, Excel, JSON, API.

- **URL**: https://apify.com/meskaoui.azeddine/career-site-jobs-scraper.md
- **Developed by:** [Azeddine MESKAOUI](https://apify.com/meskaoui.azeddine) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 job scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Scraper: Greenhouse, Lever, Ashby & more

Get every open job from a company's career site, in one clean format, whatever platform hosts it.

Supported platforms: **Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee**.

The Actor reads each platform's own public job-board API, the same data the career page shows to candidates. No login, no browser, no proxy, no personal data.

**Measured on Apify, October 2026:** 15,490 jobs from 53 companies in one run of 8 min 56 s, with full descriptions, 5,674 requests, none failed, 470 MB peak memory. A smaller run of 1,368 jobs from 8 companies took 25 seconds.

### Pricing

**$3 per 1,000 jobs** ($0.003 per job delivered). No start fee, no charge for compute time, and a company that is not found costs nothing.

| You extract | You pay |
|---|---|
| 100 jobs | $0.30 |
| 1,000 jobs | $3.00 |
| 10,000 jobs | $30.00 |

The pre-filled example stops at 50 jobs per company, so a first test run costs about $0.45. Remove the limit when you want everything.

### What it is for

- **Job boards and aggregators**: keep listings from hundreds of employers fresh, straight from the source, with the original apply link.
- **Recruiting and sales intelligence**: see who is hiring, for which teams and where. A company opening ten sales roles in Germany is telling you something.
- **Market and salary research**: compare titles, locations, remote policy and published salary ranges across companies.
- **Job alerts**: schedule a daily run with a title filter and send new rows to Slack, e-mail or a spreadsheet.
- **AI and RAG pipelines**: full descriptions as plain text, ready to embed.

### What you give it

A list of companies. Each line can be:

- a career board URL: `https://boards.greenhouse.io/stripe`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/ramp`, `https://apply.workable.com/huggingface`, `https://jobs.smartrecruiters.com/BoschGroup`, `https://bunq.recruitee.com`
- an explicit pair: `greenhouse:stripe`
- just the identifier: `stripe`. The Actor then looks for it on each platform and keeps the first one that has jobs.

Optional filters: words in the job title, words in the location, remote only, posted within the last N days. Optional limits: jobs per company, jobs in total.

#### How to find a company's identifier

Open the company's careers page and click any job. If the address bar shows one of the six platforms, the identifier is the part right after the domain: `boards.greenhouse.io/`**`stripe`**`/jobs/…`, `jobs.lever.co/`**`palantir`**`/…`. Pasting the whole URL works too.

### Example input

```json
{
    "companies": ["https://boards.greenhouse.io/stripe", "lever:palantir", "ramp"],
    "titleKeywords": ["engineer", "developer"],
    "locationKeywords": ["remote", "london"],
    "postedWithinDays": 30,
    "includeDescription": true
}
```

### Example output

One row per job. Descriptions are shortened here.

```json
{
    "ats": "ashby",
    "company": "ramp",
    "companySlug": "ramp",
    "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
    "title": "Security Engineer, Cloud",
    "department": "Engineering",
    "team": "Backend",
    "location": "New York, NY (HQ) / Remote (Canada) / Remote (US) / Miami, FL",
    "country": "USA",
    "remote": true,
    "workplaceType": "hybrid",
    "employmentType": "FullTime",
    "salary": "$211.4K – $290.6K • Offers Equity",
    "postedAt": "2026-04-07T17:12:35.753Z",
    "updatedAt": null,
    "url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
    "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
    "descriptionHtml": "<h1><strong>About Ramp</strong></h1><p>Ramp is building the smart infrastructure for finance te…",
    "descriptionText": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams, embedded in the transaction flow of every dollar a business spends…",
    "scrapedAt": "2026-10-05T17:09:24.493Z"
}
```

### Fields, and which platform fills them

Always present: `ats`, `company`, `companySlug`, `jobId`, `title`, `location`, `postedAt`, `url`, `applyUrl`, `scrapedAt`, and the description unless you turn it off.

| Field | Greenhouse | Lever | Ashby | Workable | SmartRecruiters | Recruitee |
|---|---|---|---|---|---|---|
| `department` | yes | sometimes | yes | yes | rarely | yes |
| `team` | no | yes | yes | no | yes (job function) | no |
| `country` | no | yes | yes | yes | yes | yes |
| `remote` | from the location text | when stated | when stated | yes | yes | when stated |
| `workplaceType` (remote, hybrid, onsite) | no | yes | mostly | yes | only remote or hybrid | yes |
| `employmentType` | no | yes | yes | yes | yes | yes |
| `salary` | no | when published | when published | no | no | when published |
| `updatedAt` | yes | no | no | no | no | yes |

A field the platform does not publish is `null`, never guessed. In a 53-company test (15,485 jobs), 59% of Ashby jobs and 7% of Lever jobs carried a salary; 7% overall.

`remote` is `true`, `false`, or `null` when the employer does not say.

### Run summary

Each run stores a `RUN_SUMMARY` record in the key-value store: for every company, the platform found, the number of open jobs, the number saved and a status. A company that cannot be found is reported there and in the log; it does not fail the run.

### Speed and cost

Greenhouse, Lever, Ashby and Recruitee return a whole company in one or a few requests. Workable and SmartRecruiters need one extra request per job to get the description, so they are slower; turn off **Include full job description** when you only need titles and locations.

Companies are read three at a time. Memory: 512 MB is enough for most runs, use 1 GB for very large employers with descriptions on.

### Limits

- Only companies hosted on the six platforms above. A company with a custom career site (Workday, a home-made page) is reported as "not found".
- You need to know which companies you want. This Actor does not search jobs across the whole web.
- With a total job limit, companies are read in parallel, so the limit can be used up by any of them, not necessarily the first in your list. Use **Max jobs per company** for an even split.
- It returns the jobs open now. It does not keep history; schedule runs if you want to track changes over time.

### FAQ

**Is this legal?** The Actor reads public job postings that employers publish for anyone to see, through the public endpoints their own career pages use. It collects no candidate or personal data.

**Can I get only new jobs?** Use **Posted within the last N days** with a scheduled run, for example 1 day on a daily schedule.

**The identifier is not found. Why?** Either the company is not on one of the six platforms, or its identifier differs from its name (`BoschGroup`, not `bosch`). Paste the career board URL instead.

**Something is missing or broken?** Open an issue on the Issues tab with the company you tried. Platform changes are fixed quickly.

# Actor input Schema

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

One company per line. Accepted: a career board URL (https://boards.greenhouse.io/stripe, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/ramp, https://apply.workable.com/huggingface, https://jobs.smartrecruiters.com/Bosch, https://bunq.recruitee.com), an explicit pair like greenhouse:stripe, or just the company identifier (stripe) to let the Actor find which platform hosts it.

## `titleKeywords` (type: `array`):

Keep only jobs whose title contains at least one of these words. Case-insensitive. Leave empty to keep all jobs.

## `locationKeywords` (type: `array`):

Keep only jobs whose location contains at least one of these words, for example Paris, Germany, Remote. Leave empty to keep all locations.

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

Keep only jobs flagged as remote by the employer, or whose location mentions remote.

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

Keep only jobs published in the last N days. Leave empty for no date filter. Jobs without a publication date are kept.

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

Adds the description as plain text and HTML. Turn off for lighter, faster results.

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

Stop after this many jobs for each company. Leave empty for all jobs.

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

Stop the run after this many jobs overall. Leave empty for no limit.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "lever:palantir",
    "ramp"
  ],
  "remoteOnly": false,
  "includeDescription": true,
  "maxJobsPerCompany": 50
}
```

# Actor output Schema

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

All jobs found: company, title, location, remote flag, department, salary when published, dates, links and full description.

## `runSummary` (type: `string`):

For each company: the platform found, open jobs, jobs saved and status, plus request and retry counts.

# 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": [
        "https://boards.greenhouse.io/stripe",
        "lever:palantir",
        "ramp"
    ],
    "maxJobsPerCompany": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("meskaoui.azeddine/career-site-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": [
        "https://boards.greenhouse.io/stripe",
        "lever:palantir",
        "ramp",
    ],
    "maxJobsPerCompany": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("meskaoui.azeddine/career-site-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": [
    "https://boards.greenhouse.io/stripe",
    "lever:palantir",
    "ramp"
  ],
  "maxJobsPerCompany": 50
}' |
apify call meskaoui.azeddine/career-site-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,meskaoui.azeddine/career-site-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/gwduJsXj1c8ihPUHe/builds/FC7SG65udCIp8Rxdt/openapi.json
