Paste a list of companies. Get back each one’s open jobs (up to 1,000 per company by default), straight from the company’s own job board, in one schema across 8 applicant-tracking systems: Greenhouse, Lever, Ashby, Workday and 4 more.
Mix company names, domains and careers URLs in one run, from Apify Console, on a schedule or through the Apify API. $0.001 per job row, no subscription. Companies not found are free.
Run on Apify Store →Tracking 60 employers or 500? Put every one in companies, one per line: names, domains, careers URLs or rows pasted from a spreadsheet. There’s no cap on the length of the list, and one run covers it all.
found, the ATS and board, openJobs and the jobs posted in the last 30 days, so you see at a glance who’s hiring.maxJobsPerCompany keeps one big employer from filling the run, and maxItems caps the whole run’s spend.gleanwork), and a name can match another company’s board (“Runway” matches a planning startup’s, not Runway ML’s). On the 2025 Forbes Cloud 100 (checked 2026-10-11), names alone found the right board for 67 of 100 companies, and domains for 73.| title, department, location, remote | As the board gives them — e.g. “Senior / Staff Fullstack Engineer”, Product, Europe, remote |
|---|---|
| postedAt, postedAtPrecision | Posted date, and how exact it is: exact; day for Workable and Workday; fallback-updated when Greenhouse gives only the last-updated time |
| url, ats, boardUrl | The job’s own link, and the board it came from |
| boardJobUrl | Greenhouse jobs only: the job’s own page on Greenhouse, with the title, description and apply form. On many Greenhouse boards, url is the company’s careers page (?gh_jid=), and some of those pages show the job only after a script runs or refuse requests that don’t come from a browser, so a link checker or job feed gets no job from them. Once the job closes, the link redirects to the company’s job list on Greenhouse. Empty on the other ATSes, where url is already the job’s page on the ATS |
| matchConfidence, matchedBy | explicit, high or medium, and how the board was found: board (you gave it), name (from the company’s name or its domain’s name), or site (a board whose name only partly matches, kept because the company’s own site links it or lists its jobs) |
| globalId | A stable ID per job (ats:slug:jobId) for de-duplicating across runs |
| seniority, technologies | Seniority level and technologies named in the post |
| locations, locationsCount | Workday jobs posted in several places: every place, read from the job’s own page |
| country, countries, countrySource | An ISO code (US, GB), set only when the board’s own country field or the location clearly names one country for every place of the job; countries lists every country of a job posted in several; countrySource is ats (the board’s own field) or location (read from the location text). A bare city or a US state gives no country unless the board’s own field names one. A region (“Europe”, “EMEA”) or plain “Remote” gives none, even when the board’s field names a country. An unclear country is left empty, never guessed |
A field the board doesn’t give is left empty, except remote, which is true only when the board or the location says remote. Turn on Include description for the description text on Greenhouse, Lever, Ashby, Workable, Rippling and Personio, and on Workday, where it is read from each job’s own page (one job at a time per employer, for up to 15 minutes per employer per run) and also gives the job its posted date. In Workday descriptions, email addresses, phone numbers and labelled recruiter or contact lines are removed automatically. The scrub matches patterns, so a contact written an unusual way, such as a name inside a sentence, can remain. Check descriptions if your board must show none. Descriptions from other ATSes are delivered as the employer wrote them.
Country coverage, measured 2026-10-11 on 82 job boards from the 2025 Forbes Cloud 100 (10,329 jobs): 64% of jobs have a country (Ashby 88% on 31 boards, Greenhouse 50% on 44, Workday 33% on 5), re-counted 2026-10-12 after the location rule started reading forms such as United States (Remote).
Each company also gets one free status row (type = company): found or not, why not, the board to pass explicitly next time, the board’s size, and hiring signals (jobs posted in the last 7, 30 and 90 days, a hiring score, top departments and technologies). In a CSV or spreadsheet export, filter the type column to job for job rows only.
ashby:slug or its URL. One found from a name or domain comes back as a free status row naming the board to pass.https://acme.wd1.myworkdayjobs.com/External , or workday:tenant:wdN:site, is read as given, with no lookup. To see how the lookup works, or do it by hand, read Workday jobs by company name.rippling:slug.greenhouse:stripe, lever:palantir, ashby:ramp.Other systems (iCIMS, Taleo, SuccessFactors, Oracle and the rest) aren’t covered; a company whose board isn’t on one of these 9 gets a free status row saying so. See also which ATS each company on the 2025 Forbes Cloud 100 uses and what those companies are hiring for.
Limits: Workday lists jobs page by page, and a run reads up to 1,000 jobs from each such board (Rippling: up to 1,000 listings; its status row has no board total). A bigger board’s status row says jobsTruncated with reason sourceCap and gives the board’s own total. Separately, maxJobsPerCompany defaults to 1,000 (the Console form starts at 10 for a quick first run); raise or lower it per run.
Input {"companies": ["ashby:linear"], "maxItems": 2}, run on 14 October 2026. Linear’s Ashby board (31 open jobs) was read as given, so the rows say matchConfidence: "explicit" and matchedBy: "board". Ashby’s API gives no company name, so companyName is null; an Ashby board is matched only when you give it like this, or by its URL. Two job rows came back and were charged $0.002 in all, and the status row was free. The first job row, trimmed:
{
"type": "job",
"globalId": "ashby:linear:d3bc1ced-3ce4-4086-a050-555055dbb1ff",
"title": "Senior / Staff Fullstack Engineer",
"company": "ashby:linear",
"companyName": null,
"ats": "ashby",
"boardUrl": "https://jobs.ashbyhq.com/linear",
"matchConfidence": "explicit",
"matchedBy": "board",
"url": "https://jobs.ashbyhq.com/linear/d3bc1ced-3ce4-4086-a050-555055dbb1ff",
"location": "Europe",
"remote": true,
"department": "Product",
"seniority": "staff+",
"postedAt": "2021-04-27T20:13:45.158+00:00",
"postedAtPrecision": "exact",
"technologies": ["JavaScript", "TypeScript", "React", "GraphQL", "Node.js",
"PostgreSQL", "Redis", "GCP", "Kubernetes", "Notion"],
"companyOpenJobs": 31,
"companyPostedLast30d": 4,
"companyHiringScore": 42
}
titleKeywords, excludeTitleKeywords, locationKeywords and departmentKeywords (case-insensitive, “contains any”), remoteOnly, countries (ISO codes such as US or English names such as Germany), postedWithinDays (with requirePostedDate to drop undated jobs; Workday’s “Posted 30+ Days Ago” jobs get their date from the job’s own page, read for every Workday job when descriptions are on), minMatchConfidence (medium by default, or high), and maxItems to cap job rows, and so spend, for the whole run.
With countries, a job is kept when one of its countries is in the list. A job whose country is unknown is left out and not charged; each status row counts the jobs left out in countryUnknown (no country known) and countryOther (another country). An entry that isn’t a country stops the run before anything is looked up or charged.
For scheduled runs, turn on onlyNewJobs. The first run returns every job as usual; after that, each run returns and charges only jobs that no earlier run with the same stateKey returned, whether or not the board gives a posted date. Delivered rows have isNew: true, which means not returned by this state before, not recently posted. Jobs cut by a cap, the charge limit or the timeout are offered again on the next run, so with maxJobsPerCompany smaller than a board, later runs return jobs that were already on it. Once a run returns a board in full (no jobsTruncated on its status row), later runs return only jobs added since; a Workday or Rippling board over 1,000 jobs is never read in full. For fresh postings only, add postedWithinDays, with requirePostedDate to drop jobs that have no posted date. Jobs delivered earlier are dropped before charging, and each status row counts them, free, in rowsDropped.seenBefore.
The job IDs are kept in a key-value store named company-jobs-state in your own Apify account, one saved state per stateKey (default if left empty), so give each schedule or employer list its own key.
Turn on feedOutput and each run also keeps an XML job feed at one URL that doesn’t change. Paste that URL into your job board software’s XML import, schedule the Actor daily, and the board stays in step with your employer list. Jboard, Job Boardly, JobBoard.io, SmartJobBoard, Niceboard and Cavuno can import a feed from a URL. Cavuno includes recurring XML feeds on every plan, from $39 a month. The others offer it only on some plans: Jboard’s XML importers are on its Advanced plan, and Niceboard’s Core plan allows 10 import runs a month, too few for a daily refresh.
OUTPUT record (feedUrl), its status message and its log. Runs with the same key keep the same URL: your feedKey, or with onlyNewJobs the stateKey.OUTPUT counts them in jobsWithoutDescription. Workday job pages are read for up to 15 minutes per employer per run; with onlyNewJobs, a Workday job whose page couldn’t be read in that run is held, not charged, and read again on the next run (jobsDescriptionPending). A Workday job that closed before its page was read isn’t delivered or charged (jobsClosed).location, and OUTPUT counts it in jobsWithoutLocation. JobBoard.io uses the feed’s backup location for such a job, if you set one. Jboard can mark jobs remote when the location is missing; its general location replaces the location of every imported job. Set a fallback that is true of those jobs, or leave those employers out of the feed.onlyNewJobs, a daily run charges only the jobs that are new since the last run, and the feed still keeps every one that is open.maxJobsPerCompany and maxItems limit what one run adds, not the feed. Jboard’s first import of a new feed takes the first 1,000 jobs and brings in the rest on its next daily run; on a Jboard trial, an importer stops at 1,000 jobs. With descriptions the feed holds about 1,200 jobs within its 8 MB limit. Workday descriptions vary more in length by employer, so a feed of Workday jobs holds about 800 to 2,200 within that limit (measured on live jobs, October 2026). Past the limit the oldest are left out, so split larger lists across feed keys.Anyone with the feed URL can read the feed, without an Apify token; it opens that one record only, and the jobs in it are already public on the employers’ own boards. The URL is also in the run’s log and status message, so share a run only with people who may read the feed. The feed is kept in a key-value store named company-jobs-feed in your own Apify account. Keys, retiring a URL and the full update rules are in the Actor’s README.
| Job row | $0.001 — per job delivered ($1 per 1,000) |
|---|---|
| Status row | Free, one per company |
Not charged: companies that aren’t found or whose match is below your confidence setting; jobs your filters remove; with onlyNewJobs, jobs an earlier run already returned; duplicates (a job is returned once, even when the same company is typed as a name and a domain); “general application”, talent-pool and test postings; Workday jobs that closed before their page was read (jobsClosed); with onlyNewJobs and descriptions on, Workday jobs whose page couldn’t be read in that run, held for the next run (jobsDescriptionPending); and jobs past maxJobsPerCompany, maxItems, the run’s maximum charge or its timeout. Set a maximum cost per run in the Apify run options and the tool stops cleanly at that limit.