# Company Job Postings Scraper (`modular_enrichment/my-actor`) Actor

Extract live job postings from company career pages (Greenhouse, Lever, Ashby, Workable, Recruitee, SmartRecruiters). Clean, normalized JSON with salaries, locations, remote flags. Company-level hiring data — no LinkedIn, no personal data.

- **URL**: https://apify.com/modular\_enrichment/my-actor.md
- **Developed by:** [Kurt Blair](https://apify.com/modular_enrichment) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Job Postings Scraper — Company Career Pages (Greenhouse, Lever, Ashby & more)

Extract **live job postings directly from company career pages** — the hiring data source that never needs LinkedIn or Indeed. Point the Actor at any list of companies and get a clean, normalized dataset of every open role: title, department, locations, remote status, employment type, **salary ranges**, posting dates, and application URLs.

Supports the ATS platforms behind most tech & startup career pages:

| Platform | Coverage | Salary data | Detection |
|---|---|---|---|
| **Greenhouse** | Full board | Pay ranges where published | ✅ auto |
| **Lever** | Full board | Structured `salaryRange` where published | ✅ auto |
| **Ashby** | Full board | Structured compensation tiers | ✅ auto |
| **Workable** | Full board | Parsed from description | ✅ auto |
| **Recruitee** | Full board | Structured where published | ✅ auto |
| **SmartRecruiters** | Full board (paginated) | Parsed from description | ✅ auto |

### Why scrape career pages instead of job boards?

- **Fresher**: postings appear on the company's own board before (and sometimes instead of) aggregators.
- **Complete**: no aggregator filtering — you see every public role, including the ones never syndicated.
- **Compliant**: this Actor reads the same public, logged-out JSON endpoints the career pages themselves use. It collects **company-level data only** — job postings, not people. No LinkedIn, no Indeed, no personal data.
- **Cheap**: no headless browser, no CAPTCHAs — results stream in seconds.

### What can you do with hiring data?

- **Sales signals / ABM**: a company hiring "Salesforce Administrator" is buying Salesforce tooling. Route accounts to your reps the week the signal appears.
- **Recruiting & talent intel**: track which competitors are hiring, for what roles, where, and at what salary bands.
- **Market & investment research**: headcount growth by function is a leading indicator. Watch a portfolio or a whole sector.
- **Job boards & aggregators**: build a niche job board from the source of truth.
- **AI agents & RAG**: clean JSON, stable schema — pipe it into your agent, vector DB, Clay table, or spreadsheet without post-processing.

### Input

Three ways to specify a company — mix them freely:

```json
{
    "companies": [
        "https://jobs.lever.co/mistral",
        "greenhouse:vercel",
        "https://ramp.com",
        "linear"
    ],
    "remoteOnly": false,
    "titleKeywords": ["engineer", "data"],
    "maxTotalResults": 1000
}
```

1. **ATS board URL** — fastest, zero ambiguity (`https://boards.greenhouse.io/vercel`, `https://jobs.ashbyhq.com/ramp`, …)
2. **`platform:slug`** — explicit pair (`lever:mistral`, `workable:acme`)
3. **Company website or bare name** — the Actor fetches the careers page, finds the ATS link automatically, and falls back to probing all six platforms.

Optional filters: title keywords, location keywords, remote-only, posted-within-N-days, per-company and total result caps (cost control), full descriptions on/off.

### Output (real example rows)

Data captured from live boards on 2026-07-21:

| company | title | department | location | remote | salary | published | ats |
|---|---|---|---|---|---|---|---|
| Ramp | Security Engineer, Cloud | Engineering | New York, NY (HQ) (+ Miami, Remote US/CA) | true | $211.4K – $290.6K USD/yr | 2026-04-07 | ashby |
| Vercel | Account Executive- Startups, Greenfield | — | Hybrid - San Francisco, New York City, Austin | false | — | 2025-08-19 | greenhouse |
| Mistral | Account Executive – AI for Citizens | Business | Paris | false | — | 2025-07-28 | lever |

Full JSON per job (real record, abbreviated description omitted via `includeDescription: false`):

```json
{
    "company": "Ramp",
    "companySlug": "ramp",
    "ats": "ashby",
    "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
    "title": "Security Engineer, Cloud",
    "department": "Engineering",
    "team": "Backend",
    "employmentType": "FullTime",
    "location": "New York, NY (HQ)",
    "allLocations": ["New York, NY (HQ)", "Miami, FL", "Remote (US)", "Remote (Canada)"],
    "country": "USA",
    "isRemote": true,
    "workplaceType": "Hybrid",
    "salaryMin": 211400,
    "salaryMax": 290600,
    "salaryCurrency": "USD",
    "salaryInterval": "year",
    "salarySummary": "$211.4K – $290.6K • Offers Equity",
    "publishedAt": "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",
    "sourceEndpoint": "https://api.ashbyhq.com/posting-api/job-board/ramp",
    "scrapedAt": "2026-07-21T00:19:43.009Z"
}
```

Every field is present on every row (with `null` where the ATS doesn't publish it), so the dataset drops straight into Sheets, BigQuery, Clay, or a dataframe.

### Pricing & typical cost

Pay per result — you only pay for jobs actually saved. Filters and caps (`maxTotalResults`, `maxJobsPerCompany`) are applied **before** billing, so a title-filtered run costs a fraction of a full dump. Monitoring 500 companies weekly at ~40 open roles each ≈ 20,000 results per run.

### Scheduling & integrations

- **Schedule** the Actor (e.g. daily) and diff `jobId` sets downstream to detect newly opened/closed roles.
- Use the **Apify API**, webhooks, or the dataset export (JSON, CSV, Excel) — plus native integrations with Make, Zapier, n8n, Google Sheets, and MCP for AI agents.

### FAQ

**Is this legal?** The Actor reads public, logged-out JSON endpoints that the companies' own career pages call, and collects only company-level information (job postings). It does not touch LinkedIn, Indeed, or any personal data.

**How do I find a company's board/slug?** Usually you don't need to — pass the company website and let auto-detection work. If you want to be explicit, open the company's careers page and copy the `jobs.lever.co/...`, `boards.greenhouse.io/...`, `jobs.ashbyhq.com/...` etc. link.

**A company wasn't found. Why?** Either it uses an unsupported ATS (e.g. Workday, iCIMS, SAP SuccessFactors — on the roadmap), its board has no public roles, or its careers page hides the ATS link behind JavaScript. The run log lists every unresolved company with a tip. Passing the exact board URL always works.

**Do I get salaries for every job?** Only where the company publishes them. Ashby and Lever expose structured compensation most often; for the rest the Actor parses ranges out of the description text ("$120,000 - $150,000", "€80k–100k", etc.).

**What about descriptions?** Off by default to keep datasets light. Set `includeDescription: true` to get plain-text and HTML descriptions. (On SmartRecruiters this needs one extra request per job, so it's slower there.)

**Rate limits / blocking?** The endpoints are public APIs designed for careers-page traffic; the Actor uses gentle concurrency, retries with backoff, and optional Apify Proxy. Runs are HTTP-only — no browser — so they're fast and cheap.

**Which platforms are next?** Teamtailor, Personio, BambooHR, and JazzHR are the shortlist. Open an issue to vote.

# Actor input Schema

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

One entry per company. Accepted formats: an ATS job-board URL (e.g. `https://jobs.lever.co/mistral`, `https://boards.greenhouse.io/vercel`, `https://jobs.ashbyhq.com/ramp`), an explicit `platform:slug` pair (e.g. `greenhouse:vercel`, `lever:mistral`, `ashby:ramp`, `workable:acme`, `recruitee:acme`, `smartrecruiters:Acme`), a company website / careers-page URL (e.g. `https://vercel.com` — the Actor auto-detects which ATS the company uses), or a bare slug (e.g. `vercel` — probed against all supported ATSs).

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

If enabled, each job includes `description` (plain text) and `descriptionHtml`. Leave off for lighter, cheaper datasets when you only need titles, locations, and salaries.

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

Keep only jobs whose title contains at least one of these keywords (case-insensitive). Example: `engineer`, `sales`. Leave empty to keep all jobs.

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

Keep only jobs whose location, secondary locations, or country contains at least one of these keywords (case-insensitive). Example: `New York`, `Canada`, `EMEA`.

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

Keep only jobs detected as remote (from the ATS workplace-type field or the location text).

## `postedAfterDays` (type: `integer`):

Keep only jobs first published within the last N days (where the ATS exposes a publish date). 0 = no date filter. Useful for fresh hiring signals.

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

Cap the number of jobs saved per company. 0 = unlimited.

## `maxTotalResults` (type: `integer`):

Hard cap on the total number of jobs saved across all companies (cost control for pay-per-result billing). 0 = unlimited.

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

Proxy settings. Apify datacenter proxy (default) is sufficient — the targeted endpoints are public JSON APIs and do not aggressively block. Only needed at all for very large company lists.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:vercel",
    "lever:mistral",
    "ashby:ramp"
  ],
  "includeDescription": false,
  "remoteOnly": false,
  "postedAfterDays": 0,
  "maxJobsPerCompany": 0,
  "maxTotalResults": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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:vercel",
        "lever:mistral",
        "ashby:ramp"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("modular_enrichment/my-actor").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:vercel",
        "lever:mistral",
        "ashby:ramp",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("modular_enrichment/my-actor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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:vercel",
    "lever:mistral",
    "ashby:ramp"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call modular_enrichment/my-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=modular_enrichment/my-actor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0lRspDrmkeRz4W3M9/builds/CISnXnmRu4d4PqtF7/openapi.json
