Workable Jobs Scraper - apply.workable.com Careers, No API Key avatar

Workable Jobs Scraper - apply.workable.com Careers, No API Key

Pricing

from $0.60 / 1,000 results

Go to Apify Store
Workable Jobs Scraper - apply.workable.com Careers, No API Key

Workable Jobs Scraper - apply.workable.com Careers, No API Key

Scrape published job postings from any apply.workable.com careers page: title, department, location, remote flag, dates, links, optional full description. New-postings-only mode. No API key.

Pricing

from $0.60 / 1,000 results

Rating

0.0

(0)

Developer

Brandt May

Brandt May

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Workable Jobs Scraper

Scrape published job postings from any Workable careers page (apply.workable.com/<slug>) and get them back as flat CSV, JSON or Excel rows. Give it an account slug (blueground) or the careers-page URL (https://apply.workable.com/blueground/) and this Workable scraper returns every posting the employer has published there: job title, department, employment type, city / region / country, the employer's remote flag, published date, posting and apply links, and - when you ask for it - the full job description converted from Workable's HTML into clean plain text.

Built for recruiters, sourcers, job-board operators and anyone tracking hiring at a list of companies. It reads the public JSON endpoint behind Workable's embeddable jobs widget, so there is no API key, no login and no Workable account involved. Pass one company or a few dozen.

This Actor covers Workable careers pages only. It does not read jobs.workable.com (Workable's cross-company job search, which its robots.txt disallows), and a company that does not host its careers page on Workable cannot be scraped here.

What you get

One row per published job posting. Fill rates below were measured on 678 rows across three real runs on 2026-09-25; a blank means the employer left that field empty in Workable.

FieldWhat it isFilled
companyCompany name as Workable publishes it (for example Skroutz S.A). Falls back to the slug if the account has no name.100%
slugThe Workable account the row came from, so multi-company runs stay separable.100%
jobIdWorkable's shortcode for the posting (for example 186545F8C1) - the id in the posting URL. Stable; use it to dedupe across runs.100%
requisitionCodeThe employer's own requisition code, if they filled one in.54%
titleJob title.100%
departmentDepartment the employer filed the role under.98%
employmentTypeFull-time, Part-time, Contract and so on, as set by the employer.76%
functionJob function the employer picked from Workable's list (for example Engineering).50%
industryIndustry the employer picked (for example Computer Software).96%
experienceLevelEntry level, Associate, Mid-Senior level... as set by the employer. Workable's literal Unspecified is returned as blank.57%
educationLevelBachelor's Degree, Master's Degree, Vocational... as set by the employer. Unspecified is returned as blank.44%
city, region, countryThe posting's location as three separate fields. country was filled on every row measured; city and region are blank on postings the employer published as country-only (often remote roles).83% / 83% / 100%
countryCodeISO 3166-1 alpha-2 code for the country (GR, CY, GB).100%
locationThe three location parts joined, for example Athens, Attica, Greece.100%
remotetrue/false: the employer's own remote ("telecommuting") flag in Workable.100%
workplaceTypeRemote when remote is true, otherwise blank. Workable's widget exposes no hybrid or on-site flag, so this Actor does not invent one - see the limits section.42% (by design)
publishedAtDate the posting was published, as a calendar date (2026-09-14). Workable publishes a date only, not a time, so none is invented. Rows are sorted newest-published first across all companies.100%
createdAtDate the posting was created in Workable, same format.100%
urlPublic link to the posting (https://apply.workable.com/j/<jobId>).100%
applyUrlLink straight to the application form.100%
descriptionTextThe whole job description as clean plain text: tags removed, entities decoded, list items kept as - bullets, capped at 20,000 characters. Only when includeDetails is on; blank otherwise.100% with includeDetails
scrapedAtISO 8601 UTC timestamp of the run.100%

A SUMMARY record is written to the run's key-value store with a board-health report for every company requested (ok with jobs, empty, not-found, rate-limited, error, not-reached, each with the company name and how many postings were published and saved), which companies failed and why, the total postings published, and department and country breakdowns (top 25 of each with counts).

Input

FieldTypeDefaultWhat it does
companiesstring listemptyAccount slugs or careers-page URLs, one per company. Accepts blueground, https://apply.workable.com/blueground/, https://apply.workable.com/blueground/j/186545F8C1/ and https://blueground.workable.com/. A bare job link (https://apply.workable.com/j/<code>) has no account in it and is skipped with a warning.
presetselectverified-sampleUsed only when companies is empty. verified-sample is 18 Workable accounts that each published at least 3 jobs when checked on 2026-09-25 (Blueground, Skroutz, Epignosis, Novibet, Viva.com, Spotawheel, Welcome Pickups, Printec, Orfium, European Dynamics, Grecotel, payabl., Costa Navarino, Uni Systems, Eightcap, EXUS, Hellas Direct, Stoiximan). none means only the companies you list; if that list is also empty the sample is used anyway so the run returns something.
includeDetailsbooleanfalseFetch with details=true and keep descriptionText. Every other field is unaffected.
titleContainsstringemptyKeep only postings whose title contains this text (case-insensitive, partial).
remoteOnlybooleanfalseKeep only postings the employer flagged as remote.
maxResultsPerCompanyinteger100Row cap per company, newest-published first.
maxResultsinteger300Row cap for the whole run, applied after sorting newest-published first across companies.
onlyNewSinceLastRunbooleanfalseSave only postings this Actor has not seen before. See the FAQ for exactly how the first run behaves.
maxRunSecondsinteger240Wall-clock budget. When it is reached the run stops cleanly, keeps everything already collected, and names the companies it did not reach.

Example output

A real row from a run with includeDetails on (description truncated here for readability):

{
"company": "EUROPEAN DYNAMICS",
"slug": "european-dynamics",
"jobId": "47DDC6EF15",
"requisitionCode": "DSE/09/26",
"title": "DevSecOps Engineer",
"department": "PRB",
"employmentType": null,
"function": null,
"industry": "Computer Software",
"experienceLevel": null,
"educationLevel": null,
"city": "Athens",
"region": "Attica",
"country": "Greece",
"countryCode": "GR",
"location": "Athens, Attica, Greece",
"remote": true,
"workplaceType": "Remote",
"publishedAt": "2026-09-14",
"createdAt": "2026-09-14",
"url": "https://apply.workable.com/j/47DDC6EF15",
"applyUrl": "https://apply.workable.com/j/47DDC6EF15/apply",
"descriptionText": "We are looking for a DevSecOps Engineer to help us build, automate, secure, and operate reliable software delivery platforms ...",
"scrapedAt": "2026-09-25T17:34:59.865Z"
}

FAQ

Where do I find a company's slug? Open the company's careers page. If it is hosted on Workable the address looks like https://apply.workable.com/<slug>/ - the slug is that path segment (blueground, european-dynamics, uni-systems). You can paste the whole URL, or a link to one of its job postings, into companies and the Actor extracts the slug. A slug with no careers page returns HTTP 404 and is reported for that company only; the rest of the run continues. The slug workable is not an account (Workable's own openings are at careers).

The company exists but I got no rows. That is a real answer, not a failure: plenty of Workable accounts resolve but currently publish zero jobs (in the accounts checked while building this Actor, more than half were in that state). The run finishes successfully, logs a warning, and the company shows up in SUMMARY.boardHealth as empty. Check the page in a browser at https://apply.workable.com/<slug>/ if you expected postings.

What exactly does "only postings new since the last run" do? With the option on, the Actor records the jobId of every published posting on each careers page it successfully fetched, in a named key-value store called workable-jobs-scraper-state. On the first run for a company there is no baseline to compare against, so you get every posting and the baseline is written - the log says so. From the second run on you get only ids that were not there before. A run with nothing new finishes successfully with an empty dataset and a warning - that is the expected result, not a failure. The baseline is only written on runs where the option is on, and it records every published posting, including any the caps kept out of the dataset. The store is shared by every run of this Actor on your account, so two schedules watching the same company will each consume the other's new postings; different company lists are safe, the baseline is kept per slug.

Is the description really plain text? Yes. Workable returns descriptions as HTML. This Actor strips the tags, decodes the entities and keeps list items as - bullets. On the 335-row run with includeDetails on that produced the example above, 0 rows contained leftover HTML tags or entities; descriptions averaged about 4,700 characters.

Why is there no hybrid / on-site value, and no salary? Because the widget endpoint does not publish them. The only workplace signal it carries is the employer's boolean remote flag, so remote is that flag and workplaceType is Remote or blank - nothing is inferred from the text. There is no structured salary either; pay ranges appear inside descriptionText when the employer wrote them into the posting. No made-up columns.

How fast is it? Workable returns an entire careers page in a single request, with no pagination. Measured locally on 2026-09-25, end to end including writing the rows: the default run (18 companies, 584 postings published, 300 saved) took about 8 seconds; four companies with 43 postings took under 3 seconds; five companies with 335 postings and full descriptions took under 5 seconds. Platform runs add the time to write results over Apify Storage. After the first 25 companies in a run the Actor deliberately slows to one request every 2.5 seconds - see the limits section for why.

Data source, access and limits

  • Source: the JSON endpoint behind Workable's embeddable jobs widget, https://apply.workable.com/api/v1/widget/accounts/{slug}?details=false|true. It is public but undocumented - it needs no key, login, account or cookies, but Workable does not describe it in its developer documentation, so its shape could change without notice. Only postings the employer has published on their careers page are returned.
  • Crawling is allowed; training is not. https://apply.workable.com/robots.txt (read 2026-09-25) is User-agent: * / Disallow: (nothing disallowed) with Content-Signal: search=yes, ai-input=yes, ai-train=no. So: use the data for recruiting, job aggregation, market research and monitoring; do not use it to train AI models. jobs.workable.com, Workable's cross-company search, is disallowed to crawlers and this Actor never touches it.
  • Rate limit. Workable's edge (Cloudflare) rate-limits this endpoint, and it is keyed to how many different pages one client asks for, not to raw request count: on 2026-09-25, 150 requests for the same careers page in five seconds went through untouched, while 50 requests for 50 different (unknown) slugs in two seconds got HTTP 429 (an HTML error page). The first three blocks that day carried retry-after: 0 and cleared within twenty seconds to five minutes. After a fourth burst inside the same hour the 429 came back with retry-after: 85836 (about 24 hours); over the following half hour that block was enforced inconsistently - some requests from the same client went through while others were refused with the same expiry - so treat a long retry-after as real. A run is one request per company, so a list of a few dozen companies is fine (30 companies in one run did not trip it); past 25 the Actor paces itself to one request every 2.5 seconds. A 429 with no retry-after is retried four times over 45 seconds; a short retry-after (up to 45 seconds) is waited out once and the request tried once more; a longer retry-after is treated as the block it is - the Actor does not retry it. Either way the run stops there, keeps what it has, writes the board-health report, and lists the companies it did not reach in SUMMARY.boardHealth as not-reached (the refused one as rate-limited, with retryAfterSec) so you can re-run just those later. Spreading scheduled runs apart helps, and so does not passing long lists of guessed slugs - unknown slugs count too. Apify runs share outbound IPs with other users, so a block caused by someone else's traffic is possible; it shows up as rate-limited in the board-health report, never as "no jobs".
  • remote is the employer's flag, not an inference. A role that is remote only in its description text reads false.
  • Everything else is passed through as published. Titles, departments, functions, industries, levels, locations and dates come from the employer's own Workable data, including its gaps - the fill rates above are what employers actually fill in.
  • No personal data is extracted. Every row describes a job posting, not a person: there is no recruiter name, email or phone field, and none is inferred. descriptionText is the employer's own published description reproduced as text. Nothing is collected from candidates or applications.
  • Failures are explicit. Companies that 404 or error are named in the log and in SUMMARY.failedSources, and the run still saves everything from the companies that worked. If every company that was fetched fails, the run fails with a message naming the likely cause instead of returning an empty dataset that looks like "no jobs". The SUMMARY record, with the board-health report, is written before the run fails, so you can still see which companies were refused and which were never reached.
  • Billing: this Actor is billed per result on Apify - the current rate is on the Pricing tab of this Actor's page. There is nothing else to buy; the data source itself needs no key.
  • Not affiliated with Workable. Workable is a trademark of Workable Software Limited; this Actor is an independent tool that reads publicly available careers-page data.