# Workable Job Board Scraper — Company Hiring Signals (`foxlabs/workable-ats-scraper`) Actor

Search all ~170K Workable jobs by keyword, location, remote/hybrid and date — no company slugs needed. Every row has the hiring company's website, domain, logo and description, plus title, department, workplace, type, posted date, full description and apply URL.

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

## Pricing

$2.00 / 1,000 job posting delivereds

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 Job Board Scraper — Company Hiring Signals 🚀

**foXLabs hiring series:** [Greenhouse](https://apify.com/foxlabs/greenhouse-job-board-scraper) · [Lever](https://apify.com/foxlabs/lever-job-board-scraper) · [Ashby](https://apify.com/foxlabs/ashby-job-board-scraper) · [Workday](https://apify.com/foxlabs/workday-job-board-scraper) · [SmartRecruiters](https://apify.com/foxlabs/smartrecruiters-job-board-scraper) · [Personio](https://apify.com/foxlabs/personio-job-board-scraper) · [Teamtailor](https://apify.com/foxlabs/teamtailor-job-board-scraper) · [BambooHR](https://apify.com/foxlabs/bamboohr-ats-scraper) · **[All platforms in one search →](https://apify.com/foxlabs/job-postings-database)**

🎉 Search every job posted on Workable (~170,000 open roles) by keyword, location, workplace and date — and get the **hiring company's website, logo and description** on every row. No login, no API key, no company slugs to look up.
Built for sales & competitive-intelligence teams scoring hiring intent, recruiters sourcing roles, and job-data pipelines.

### 🔍 What is the Workable Job Board Scraper — and when should you use it?

Workable powers the careers pages of tens of thousands of small and mid-market companies. Type a keyword (`account executive`, `nurse`, `software engineer`) and this actor searches all of them at once, with the same filters as Workable's own job search: location, remote/hybrid/on-site, employment type and posting date. Every row is one open role — title, department, location, workplace, employment type, posted date, full description, requirements, benefits, apply link — **plus the company behind it**: name, website, domain, logo and description.

Already know your target companies? Add their Workable board (`acme` or `apply.workable.com/acme`) and get every open role on it.

**Use it when you need:** a list of companies hiring for a function right now (with their domains, ready for enrichment or outreach); a daily feed of new roles for a keyword; every open role at a target company; or a read on a competitor's hiring plans.

**Use something else when:** the companies you care about don't run on Workable. Point the matching actor at their ATS instead — [Greenhouse](https://apify.com/foxlabs/greenhouse-job-board-scraper), [Lever](https://apify.com/foxlabs/lever-job-board-scraper), [Ashby](https://apify.com/foxlabs/ashby-job-board-scraper), [Workday](https://apify.com/foxlabs/workday-job-board-scraper), [SmartRecruiters](https://apify.com/foxlabs/smartrecruiters-job-board-scraper), [Personio](https://apify.com/foxlabs/personio-job-board-scraper), [Teamtailor](https://apify.com/foxlabs/teamtailor-job-board-scraper) or [BambooHR](https://apify.com/foxlabs/bamboohr-ats-scraper). Every one emits the **same core schema**, so their outputs concatenate into one hiring-intent table.

**Need one search across the other platforms?** [Job Postings Database](https://apify.com/foxlabs/job-postings-database) keeps a daily-refreshed index of 440,000+ open roles from ~33,000 Greenhouse, Lever, Ashby, SmartRecruiters, BambooHR, Personio and Teamtailor boards and answers a single query across all of them in seconds — every delivered role is re-checked live on its own board before it reaches you. Workable boards are not in that index yet, so this Actor stays the way to read them.

### 🤖 Use with AI agents

**Already on the Apify MCP server?** Ask for this Actor by name: `foxlabs/workable-ats-scraper`.

**Your agent can pay for its own runs.** This Actor is pay-per-event with agentic payments, so an agent can discover it, run it and settle the bill over **x402 (USDC on Base)** or **Skyfire** — no Apify account or API token of its own. Billing is the same either way: per delivered role, never for errors.

Otherwise paste this into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```
I want to find open jobs on Workable using the Apify Actor `foxlabs/workable-ats-scraper`.

Input: `searchQueries` is a list of job keywords (e.g. "account executive"; "*" = every job).
Optional filters: `location` ("London", "Germany"), `workplace` ("remote" | "hybrid" | "on_site"),
`employmentType` ("full_time" | "part_time" | "contract" | "temporary" | "other"),
`postedWithinDays` ("1" | "7" | "30"), `titleMustMatch` (true keeps only titles containing every keyword).
`maxResultsPerQuery` caps jobs per keyword (default 200).
Each row has jobTitle, department, location, workplace, employmentType, postedAt, description,
applyUrl and the company's companyName, companyWebsite, companyDomain and companyDescription.

Start with:
{ "searchQueries": ["account executive"], "location": "United Kingdom", "postedWithinDays": "7", "maxResultsPerQuery": 50 }

Ask me which roles and region I care about, run the Actor, then summarise the hiring companies as a table.
```

Things you can ask your agent for:

- "Which companies in Germany opened remote sales roles this week? Give me their domains."
- "Every new nursing job on Workable in the last 24 hours, as a table."
- "Pull every role on this Workable board and group them by department."

The machine-readable API, MCP config and OpenAPI definition live at `apify.com/foxlabs/workable-ats-scraper.md`.

### 📋 Overview

Everything you need to turn Workable's job market into clean, structured hiring data — roles, companies and hiring signals — in one actor, with no login, cookies or API key.

**Why teams pick this actor:**

- 🔎 **No slugs needed** — search all of Workable by keyword; the companies come to you.
- 🏢 **Company data on every row** — website, domain, logo and description of the hiring company, ready for enrichment, CRM import or outreach.
- 🎛️ **Workable's own filters** — location, remote/hybrid/on-site, employment type, last 24 h / 7 / 30 days.
- 🎯 **Strict title option** — keep only titles that contain your keywords; dropped jobs are never charged.
- 🔗 **Same schema across the series** — join Workable output with the other ATS actors on `companyName` / `companyBoard`.
- 💰 **Pay only for results** — per-role pricing; a job found by two keywords is charged once; empty searches and failed lookups are never billed.
- 🤖 **Agent-ready** — MCP + x402 agentic payments.

### ✨ Features

- 🔍 **Keyword search across all of Workable** — paged through to as many results as you ask for (up to 10,000 per keyword).
- 🏢 **Hiring-company block** — `companyName`, `companyWebsite`, `companyDomain`, `companyLogo`, `companyDescription`, `companyJobsUrl`.
- 📄 **Full role details** — title, department, location, workplace, remote flag, employment type, language, posted/updated dates, description, requirements and benefits (HTML stripped), apply URL.
- 📋 **Company boards** — every open role on a board by account slug or URL, with seniority, industry and job function.
- 🧹 **Deduplicated** — overlapping keywords never deliver or bill the same job twice.
- 📦 **Clean export** — stable camelCase rows, ready for CSV/Excel/JSON.

### 🎬 Quick Start

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~workable-ats-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchQueries": ["account executive"], "location": "United Kingdom", "postedWithinDays": "7", "maxResultsPerQuery": 50}'
```

### 🚀 Getting Started (3 steps)

1. **Type your keywords** — one per line (`software engineer`, `nurse`), or `*` for every job.
2. **Narrow it down (optional)** — location, workplace, employment type, posting date; turn on *Job title must contain every keyword* for exact matches.
3. **Run and export** — get a clean dataset as JSON, CSV or Excel.

### 📥 Input

```json
{
  "searchQueries": ["account executive", "sales development representative"],
  "location": "United Kingdom",
  "workplace": "any",
  "employmentType": "full_time",
  "postedWithinDays": "7",
  "titleMustMatch": true,
  "queries": ["careers"],
  "maxResultsPerQuery": 200
}
```

| Field | Type | Description |
|---|---|---|
| `searchQueries` | array | Job keywords, one per line, searched across all of Workable. `*` = every job matching the filters. |
| `titleMustMatch` | boolean | Keep only jobs whose title contains every keyword (`engineer` also matches `engineering`). Default off — Workable's own search is looser. |
| `location` | string | City, region or country for the search, e.g. `London`, `Germany`, `Texas`. Empty = worldwide. |
| `workplace` | string | `any`, `remote`, `hybrid` or `on_site`. |
| `employmentType` | string | `any`, `full_time`, `part_time`, `contract`, `temporary` or `other` (type not set by the employer). |
| `postedWithinDays` | string | `any`, `1`, `7` or `30`. |
| `queries` | array | Optional company boards: account slugs (`acme`) or board URLs. Search filters do not apply to boards. |
| `maxResultsPerQuery` | integer | Caps jobs per keyword or board (default 200, up to 10,000). |
| `maxConcurrency` | integer | How many keywords/boards to run at once (default 5). |
| `includeRaw` | boolean | Attach the source's untouched record under `raw`. |
| `requestDelayMs` | integer | Politeness delay between requests. |
| `proxyConfiguration` | object | Apify Proxy (datacenter) by default — Workable's job search limits how many pages one IP may fetch, so large searches rotate IPs. |

### 📤 Output

One row per open role, saved to the dataset.

| Field | Type | Description |
|---|---|---|
| `companyName` | string | Hiring company |
| `companyBoard` | string | Workable company id (search) or account slug (boards) — the join key across runs |
| `companyWebsite` / `companyDomain` | string | Company website and its bare domain (search) |
| `companyLogo` | string | Company logo URL (search) |
| `companyDescription` | string | Company profile text, HTML stripped |
| `companyJobsUrl` | string | The company's Workable jobs page |
| `jobId` | string | Workable job id |
| `jobTitle` | string | Role title |
| `department` / `team` | string | Department; job function (boards) |
| `location` | string | Location as posted |
| `city` / `countryName` | string | Parsed location parts |
| `workplace` | string | `remote`, `hybrid` or `on_site` (search); `remote` when a board role is telecommuting |
| `isRemote` | boolean | True when the role is remote or reads as remote |
| `employmentType` | string | Full-time, part-time, contract… |
| `seniority` / `industry` | string | Experience level and industry as posted (boards) |
| `language` | string | Posting language (search) |
| `postedAt` / `updatedAt` | string | Posted / updated date (ISO) |
| `description` | string | Full role description, HTML stripped |
| `requirements` / `benefits` | string | Requirements and benefits sections, when the employer wrote them (search) |
| `applyUrl` / `sourceUrl` | string | Apply link / public posting URL |

Every row also carries `query`, `scrapedAt`, and — when a search finds nothing or a board lookup fails — an `error` explaining why.

```json
{
  "source": "Workable",
  "query": "account executive",
  "companyName": "DC Thomson",
  "companyBoard": "5ebbcad8-9803-4941-84e5-2eaeb09ae071",
  "companyWebsite": "http://www.dcthomson.co.uk",
  "companyDomain": "dcthomson.co.uk",
  "companyLogo": "https://workablehr.s3.amazonaws.com/uploads/account/logo/303322/logo",
  "companyDescription": "DC Thomson is one of the leading media organisations in the …",
  "jobTitle": "Account Executive",
  "department": "Commercial",
  "location": "Perth, Scotland, United Kingdom",
  "city": "Perth",
  "countryName": "United Kingdom",
  "workplace": "hybrid",
  "isRemote": false,
  "employmentType": "Full-time",
  "language": "en",
  "postedAt": "2026-10-13",
  "requirements": "Skills: • Applies structured sales m…",
  "applyUrl": "https://jobs.workable.com/view/2Bpz8ssgzDzrWcXJw6iqgi/hybrid-account-executive-in-perth-at-dc-thomson"
}
```

### 💼 Use cases

**1. Hiring-intent lead lists** — a company that just opened five sales roles is buying sales tooling.
*Input:* `searchQueries: ["account executive", "sales development"]`, `postedWithinDays: "7"`, scheduled weekly. *Output:* hiring companies with domains. *Use:* push the domains to your enrichment/CRM and reach out while the need is fresh.

**2. Daily new-job feed** — every new role for your keywords, once.
*Input:* your keywords, `postedWithinDays: "1"`, scheduled daily. *Output:* that day's new postings. *Use:* job boards, alerts, market dashboards.

**3. Competitor headcount tracking** — watch which functions a peer grows and which freeze.
*Input:* the competitor's board in `queries`, run weekly. *Output:* the full role list over time. *Use:* spot expansion and hiring freezes early.

**4. Recruiter sourcing** — every open role for a skill in a region, with apply links.
*Input:* `searchQueries: ["react developer"]`, `location: "Poland"`, `workplace: "remote"`. *Output:* one table of roles + companies. *Use:* build a sourcing pipeline in minutes.

### 🔗 Integration

**JavaScript / Node.js**

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('foxlabs/workable-ats-scraper').call({
  searchQueries: ['account executive'], location: 'United Kingdom', postedWithinDays: '7', maxResultsPerQuery: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('foxlabs/workable-ats-scraper').call(
    run_input={'searchQueries': ['account executive'], 'location': 'United Kingdom', 'postedWithinDays': '7', 'maxResultsPerQuery': 50}
)
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)
```

Written for `apify-client` 3 for Python, where `call()` returns a run object; with version 1 or 2 it returns a dict — write `run['defaultDatasetId']` there.

**Automation (n8n / Zapier / Make):** schedule or webhook → HTTP request to the actor API with your `searchQueries` → handle the JSON dataset → push to a sheet, CRM or dashboard.

### 📊 Pricing

Pay-per-event: **$0.002 per delivered role**. A job found by two of your keywords is charged once; empty searches and failed lookups are never billed; with *Job title must contain every keyword* on, the jobs it drops are never billed either. [View current pricing.](https://apify.com/foxlabs/workable-ats-scraper)

### ❓ FAQ

**Do I need a Workable account, login or API key?** No. This reads Workable's public job search and public board API — the same endpoints Workable's job site and the companies' careers pages call.

**Do I need to know company slugs?** No. Search by keyword; every row tells you the company, its website and its domain. Slugs are only for when you want one specific company's full board.

**How many jobs can I get?** Up to 10,000 per keyword, as many keywords as you like. Workable lists ~170,000 open jobs in total.

**Why do some roles appear several times with different cities?** When an employer opens the same role in several locations, Workable publishes one posting per location, each with its own job id. They are separate postings at the source.

**Why does `software engineer` return sales jobs?** Workable's search ranks loosely and also returns related roles (e.g. account executives at software companies). Turn on *Job title must contain every keyword* to keep only matching titles; dropped jobs are not charged.

**How current is the data?** Every run queries Workable live, so results are as fresh as the postings themselves.

**Can I export to CSV / Excel / JSON?** Yes — directly from the Apify dataset.

**What happens when a search finds nothing or a slug is wrong?** You get a row carrying your `query` and an `error` — nothing is silently dropped, and you're not charged.

### 🐛 Troubleshooting

- **Fewer rows than expected** — the filters may be narrow (check the same search on jobs.workable.com), or `maxResultsPerQuery` is capping them.
- **"Workable has no public board named …"** — take the slug from the careers URL (the part after `apply.workable.com/`), not the company's domain.
- **`companyWebsite` is empty on board rows** — the board API does not publish it; use the keyword search to get websites.

### ⚠️ Trademark

Independent, third-party tool. Not affiliated with, endorsed by or connected to Workable Technology Limited. "Workable" and related marks belong to their owners and are used here for identification only.

### ⚖️ Is it legal to scrape this data?

This actor reads only publicly published job-posting and company-profile data — no private or personal user data. Your results can still contain personal data (e.g. a recruiter name in a description); personal data is protected by the GDPR and similar laws, so only process it with a legitimate basis. See Apify's blog post on the legality of web scraping.

### 🤝 Support & contact

- 🌐 **Website:** [data.foxlabs.com.tr](https://data.foxlabs.com.tr)
- 📧 **Email:** info@foxlabs.com.tr
- 🐛 **Issues:** open a ticket in the Actor's **Issues** tab
- 🧰 **More clean B2B data actors:** [Fox Labs on Apify](https://apify.com/foxlabs)

### Changelog

#### 0.2.0 — 2026-10-14

- **New: keyword search across all of Workable** (`searchQueries`) — no company slug needed. Filters: `location`, `workplace`, `employmentType`, `postedWithinDays`, plus `titleMustMatch` for strict title matching. Up to 10,000 jobs per keyword.
- **New company fields** on search rows: `companyWebsite`, `companyDomain`, `companyLogo`, `companyDescription`, `companyJobsUrl`; new role fields `workplace`, `language`, `requirements`, `benefits`. Board rows now carry `companyDescription` and `companyJobsUrl`.
- A job found by several keywords is delivered and charged once.
- `queries` keeps working exactly as before for company boards; it is now optional.
- Fix: every row now has the same set of keys (`industry` used to appear only on some rows).

#### 0.1.0 — 2026-10-11

- Initial release: full open-roles extraction from any Workable board by slug or URL, with department, function, parsed location, seniority, employment type, HTML-stripped description and apply URL. Shares the hiring-signal core and schema (`companyBoard` join key) with the Greenhouse/Lever/Ashby/… series.

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/workable-ats-scraper/changelog.md

# Actor input Schema

## `searchQueries` (type: `array`):

Search every published Workable job (~170,000 across all Workable customers) — no company slug needed. One keyword or phrase per line, e.g. `software engineer`, `account executive`, `nurse`. Use `*` for every job that matches the filters below. Each line is its own search; a job found by two lines is delivered and charged once.

## `titleMustMatch` (type: `boolean`):

Workable's search is loose: `software engineer` also returns account executives at software companies. Turn this on to keep only jobs whose title contains every word of the search line (`engineer` also matches `engineering`). Dropped jobs are never delivered or charged.

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

City, region or country for the keyword search, e.g. `London`, `Germany`, `Texas`. Leave empty for worldwide.

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

Keep only remote, hybrid or on-site jobs (keyword search).

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

Keep only one employment type (keyword search). "Other" covers jobs whose employer did not set a type.

## `postedWithinDays` (type: `string`):

Keep only jobs posted recently (keyword search). Use `Last 24 hours` on a daily schedule to get each day's new jobs.

## `queries` (type: `array`):

Already know the companies? Add Workable account slugs (`acme`) or board URLs (`https://apply.workable.com/acme`) to get every open role on those boards. The slug is the path segment after apply.workable.com, or the subdomain of an `acme.workable.com` URL. Search filters do not apply to boards.

## `maxResultsPerQuery` (type: `integer`):

How many jobs one search line or one company board may return. Searches page through results 20 at a time until this is reached.

## `maxConcurrency` (type: `integer`):

How many searches/boards to run at the same time. Lower it if the source throttles you.

## `includeRaw` (type: `boolean`):

Attach the source's untouched response under `raw`. Useful when you need a field this actor does not map.

## `requestDelayMs` (type: `integer`):

Politeness delay against a public source. Raise it for large runs.

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

Workable's job search limits how many pages one IP may fetch, so searches rotate through Apify Proxy (datacenter) by default. Turn it off only for small runs.

## Actor input object example

```json
{
  "searchQueries": [
    "software engineer"
  ],
  "titleMustMatch": false,
  "workplace": "any",
  "employmentType": "any",
  "postedWithinDays": "any",
  "maxResultsPerQuery": 200,
  "maxConcurrency": 5,
  "includeRaw": false,
  "requestDelayMs": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "searchQueries": [
        "software engineer"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/workable-ats-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 = {
    "searchQueries": ["software engineer"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/workable-ats-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 '{
  "searchQueries": [
    "software engineer"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call foxlabs/workable-ats-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,foxlabs/workable-ats-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/9ptcSQf3tl9RJlTYp/builds/wvtuZ7ugtYYEYWYCP/openapi.json
