# Workable Jobs Scraper \[$0.90/1K💰] | ATS Boards | Remote Jobs (`ahmed_jasarevic/jobs-workable-scraper`) Actor

Scrape job postings from any Workable ATS careers board or the global Workable job feed via Workable's own public JSON APIs. Title, company, location, department, remote flag, employment type, description HTML, apply URL. No browser needed.

- **URL**: https://apify.com/ahmed_jasarevic/jobs-workable-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.88 / 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.
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

## Jobs Workable Scraper

Scrape job postings from any Workable ATS careers board or from the whole Workable job universe as clean JSON, with no browser and no HTML parsing. Workable powers the careers sites of thousands of companies; their boards live at `apply.workable.com/<company-slug>` (legacy: `<slug>.workable.com`) and are aggregated on `jobs.workable.com`. This actor reads Workable's own public JSON APIs directly, so it is fast, cheap and reliable - the closest thing to a free workable jobs api for building your own job feed.

### Main Use Cases

- **Hiring intelligence and recruitment analytics** - track openings, departments and employment types across companies over time
- **Job board and ATS aggregation** - one JSON schema across every Workable-powered careers page, ready for a job feed or doormat
- **Talent sourcing and lead research** - company names, locations, remote flags and direct apply URLs for outreach
- **Remote work data tracking** - `workplace` filter (remote/hybrid/on_site) and `dayRange` over the global workable jobs feed
- **Competitive hiring monitoring** - see which roles a company opens, when they were posted and where

### How It Works (No Browser Required)

Workable exposes clean JSON endpoints that the site's own frontend uses. The actor calls them directly with `CheerioCrawler` (plain HTTP + JSON). There is no Cloudflare challenge, no login and no anti-bot wall on these endpoints - a plain `curl` with a desktop User-Agent returns the JSON.

| Endpoint | Purpose |
| --- | --- |
| `GET https://apply.workable.com/api/v1/widget/accounts/<slug>?details=true` | **Primary.** One request returns `{ name, description, jobs[] }` for a whole board - title, shortcode, employment type, remote flag, department, locations, `published_on`, full description HTML, apply URL |
| `GET https://jobs.workable.com/api/v1/jobs?limit=20&...` | **Global feed.** Cursor-paginated via `nextPageToken` (note: `limit` is hard-capped at 20). Supports `query`, `location`, `workplace`, `employment_type`, `day_range` |
| `GET https://jobs.workable.com/api/v1/companies/<code>` | Resolves a `jobs.workable.com/company/<code>` URL to its board slug |
| `GET https://jobs.workable.com/api/v1/jobs/<uuid>` | Single-job lookup (used during recon to prove the feed's `created` field is not the posted date) |

### Input Parameters

| Field | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `boards` | array | No | `[]` | Workable board slugs/URLs. Accepts a bare slug (`vsf-rentals`), `apply.workable.com` URL, legacy `<slug>.workable.com` URL, or a `jobs.workable.com` company/job URL. Empty = global-search mode over the whole feed |
| `query` | string | No | empty | Keyword filter (global-search mode only) |
| `location` | string | No | empty | Location filter, e.g. `London` or `United States` (global-search mode only) |
| `workplace` | string | No | unset | `remote`, `hybrid` or `on_site` (global-search mode only) |
| `employmentType` | string | No | unset | `Full-time`, `Part-time`, `Contract`, `Temporary` (global-search mode only) |
| `dayRange` | integer | No | unset | Only jobs posted within the last N days (1-365, global-search mode only) |
| `maxItems` | integer | No | 100 | Hard cap on returned rows (1-100000); free users capped at 10 |
| `maxBoards` | integer | No | 50 | Max per-company widget lookups in global-search mode (1-1000) |
| `enrichApplyUrls` | boolean | No | true | In global-search mode, look up each company's board to attach the direct apply URL, exact posted date and shortcode (adds one request per company) |
| `proxy` | object | No | off | Standard Apify proxy picker (these endpoints do not require it) |

### Output Fields

One dataset row per job (full field list in the dataset schema):

- **Identity**: `jobId` (shortcode in board mode, UUID in global-search), `shortcode`, `source` (`board-widget` or `global-feed`), `title`
- **Company**: `companyName`, `boardSlug`, `companyWebsite` (global mode), `companyUrl` (global mode), `boardUrl`
- **Location**: `location` (human-readable), `locations` (all open locations), `city`, `region`, `country`
- **Work model**: `remote` (true when fully remote), `workplace` (`remote`/`hybrid`/`on_site`)
- **Employment**: `department`, `employmentType`
- **Dates**: `postedDate`, `updatedAt`
- **Content**: `descriptionHtml` (full description incl. requirements and benefits), `applyUrl` (direct application URL), `jobUrl`
- **Metadata**: `language` (global mode), `scrapedAt`

#### Known Limitations (verified)

- **Hybrid jobs in board mode**: the widget API only exposes a `telecommuting` boolean, so hybrid jobs are reported as `on_site` with `remote: false`. The global feed does expose an exact `workplace` (`remote`/`hybrid`/`on_site`).
- **Multi-location jobs** are emitted as one row per location (matching how Workable lists them). Rows of the same job share the same `shortcode` (board mode) so you can group them.
- **Posted date in global-search mode**: if you disable `enrichApplyUrls`, `postedDate` stays `null` rather than publishing a wrong date (the feed's `created == updated`; the true publication date is only on the single-job endpoint).
- Some boards on a custom domain return a widget 404 even though they exist - those are skipped with a warning.

### Example Input And Output

#### Example Input

Boards mode (per-company careers boards):

```json
{
  "boards": ["vsf-rentals", "https://apply.workable.com/redbull/"],
  "maxItems": 500
}
```

Global-search mode (whole Workable job universe):

```json
{
  "boards": [],
  "query": "engineer",
  "workplace": "remote",
  "employmentType": "Full-time",
  "dayRange": 30,
  "maxItems": 100
}
```

#### Example Output

```json
{
  "jobId": "ABC123",
  "source": "board-widget",
  "title": "Senior Software Engineer",
  "companyName": "VSF Rentals",
  "boardSlug": "vsf-rentals",
  "boardUrl": "https://apply.workable.com/vsf-rentals/",
  "location": "London, United Kingdom",
  "locations": ["London, United Kingdom", "Remote"],
  "city": "London",
  "region": "England",
  "country": "United Kingdom",
  "remote": false,
  "workplace": "on_site",
  "department": "Engineering",
  "employmentType": "Full-time",
  "postedDate": "2026-09-28",
  "descriptionHtml": "<p>We are looking for...</p>",
  "applyUrl": "https://apply.workable.com/vsf-rentals/j/ABC123",
  "jobUrl": "https://jobs.workable.com/view/ABC123",
  "shortcode": "ABC123",
  "scrapedAt": "2026-10-10T12:00:00.000Z"
}
```

### Integrations & Automation

- **Apify API** - run via `POST https://api.apify.com/v2/acts/{actorId}/runs`, export via `GET /v2/datasets/{datasetId}/items?clean=true&format=json`
- **Schedules** - Apify Schedules for a daily/weekly hiring snapshot (recommended for recruitment analytics)
- **Webhooks** - run-finish events into downstream pipelines
- **Zapier / Make** - via the Apify integration (e.g. new job postings to Slack/Airtable)
- **Pay-per-event** - $0.90 per 1,000 job rows, no subscription, free 10-item preview, 256 MB memory

### Related Actors

- [linkedin-jobs-scraper](https://apify.com/curious_coder/linkedin-jobs-scraper): the largest job-board scraper on the Store; pairs Workable ATS data with LinkedIn reach.
- [indeed-scraper](https://apify.com/borderline/indeed-scraper): one of the most-used Indeed scrapers for aggregate job coverage.
- [Workable-Job-Scraper](https://apify.com/shahidirfan/Workable-Job-Scraper): a competing Workable job scraper, for comparison.
- [totaljobs-scraper](https://apify.com/ahmed_jasarevic/totaljobs-scraper): UK job board listings with salary and geo data for a broader British feed.
- [cv-library-co-uk-scraper](https://apify.com/ahmed_jasarevic/cv-library-co-uk-scraper): another major UK job board, same salary/geo schema style.

### FAQ

#### Does Workable have a public API?

Yes - and that is exactly what this actor uses. Workable's careers sites load their jobs from public JSON endpoints (`apply.workable.com/api/v1/widget/accounts/<slug>?details=true` per board, `jobs.workable.com/api/v1/jobs` for the global feed). No auth, no browser, no HTML parsing.

#### How do I scrape a Workable careers page without a browser?

Pass the board slug or URL in `boards` (e.g. `["vsf-rentals"]`) and run. Each board costs exactly 1 request, and you get every open job with title, location, department, employment type, full description HTML, posted date and apply URL.

#### What are the alternatives for ATS job data?

Store alternatives: shahidirfan/Workable-Job-Scraper (per-job pricing, same target) and wickfeed/ats-job-aggregator (job aggregation across ATS systems including Workable, Lever and Greenhouse). For broader UK coverage, this actor pairs with totaljobs-scraper and cv-library-co-uk-scraper.

#### Why is a hybrid job shown as on-site?

The board widget API only exposes a `telecommuting` boolean, so hybrid jobs are reported as `on_site` with `remote: false` in boards mode. Use global-search mode (`boards` empty) to get the exact `workplace` value (`remote`/`hybrid`/`on_site`) from the global feed.

#### How do I export Workable jobs to a database?

Run the actor and fetch the dataset as JSON/CSV via the Apify API: `GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json`. The `overview` view shows title, company, location, posted date and apply URL.

#### How much does it cost?

$0.90 per 1,000 job rows, pay-per-event, with a free 10-item preview per run. Memory is 256 MB; typical runs need no proxy.

### SEO Keywords

workable scraper, workable jobs api, workable ats scraper, scrape workable job board, ats job scraper, job board scraper, workable careers board, global job feed api, hiring data api, workable apply url, ats aggregation, remote jobs data api, workable alternative api, job posting data, talent sourcing data, careers page scraper, workable jobs export, recruitment analytics, workable board slug, greenhouse lever workable scraper

### For AI Agents & LLM Apps

- **Purpose**: returns one JSON row per open job from a Workable ATS board or the global Workable feed (title, company, location, department, workplace type, employment type, posted date, full description HTML, apply URL).
- **Minimal working input** (boards mode):

```json
{ "boards": ["vsf-rentals"], "maxItems": 10 }
```

- **Variant input** (global-search mode - only when `boards` is empty):

```json
{ "boards": [], "query": "engineer", "workplace": "remote", "maxItems": 10 }
```

- **Output field names**: `jobId, source, title, companyName, boardSlug, companyWebsite, companyUrl, boardUrl, location, locations, city, region, country, remote, workplace, department, employmentType, postedDate, updatedAt, descriptionHtml, applyUrl, jobUrl, shortcode, language, scrapedAt`.
- **Behaviors an agent should know**:
  - `boards` is the mode switch: non-empty = per-board mode (1 request per board, full data); empty = global-search mode over the whole `jobs.workable.com` feed.
  - In global-search mode `enrichApplyUrls` (default true) costs one extra request per company board and attaches the direct apply URL and exact `postedDate`. If disabled, `postedDate` is `null` for search rows - never published as a wrong date.
  - Cost-relevant default: `maxItems` defaults to 100 (hard cap 100,000; free tier 10). Billing is per dataset row, not per request - board mode is 1 request but `maxItems` rows.
  - Hybrid jobs in board mode come back as `on_site`/`remote: false` (widget API limitation); global mode returns the exact `workplace`.
  - Multi-location jobs produce multiple rows sharing one `shortcode` - deduplicate by `shortcode` + `jobId` if needed.
  - The feed's `limit` parameter is hard-capped at 20; pagination is by `nextPageToken`, handled internally.
- **Billing**: pay-per-event - $0.0009 per dataset row, $0.00005 per run start.

### Legal & Compliance Disclaimer

This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Workable Software Ltd or any company whose board is scraped. It accesses publicly available job postings via Workable's public JSON endpoints - no login, no authentication bypass, no CAPTCHA solving.

Users are responsible for their own compliance with Workable's terms of service and applicable data-protection law. Job-posting data is generally public by design, but treat any personal data (e.g. contact details in descriptions) lawfully and do not use it for unsolicited outreach.

# Actor input Schema

## `boards` (type: `array`):

One or more Workable careers boards to scrape. Accepts a bare slug (e.g. "vsf-rentals"), an apply.workable.com URL, a legacy <slug>.workable.com URL, or a jobs.workable.com company/job URL. When empty, the actor runs in global-search mode over the whole Workable job feed.

## `query` (type: `string`):

Keyword to filter jobs by (global-search mode only).

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

Location filter, e.g. "London" or "United States" (global-search mode only).

## `workplace` (type: `string`):

Filter by workplace type (global-search mode only).

## `employmentType` (type: `string`):

Filter by employment type (global-search mode only).

## `dayRange` (type: `integer`):

Only return jobs posted within the last N days (global-search mode only).

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

Maximum number of job rows to return. Free users are capped at 10.

## `maxBoards` (type: `integer`):

In global-search mode, how many distinct company boards may be looked up to attach apply URLs and exact posted dates (1 request per company).

## `enrichApplyUrls` (type: `boolean`):

In global-search mode, look up each company's board to attach the direct apply URL, exact posted date and shortcode. Adds one request per company.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "boards": [
    "super-soccer-stars"
  ],
  "workplace": "remote",
  "employmentType": "Full-time",
  "dayRange": 30,
  "maxItems": 100,
  "maxBoards": 50,
  "enrichApplyUrls": true,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "boards": [
        "super-soccer-stars"
    ],
    "query": "",
    "location": "",
    "workplace": "remote",
    "employmentType": "Full-time",
    "dayRange": 30,
    "maxItems": 100,
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/jobs-workable-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 = {
    "boards": ["super-soccer-stars"],
    "query": "",
    "location": "",
    "workplace": "remote",
    "employmentType": "Full-time",
    "dayRange": 30,
    "maxItems": 100,
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/jobs-workable-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 '{
  "boards": [
    "super-soccer-stars"
  ],
  "query": "",
  "location": "",
  "workplace": "remote",
  "employmentType": "Full-time",
  "dayRange": 30,
  "maxItems": 100,
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/jobs-workable-scraper --silent --output-dataset

```

## MCP server setup

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