# Company Jobs Scraper — Greenhouse, Lever & Ashby (`hichemdev/company-jobs-scraper`) Actor

Scrape every open job from a company's own careers page across Greenhouse, Lever, Ashby and SmartRecruiters: title, department, team, location, remote flag, employment type, posting date, requisition ID and apply link. Filter by title, location or remote. No API key.

- **URL**: https://apify.com/hichemdev/company-jobs-scraper.md
- **Developed by:** [Hichem Ben Moussa](https://apify.com/hichemdev) (community)
- **Categories:** Lead generation, Business, Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 job postings

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Company Jobs Scraper — Greenhouse, Lever, Ashby & SmartRecruiters

Scrape **every open role straight from a company's own careers page**, across the four applicant tracking systems that most companies actually use. One input, one unified output schema, no matter which ATS a company runs.

This is the data behind two of the highest-value plays in B2B: **hiring signals** (a company posting 12 sales roles is expanding; one posting a "Head of Data" is about to buy tooling) and **recruiting intelligence** (every competitor's open headcount, updated daily).

No API key required.

### Supported platforms

| Platform | Handle to use | Where the handle comes from |
|---|---|---|
| **Greenhouse** | `greenhouse:stripe` | `boards.greenhouse.io/`**`stripe`** |
| **Lever** | `lever:leverdemo` | `jobs.lever.co/`**`leverdemo`** |
| **Ashby** | `ashby:ramp` | `jobs.ashbyhq.com/`**`ramp`** |
| **SmartRecruiters** | `smartrecruiters:BoschGroup` | `jobs.smartrecruiters.com/`**`BoschGroup`** |

You can paste a full job-board URL instead of `platform:handle` and the actor will work out both.

### What you get

| Field | Description |
|---|---|
| `title` | Job title |
| `company` | Company name as the board reports it |
| `platform` | Which ATS the posting came from |
| `department` | Department, e.g. *Engineering*, *Sales* |
| `team` | Sub-team, where the board publishes one |
| `industry` | Industry classification (SmartRecruiters) |
| `location` | Primary location |
| `additionalLocations` | Extra offices or remote regions the role is open to |
| `isRemote` | Remote flag from the board, or inferred from the location text |
| `employmentType` | Full-time, contract, intern… |
| `experienceLevel` | Seniority, where published |
| `postedAt` | When the role first went live |
| `updatedAt` | Last edited |
| `requisitionId` | Internal req number — useful for deduping against your own ATS |
| `description` | Full job text as plain text (opt in) |
| `applyUrl`, `jobUrl` | Direct links |

### Example input

```json
{
  "companies": ["greenhouse:stripe", "ashby:ramp", "lever:leverdemo"],
  "titleFilter": "engineer",
  "remoteOnly": true,
  "maxJobsPerCompany": 50,
  "maxJobs": 200
}
```

Track a list of target accounts by putting all of them in `companies` and scheduling a daily run.

### Example output

```json
{
  "title": "Abuse Investigator",
  "company": "Stripe",
  "platform": "greenhouse",
  "department": "Risk Operations",
  "location": "Dublin",
  "isRemote": false,
  "postedAt": "2026-09-03T17:32:53.000Z",
  "requisitionId": "See Opening ID",
  "jobUrl": "https://stripe.com/jobs/search?gh_jid=8172508"
}
```

### Who uses this

- **Sales and GTM teams** — hiring signals are the cleanest public proxy for budget and expansion. A company opening its first "RevOps" role is in market for tooling now.
- **Recruiters and talent teams** — every competitor's open roles, salaries where published, and how long a req has been sitting
- **Job boards and aggregators** — fill a niche board from the source rather than re-scraping other boards
- **Investors and analysts** — headcount growth by department is a leading indicator that shows up months before a funding announcement
- **Compensation researchers** — track which roles a market is hiring for and where

### Notes on field coverage

Different ATS platforms publish different amounts, and the actor is explicit about it rather than inventing values:

- **Greenhouse leaves `departments` empty** on its jobs endpoint unless you request full content, which makes the response about twelve times larger. The actor instead reads Greenhouse's separate departments endpoint and joins it, so you get departments **without** paying for every job description.
- **SmartRecruiters usually leaves `department` blank** and puts the meaningful classification in its job *function* field. The actor maps function into `department` so the column is populated consistently, and adds `industry` on top.
- **`employmentType` and `experienceLevel` are not published by Greenhouse at all** — expect them to be null for Greenhouse rows and filled for Ashby, Lever and SmartRecruiters.
- **Workable is not supported.** Its public widget endpoint currently returns an empty job list for every account tested, so rather than ship a mapping that silently yields nothing, it is left out.

### Pricing

Pay per result. Each job posting returned counts as one result. Filters are applied before charging, so a run that keeps 20 of 700 postings costs 20.

### Notes

- All four platforms serve these postings publicly, un-authenticated, as the feed that powers each company's own careers page.
- Big boards are big: Stripe alone had 702 open roles at the time of writing. Use `maxJobsPerCompany` so one large employer cannot consume an entire run.
- `includeDescription` is off by default on purpose — turning it on multiplies output size and run time substantially.
- This is an unofficial actor and is not affiliated with Greenhouse, Lever, Ashby or SmartRecruiters.

# Actor input Schema

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

One entry per company, as platform:handle - for example greenhouse:stripe, lever:leverdemo, ashby:ramp, smartrecruiters:BoschGroup. A full job-board URL works too. The handle is the slug from the public board URL.

## `titleFilter` (type: `string`):

Keep only postings whose title contains this text, e.g. engineer, sales, designer.

## `locationFilter` (type: `string`):

Keep only postings whose location contains this text, e.g. London, Berlin, New York.

## `departmentFilter` (type: `string`):

Keep only postings in a matching department or team, e.g. Engineering, Marketing.

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

Keep only postings flagged remote by the board or with remote in the location.

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

Fetch the full job description as plain text. Much larger output, and noticeably slower on big boards.

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

Cap per company so one large board cannot use up the whole run. 0 means no cap.

## `maxJobs` (type: `integer`):

Stop after this many postings in total.

## `proxyConfiguration` (type: `object`):

Optional. A proxy is not required for this actor.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:stripe",
    "ashby:ramp",
    "lever:leverdemo"
  ],
  "remoteOnly": false,
  "includeDescription": false,
  "maxJobsPerCompany": 0,
  "maxJobs": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All scraped items as JSON.

## `overview` (type: `string`):

Browse results in the Apify Console.

# 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": [
        "greenhouse:stripe",
        "ashby:ramp",
        "lever:leverdemo"
    ],
    "maxJobs": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("hichemdev/company-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": [
        "greenhouse:stripe",
        "ashby:ramp",
        "lever:leverdemo",
    ],
    "maxJobs": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("hichemdev/company-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": [
    "greenhouse:stripe",
    "ashby:ramp",
    "lever:leverdemo"
  ],
  "maxJobs": 50
}' |
apify call hichemdev/company-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hichemdev/company-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/kOwY8aJM6azrqe6gH/builds/BvcoOUt1zYqNec7KF/openapi.json
