# Workable Jobs Scraper: apply.workable.com Company Boards (`santamaria-automations/workable-jobs-scraper`) Actor

Scrape open jobs from Workable company boards (apply.workable.com): title, company, location, workplace type, employment type, posting date, apply URL, salary where stated and full description. Filter by keyword, location and date. Pay per result.

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

## Pricing

Pay per event

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

## Workable Jobs Scraper: apply.workable.com Company Boards

Get the open jobs of any company that hires through [Workable](https://www.workable.com). Paste a company board URL such as `https://apply.workable.com/unilabs` (or just the account name) and receive title, location, department, employment type, remote flag, posting date and apply URL as clean dataset rows.

### What you can do with it

- Pull all open roles of a list of target companies for lead generation or recruiting research.
- Track hiring over time: run it on a schedule with `postedWithinDays` and `sortBy: newest` to see only new postings.
- Feed a job board or alert system with the openings of the companies you follow.
- Filter by keyword in the title, by location or by country.

### What you get

One dataset row per job. Duplicates are removed before anything is charged, so the number of rows is the number of results you pay for.

| Field | Description |
|-------|-------------|
| `id` | Job id, unique across boards |
| `ats_job_id` | The id the portal itself uses for the posting |
| `title` | Job title |
| `company` | Account name of the board (the part after `apply.workable.com/`) |
| `ats_platform` | `workable` |
| `location`, `city`, `country` | Location text as posted, the city and the two-letter country code when they can be read from it |
| `department` | Department or team, when the board states one |
| `employment_type` | Full-time, part-time, contract and so on, when stated |
| `remote` | Remote flag, when the board states one |
| `workplace_type` | `on_site`, `hybrid` or `remote`, as the posting states it; empty when it does not say |
| `additional_locations` | The other locations of a posting that lists several (for example `Gauteng, South Africa`); `location` stays the first one |
| `description` | Full job description as HTML, with the requirements and benefits sections when the posting has them. Empty only when `includeDescription` is off or the posting page could not be read |
| `apply_url`, `job_url` | Link to the posting and to its application page |
| `created_at` | Posting date |
| `language` | Language of the posting text |
| `scraped_at` | Time of the run |

Salary fields (`salary_text`, `salary_min`, `salary_max`, `salary_currency`, `salary_period`, `salary_source`) are filled only when the posting states a salary (the salary range of the job, or a range in its description). They are never estimated.

### Input

| Field | Description |
|-------|-------------|
| `companies` | Workable board URLs or bare account names (`unilabs` is `https://apply.workable.com/unilabs`). Strings, `{"url": "..."}` objects, a single string, or several separated by commas or new lines. Empty = one sample board. |
| `keywords` | Keep only jobs whose title matches at least one keyword. They filter the jobs of the boards you list; they do not search other companies. |
| `location` | Keep only jobs in this city, region or country (`London`, `Germany`, `DE`). |
| `countries` | ISO-2 codes such as `["US", "CA"]`: keep only jobs located in these countries (jobs whose country cannot be determined are left out). |
| `includeRemoteWithoutRegion` | Only with a country filter: also keep remote jobs that state no country or region (they may not be open to applicants in that country). Default `false`. |
| `postedWithinDays` | Drop jobs older than this many days. Jobs without a posting date are kept. |
| `sortBy` | `newest` (default) or `relevance` (the portal's own order). |
| `maxJobsPerCompany` | Cap per board, counted after the filters. `0` = all. Default 50. |
| `maxResults` | Cap for the whole run. The run stops cleanly when it is reached. `0` = no limit. Default 100. |
| `includeDescription` | Include the description HTML where the board provides one. Default `true`. |

#### Example: one board

```json
{
  "companies": ["https://apply.workable.com/unilabs"],
  "maxResults": 20
}
```

#### Example: several boards with filters

```json
{
  "companies": [
    "https://apply.workable.com/unilabs",
    "ems-group"
  ],
  "keywords": ["engineer", "data"],
  "postedWithinDays": 30,
  "sortBy": "newest",
  "maxJobsPerCompany": 25
}
```

Only Workable boards are read. A URL of any other job system (Greenhouse, Lever, Workday and so on) is skipped with a log line that names the actor to use, and is never charged.

#### Supported URL formats

- Board: `https://apply.workable.com/{account}` (with or without a trailing slash, or without `https://`).
- Posting: `https://apply.workable.com/{account}/j/{SHORTCODE}/` is reduced to its board; the whole board is read.
- Bare account name: `{account}`.

### Output

```json
{
  "id": "workable-3c9d41aa-8A2F1B7C3D",
  "ats_job_id": "8A2F1B7C3D",
  "title": "Senior Backend Engineer",
  "company": "unilabs",
  "ats_platform": "workable",
  "location": "London, England, United Kingdom",
  "city": "London",
  "country": "GB",
  "department": "Engineering",
  "employment_type": "Full-time",
  "remote": false,
  "apply_url": "https://apply.workable.com/unilabs/j/8A2F1B7C3D/",
  "job_url": "https://apply.workable.com/unilabs/j/8A2F1B7C3D/",
  "language": "en",
  "created_at": "2026-10-20T09:12:44.000Z",
  "scraped_at": "2026-10-25T09:00:00Z"
}
```

The row above is illustrative; values depend on the board. `created_at` is the posting date the portal reports.

### Pricing

Pay per result. You pay the platform start fee per run and then only for the jobs you receive. Filtered-out and duplicate jobs are never charged. The pricing box on the actor page always shows the current rates.

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client, such as Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

**Example prompts once connected:**

> "Use `workable-jobs-scraper` for https://apply.workable.com/unilabs and list the open roles with title, location and apply URL."

> "Use `workable-jobs-scraper` for the account names unilabs and ems-group and return the roles posted in the last 30 days."

Configure the MCP server with the Workable Jobs Scraper preconfigured at `mcp.apify.com?tools=santamaria-automations/workable-jobs-scraper`:

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=santamaria-automations/workable-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}
```

See the auto-generated API tab on the actor page for language-specific examples (cURL, JavaScript, Python, and more).

### FAQ

**How do I find a company's Workable board URL?**
Open the company's careers page and look at the address of a job: if it starts with `apply.workable.com/`, the part right after it is the account name and `https://apply.workable.com/{account}` is the board URL. You can pass either the URL or just the account name.

**Can I search by keyword across all Workable companies?**
No. Give the board URL or account name of each company. Keywords only filter the titles of the jobs of the boards you list.

**What if a board is not found?**
The run continues with the other boards. The run status line names the board and the reason (for example `board_not_found`), and nothing is charged for it.

**Why is the description empty?**
The description is read from each job's own page, so it is empty when `includeDescription` is off, or when that page could not be read. The row still has title, location, department, employment type, date and the apply URL, and is charged the same.

**Why did I get fewer jobs than `maxJobsPerCompany`?**
The caps apply after your filters, and a board can simply have fewer open jobs. The boards are read in the order you list them, and the run stops once `maxResults` is reached.

### Limits

- Boards only; no company-name search across Workable.
- Salary fields are filled only when the posting states a salary.
- Descriptions depend on what the board provides.

### Related actors

- [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper): the same engine for 40+ job systems (Workday, SmartRecruiters, Personio and more).
- [Greenhouse, Lever & Ashby Jobs Scraper](https://apify.com/santamaria-automations/greenhouse-lever-ashby-jobs-scraper): jobs of any Greenhouse, Lever or Ashby board, with keyword search across companies.
- [Workday Jobs Scraper](https://apify.com/santamaria-automations/workday-jobs-scraper): jobs of any Workday job site.
- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): any company website to its careers page, job system and jobs.

### Support

- **Questions or issues?** Email contact@nanoscrape.com, we typically reply within 6 hours, or open a ticket in the Issues tab on the actor page.
- **Need a scraper for a job board we don't cover yet?** Email contact@nanoscrape.com with the target site and your rough usage volume.

# Actor input Schema

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

Workable board URLs such as https://apply.workable.com/unilabs, or bare account names such as unilabs (the part after apply.workable.com/). Strings or {"url": "..."} objects; a single string, or several separated by commas or new lines, also works. A URL of one job posting is reduced to its board. URLs of other job systems are skipped with a log line that names the right actor, and are never charged. With no companies (an empty input does this too) the actor runs one sample board.

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

Return only jobs whose TITLE matches at least one of these words or phrases (OR). Case and accents are ignored. A keyword of 4 or more characters matches anywhere inside the title; a keyword of 3 or fewer characters (for example QA, PM) must match as a whole word. Example: \["engineer", "manager"]. The keywords filter the jobs of the boards you list; they do not search other companies.

## `location` (type: `string`):

Optional. Return only jobs in this city, region or country, for example "London", "Germany" or "DE". Country names and ISO codes match in both directions.

## `includeRemoteWithoutRegion` (type: `boolean`):

Only matters when you filter by country (the Location input is a country, or a query carries a country). Off (default): a remote job counts for the country only when it names it ("Remote - Germany"), names a region that contains it (EMEA, Europe, EU, DACH, Americas, APAC) or is open worldwide. Remote jobs that say only "Remote" are left out and are not charged. On: those jobs are kept too, but they may not be open to applicants in the chosen country.

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

Optional. ISO 3166-1 alpha-2 codes such as \["DE", "CH"]. Returns only jobs located in these countries (jobs whose country cannot be determined are left out).

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

Optional. Drop jobs posted more than this many days ago. Jobs without a posting date are kept.

## `sortBy` (type: `string`):

"newest" returns the most recently posted jobs of each board first, so maxJobsPerCompany keeps the newest ones. "relevance" keeps the portal's own order. Boards are read in the order you list them.

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

Maximum number of jobs returned per board, counted after the filters (filtered-out jobs are never returned or charged). 0 = all jobs.

## `maxResults` (type: `integer`):

Maximum number of jobs returned in total across all companies. The run stops cleanly once it is reached. 0 = no limit.

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

Include the job description (HTML) in the output where the board provides one. Switch off for a smaller, faster run.

## Actor input object example

```json
{
  "companies": [
    "https://apply.workable.com/unilabs"
  ],
  "includeRemoteWithoutRegion": false,
  "sortBy": "newest",
  "maxJobsPerCompany": 20,
  "maxResults": 20,
  "includeDescription": true
}
```

# Actor output Schema

## `items` (type: `string`):

Job listings from Workable company boards (apply.workable.com)

# 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://apply.workable.com/unilabs"
    ],
    "maxJobsPerCompany": 20,
    "maxResults": 20,
    "includeDescription": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/workable-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://apply.workable.com/unilabs"],
    "maxJobsPerCompany": 20,
    "maxResults": 20,
    "includeDescription": True,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/workable-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://apply.workable.com/unilabs"
  ],
  "maxJobsPerCompany": 20,
  "maxResults": 20,
  "includeDescription": true
}' |
apify call santamaria-automations/workable-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/workable-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/NWpbTtOX7PCCGTA7k/builds/gWBSF3xjK1GFeptlp/openapi.json
