Remote Jobs Scraper - Employer-Direct, No Job-Board Reposts avatar

Remote Jobs Scraper - Employer-Direct, No Job-Board Reposts

Pricing

from $0.60 / 1,000 results

Go to Apify Store
Remote Jobs Scraper - Employer-Direct, No Job-Board Reposts

Remote Jobs Scraper - Employer-Direct, No Job-Board Reposts

Remote postings read straight from employer boards on Greenhouse, Lever, Ashby, Recruitee and Workable, not job-board reposts. Remote is location-inferred on Greenhouse. New-since-last-run diff.

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

7 hours ago

Last modified

Share

Remote Jobs Scraper - Employer-Direct (Greenhouse, Lever, Ashby, Recruitee, Workable)

Scrape remote job postings straight from employers' own career boards and get them back as flat CSV, JSON or Excel rows, newest first. Nothing here comes from a job board or an aggregator: every row is a posting the employer currently publishes on its own Greenhouse, Lever, Ashby, Recruitee or Workable board, read through those platforms' public job-board APIs. No API key, no login, no account on any platform.

Two things set this remote jobs scraper apart from a generic ATS scraper:

  • An honest remote flag. Every row says why it counts as remote (remoteBasis). On Ashby, Lever, Recruitee and Workable the platform publishes a remote marker per posting and the Actor uses it; on Ashby, Lever and Recruitee a posting the platform marks hybrid or on-site is dropped even when its location line says "Remote" (strictRemote, on by default). Greenhouse publishes no workplace field at all, so on Greenhouse remote is always inferred from the location text ("Remote, United States", "Home based - Worldwide") - the title of this Actor says so because it matters. The same inference is the fallback on the other platforms whenever the employer left the marker blank.
  • A built-in, verified list of 70 majority-remote employer boards (preset: remote-first), plus a new since last run mode for a daily digest and a per-run board-health report naming boards that resolved but published nothing.

Built for remote job seekers, remote-work job boards that want employer-direct listings, recruiters sourcing remote talent, and anyone tracking remote hiring at a list of companies.

What you get

One row per remote job posting. Rows from every company are merged and sorted newest first.

FieldWhat it isFilled on the default run (800 rows, three runs on 2026-09-25)
atsPlatform the board runs on: greenhouse, lever, ashby, recruitee or workable.100%
companyThe slug you passed (or the preset's slug), for example gitlab. Stable; use it to group.100%
companyNameDisplay name as the platform publishes it (GitLab). Greenhouse, Recruitee and Workable send one; Lever and Ashby do not, so their rows have null here.64%
titleJob title.100%
departmentDepartment the employer filed the role under.99.8%
teamTeam (Lever, Ashby), function (Workable) or first office (Greenhouse - it has no team field). Recruitee has none.94.9%
locationThe location line the employer published, for example Remote, Canada; Remote, United States.100%
remoteAlways true - only remote postings are saved. Kept for schema compatibility with our ATS Job Postings Scraper.100%
remoteBasisWhy the row is remote: workplaceType (the platform marked it remote) or location-text (inferred from the location line - the only signal on Greenhouse). On the default run: 984 / 1,526 of the 2,510 postings kept before the total cap.100%
workplaceTyperemote, hybrid or onsite as the platform publishes it. null when the platform has no such field (every Greenhouse row), when the employer left it blank (many Ashby rows), or on a Workable row without the telecommuting flag.34.8%
employmentTypeCommitment as published, unnormalized: FullTime, Full-time, Contract, ... Greenhouse has no such field.33.9%
postedAtISO 8601 UTC timestamp of publication (Greenhouse: first published, falling back to last updated).100%
salaryMin, salaryMax, salaryCurrency, salaryPeriodStructured pay range when the platform returns one (Lever salaryRange, Ashby compensation, Recruitee salary). Greenhouse and Workable never do; pay ranges those employers write into the description text are not parsed. salaryPeriod is year, month, week, day or hour.12%
urlPublic link to the posting.100%
jobIdThe platform's job ID, as a string. Stable - use it to dedupe across runs.100%
descriptionOnly when includeDescription is on: the full posting as clean plain text (HTML unescaped and stripped, bullets kept as - , capped at 20,000 characters).-
scrapedAtISO 8601 UTC timestamp of the run.100%

A SUMMARY record is written to the run's key-value store with: companies requested / attempted / resolved and which platform each resolved on; failedSources (boards that errored) and notFound (slugs with no board anywhere); boardHealth - boards that resolved but publish 0 postings, and boards with open postings but none remote; open and remote postings seen per board; the remoteBasis breakdown; how many rows the maxResults cap cut; and whether the run stopped early on its time budget.

The remote rule, platform by platform

PlatformWhat the platform publishesHow a posting becomes remoteremoteBasis
AshbyworkplaceType Remote / Hybrid / OnSite - often blank (Supabase on 2026-09-25: 24 of 55 postings blank, location "Remote, Global")Remote -> remote. Hybrid / OnSite -> dropped when strictRemote is on. Blank -> location text decides.workplaceType or location-text
LeverworkplaceType remote / hybrid / onsite / unspecifiedSame as Ashby; unspecified counts as blank.workplaceType or location-text
Recruiteeremote, hybrid, on_site flagsSame as Ashby.workplaceType or location-text
Workabletelecommuting true / false only - nothing separates hybrid from on-siteFlag set -> remote (workplaceType = remote). Not set -> location text decides. On the two Workable boards checked when the rule was built (zyte, remotebase - 22 remote postings), every remote posting carried the flag and none had remote in its city or country line, so the flag is the working signal there.workplaceType or location-text
GreenhouseNothing. No workplace field of any kind.Location text decides, always.location-text

"Location text decides" means the posting's location line(s) contain one of: remote, remotely, distributed, home based, work from home, WFH, anywhere, worldwide, virtual, telecommute. Every one of those words was seen on a live board when the list was built. Job titles are never used as location text. A country name on its own ("United States", "Spain") is not remote - which is why Elastic (382 open roles, all published as country names) is not in the preset even though the company is distributed. Ashby's isRemote flag is never used: it is true on hybrid postings too (checked 2026-09-25 on the OpenAI, Sentry and Alchemy boards: all 572 postings marked Hybrid had isRemote true).

Input

FieldTypeDefaultWhat it does
presetremote-first or noneremote-firstThe built-in list of 70 verified boards (below). Used only when no companies are listed.
companiesstring listemptyCompany slugs, auto-detected across the five platforms in the order Greenhouse, Lever, Ashby, Recruitee, Workable. Listing companies replaces the preset.
greenhouse, lever, ashby, recruitee, workablestring listemptySlugs pinned to one platform, skipping detection.
titleContainsstring-Keep only titles containing this text (case-insensitive, partial).
strictRemotebooleantrueDrop postings the platform marks Hybrid or OnSite even if the location text says remote. Off: keep them as location-text. On the preset this changes very little (3,292 vs 3,294 remote postings on 2026-09-25) because the boards are remote-first to begin with.
onlyWithSalarybooleanfalseKeep only rows with a structured salaryMin or salaryMax (never a Greenhouse or Workable row).
postedWithinDaysinteger-Keep only postings published in the last N days.
includeDescriptionbooleanfalseAdd the description column.
maxResultsPerCompanyinteger100Cap per board, newest first.
maxResultsinteger800Total cap, applied after merging every company newest first - a capped run is the freshest N postings across the list, not the first few companies.
onlyNewSinceLastRunbooleanfalseOnly postings not seen by a previous run with this option on. See the FAQ - the first run returns everything.
maxRunSecondsinteger240Wall-clock budget. The run stops cleanly and keeps what it has.

Every board is one request whatever the caps say, so the caps only shape the output.

The remote-first preset (70 boards, verified 2026-09-25)

A board is in the list because, on the day it was checked, it resolved on exactly this platform under this slug, had at least 5 remote postings under the default strictRemote rule, and remote postings were at least half of its open roles. That is a measured property of the board on that day, not a statement about company policy, and boards drift: the preset is re-verified monthly with src/preset-health.mjs (it prints any board that no longer qualifies), and a run logs a warning naming any preset board that came back empty or non-remote.

  • Greenhouse (30, remote location-inferred): affirm, calendly, canonical, chainguard, coinbase, consensys, cribl, customerio, dropbox, gitlab, grafanalabs, hightouch, honeycomb, lattice, launchdarkly, mercury, monzo, mozilla, outschool, pantheon, planetscale, reddit, remotecom, sourcegraph91, storyblok, tailscale, twilio, typeform, webflow, wikimedia
  • Lever (7): anchorage, binance, metabase, neon, offchainlabs, sysdig, toptal
  • Ashby (32): 1password, airbyte, andela, atlan, checkly, clickhouse, clickup, close, coder, confluent, docker, goteleport, helpscout, hopper, linear, mural, n8n, oyster, posthog, prefect, quora, railway, redis, render, resend, revenuecat, sanity, signoz, supabase, temporal, workos, zapier
  • Recruitee (1): timedoctor
  • Workable (0): none, on purpose. Zyte and Remotebase qualified on content (17 and 5 remote postings), but Workable enforces a per-IP daily quota - its HTTP 429 carries a Retry-After of about 24 hours - and on a shared platform IP that quota can be gone before a run starts. Two boards worth 22 postings are not worth a default run that is slow or warns at random. Workable boards work when you list them explicitly (workable); see "Data source, access and limits".

Checked the same day and deliberately left out: Elastic and Mattermost (distributed companies whose boards publish only country names), Databricks (889 open, 8% remote), Vercel (88 / 10%), Airbnb (157 / 11%), Invisible (Greenhouse invisible 5 open / 4 remote, invisibletech 18 / 2), Ghost (Greenhouse, 6 open, 0 remote), Buffer and GitBook (Ashby boards with a single posting each), Deel (Ashby board resolves but publishes 0 jobs), 15Five and Kraken (Lever, 0 jobs), and Automattic, Doist, Hotjar, Toggl and HashiCorp (Workable accounts exist but publish 0 jobs; not on the other four platforms under those slugs). If you know the right board for one of these, pass it explicitly.

On 2026-09-25 the preset had 3,662 open postings, 3,292 of them remote; the default maxResults of 800 returned the newest three weeks (2026-09-04 onward) across 66 of the 70 companies - 513 Greenhouse, 203 Ashby, 82 Lever and 2 Recruitee rows.

Example output

A real row from the default run (2026-09-25):

{
"ats": "greenhouse",
"company": "gitlab",
"companyName": "GitLab",
"title": "Distinguished Engineer, Core DevOps",
"department": "DevOps Engineering",
"team": null,
"location": "Remote, Canada; Remote, United Kingdom; Remote, United States",
"remote": true,
"remoteBasis": "location-text",
"workplaceType": null,
"employmentType": null,
"postedAt": "2026-09-25T17:37:29.000Z",
"salaryMin": null,
"salaryMax": null,
"salaryCurrency": null,
"salaryPeriod": null,
"url": "https://job-boards.greenhouse.io/gitlab/jobs/8831350002",
"jobId": "8831350002",
"scrapedAt": "2026-09-25T18:07:35.772Z"
}

FAQ

Is this "true remote only"? Not unqualified, and the Actor does not claim it. On Ashby, Lever and Recruitee the default run keeps only postings the platform itself marks Remote, or postings with no workplace type whose location line says remote. On Workable the platform's telecommuting flag is used, and it cannot tell hybrid from on-site. On Greenhouse there is no workplace field to check, so remote is inferred from the location line - an employer that writes "Remote" on a posting that is really hybrid will get through, and an employer that writes only a city on a remote role will not. remoteBasis tells you which case each row is, so you can filter on workplaceType alone if you want the strictest set (34.8% of the default run).

What exactly does "only postings new since the last run" do? With the option on, the Actor records the job IDs of every remote posting on each board it read, in a named key-value store called remote-jobs-employer-direct-state, keyed by platform and slug. On the first run there is no baseline, so you get every remote posting and the baseline is written - the run log warns about this. From the second run on you get only IDs that were not in the baseline. 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 written only on runs with the option on, it records every remote posting on the board (so a maxResultsPerCompany cap does not hide postings from later diffs), and it is shared by every run of this Actor on your account - two schedules watching the same board will each consume the other's new postings. Do not turn this on for a run you expect to return rows every time.

Why is company X not found? The slug has to be the one in the board URL: job-boards.greenhouse.io/gitlab -> gitlab, jobs.lever.co/toptal -> toptal, jobs.ashbyhq.com/zapier -> zapier, timedoctor.recruitee.com -> timedoctor, apply.workable.com/zyte -> zyte. Some are not obvious: Sourcegraph's Greenhouse token is sourcegraph91, Remote.com's is remotecom. A slug that 404s on every platform is listed under notFound in SUMMARY and the rest of the run continues. If a company uses Workday, SmartRecruiters, iCIMS, Teamtailor or its own careers site, it cannot be read here.

Why not SmartRecruiters? Because api.smartrecruiters.com/robots.txt disallows every crawler except LinkedInBot. This Actor stays off it.

Does a Workable "found" mean the company hires there? Not always. Workable answers HTTP 200 with an empty job list for many accounts that exist but publish nothing (Automattic, HashiCorp, Doist and Hotjar all do), so during auto-detection an empty Workable hit is only used when no other platform has the company, and it is reported under boardHealth.resolvedButEmpty, not as a live board.

Why is there no salary on most rows? Because Greenhouse and Workable return no structured pay data, and on Lever, Ashby and Recruitee it is there only when the employer fills it in. 12% of the default run's rows had one. Ranges written into the description are in description when you request it, unparsed - no made-up column.

How fast is it? Each board is a single request; Greenhouse, Ashby and Recruitee are read four boards at a time, Lever one board per second (its robots.txt asks for a one-second crawl delay) and Workable one at a time. Measured locally on 2026-09-25, three consecutive default runs - the 70-board preset, 3,662 postings inspected, 800 rows written - took 10, 12, 21 and 26 seconds end to end across four consecutive runs; the spread is download throughput, because the 70 boards return 51 MB of JSON (measured 2026-09-25 - Greenhouse only publishes departments together with the full posting text). Platform runs add the time to write rows to Apify storage. Long custom lists are bounded by maxRunSeconds, not by the number of boards: with maxRunSeconds 30 against 47 Lever boards, the run finished as a success at 31 seconds with 223 rows and named the 38 boards it did not reach.

Data source, access and limits

  • Sources: the public job-board APIs of Greenhouse (boards-api.greenhouse.io), Lever (api.lever.co/v0/postings), Ashby (api.ashbyhq.com/posting-api/job-board), Recruitee (<slug>.recruitee.com/api/offers) and Workable (apply.workable.com/api/v1/widget/accounts). No key, no login, no cookies. Only postings the employer has published publicly.
  • Remote is a signal, not a guarantee. See the rule table above. remoteBasis is on every row so nothing is hidden.
  • Everything else is passed through as published. Titles, departments, locations, employment types and timestamps come from the employer's own data, with its inconsistencies - employmentType is FullTime on Ashby and Full-time on Lever, and Greenhouse has none.
  • 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. description reproduces the employer's own published text. Nothing is collected from candidates or applications.
  • Failures are explicit. Boards that error are named in the log and in SUMMARY.failedSources; slugs found nowhere in SUMMARY.notFound; boards that resolve but publish nothing in SUMMARY.boardHealth. The run still saves everything from the boards that worked. If every company fails, the run fails with a message naming the likely cause instead of returning an empty dataset that looks like "no jobs".
  • Rate limits are the platforms'. Lever asks for a one-second crawl delay and gets it. Workable enforces a per-IP daily quota: its HTTP 429 carries a Retry-After of about 24 hours (84,576 seconds measured on 2026-09-25) and its servers answer 429 and 200 alternately once the quota is used. The Actor reads Workable one board at a time, retries a 429 twice a second apart, then lists the board in SUMMARY.failedSources with the Retry-After value instead of waiting. Because Apify runs share egress IPs, an explicitly listed Workable board can fail in one run and work in the next; that is the reason no Workable board is in the preset.
  • Billing: runs are 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 sources themselves are keyless. New Apify accounts receive monthly free platform credits that cover small runs.
  • Not affiliated with Greenhouse Software, Lever, Ashby, Recruitee, Workable or any employer in the preset. Those names are trademarks of their owners; this Actor is an independent tool that reads publicly available job-board data.

Maintenance (for the publisher)

The preset is a snapshot. Once a month, and before any change to src/preset.js:

cd remote-jobs-scraper
node src/preset-health.mjs

It re-fetches every preset board with the Actor's own remote rule and exits 0 when all still qualify, 1 with an ACTION NEEDED list of boards to remove or re-slug, or 2 when a board could not be checked (transport or rate-limit error - re-run in a few minutes). Candidate boards can be checked before adding them: node src/preset-health.mjs greenhouse:elastic ashby:deel. Update PRESET_VERIFIED_ON in src/preset.js and the counts in this README after pruning.