ATS Hiring Intelligence for Your Account List avatar

ATS Hiring Intelligence for Your Account List

Pricing

from $3.00 / 1,000 company processeds

Go to Apify Store
ATS Hiring Intelligence for Your Account List

ATS Hiring Intelligence for Your Account List

Give it your account list (a dataset or ATS board links). It reads each company's PUBLIC Greenhouse, Lever or Ashby job feed and adds hiring columns next to your original ones: open roles, role families, remote/salary coverage, tech mentions, and new/changed/removed roles between runs.

Pricing

from $3.00 / 1,000 company processeds

Rating

0.0

(0)

Developer

MST MORIUM AKTHER MAYA

MST MORIUM AKTHER MAYA

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Hiring intelligence for your account list. Give this Actor a list of companies (typed in, or an existing Apify dataset such as the output of a lead scraper) and it reads each company's public job board on Greenhouse, Lever or Ashby, then adds hiring columns to your own row: open roles, role families, departments, locations, remote share, how many roles publish pay, and, if you run it again, which roles are new, changed or gone.

It is not a job-board scraper. You get one row per company you gave it, with your own columns kept, so the result drops straight into your CRM, spreadsheet, n8n or Make workflow.

What it does

  • Reads only the public job-posting feeds of Greenhouse, Lever (including the EU tenant) and Ashby. Plain HTTP and JSON: no browser, no proxy, no login, no cookies.
  • Deterministic. No AI/LLM is called; the same board gives the same answer.
  • Never touches candidates, applications, hiring managers or any private ATS data, and never uses an authenticated API.
  • Does not republish job descriptions. Descriptions are read only if you turn on technology mentions; only the matched term plus a snippet of at most 120 characters is output.
  • Tells you honestly when it could not look. "No ATS found" and "source unavailable" are never reported as "no jobs".

Who it is for

  • Sales and RevOps teams who want a hiring signal next to every account in their CRM export.
  • Recruiting and staffing agencies who track which target accounts are opening roles in a given team.
  • Market and competitor analysts who monitor a fixed list of companies week after week.
  • Automation builders who need a predictable, one-row-per-company JSON that an AI agent or workflow can consume.

Supported applicant tracking systems

ATSAccepted formsNotes
Greenhousegreenhouse:airbnb, https://boards.greenhouse.io/airbnb, https://job-boards.greenhouse.io/airbnbThe public list feed carries no pay data, so pay columns are null (unknown), not 0.
Leverlever:weride, https://jobs.lever.co/weride; EU tenant lever-eu:acmePay appears only when the posting publishes it.
Ashbyashby:ramp, https://jobs.ashbyhq.com/rampPublishes workplace type and, often, pay ranges.

Other ATS vendors, authenticated APIs and jobs-per-row output are not part of this version.

Input modes

  1. Boards typed in (boards): one entry per line, either a short form or a public board link. An entry can also be an object with your own columns plus a board column, for example {"company": "Ramp", "board": "ashby:ramp"}.
  2. An existing dataset (datasetId + boardField): pick a dataset holding your account list. Your dataset is only read, never modified. boardField names the column with the board link; if empty, the Actor looks for board, careersUrl, jobsUrl, ats, greenhouse, lever or ashby.
  3. Find the board from the company website (detectFromWebsite, optional, best effort): for rows with no board, the Actor reads at most 2 public pages of the company site (/careers, then the home page) and looks for a Greenhouse, Lever or Ashby link. Board names are never guessed. The company's robots.txt is respected here; if a site disallows access, cannot be confirmed, or shows no board, the row is ATS_NOT_DETECTED.

Other options: includeTechnologies (default off), trackChanges and stateStoreName (history for change detection), maxRows (a cheap test cap), maxConcurrency (1 to 4).

Enriching an existing dataset

Your original columns come first, in their original order, and the ats* columns are appended. If one of your columns already has an ats* name, ours is stored with an enrichment_ prefix so nothing of yours is overwritten. Rows are never dropped: an unusable row stays in the output with its status and the reason. If two rows point to the same board, the second row repeats the first row's result, atsDuplicateOf holds the first row's inputIndex, and you are charged once.

Keep in mind that Apify deletes unnamed (default) datasets after a retention period (7 days at the time of writing, per Apify's storage rules), so export or forward the results you want to keep.

Output

One row per input row. Example for ashby:ramp, produced by running this Actor's code on a recorded real Ashby response (top roles shortened):

{
"company": "Ramp",
"website": "ramp.com",
"atsStatus": "SUCCESS",
"atsProvider": "ashby",
"atsBoardKey": "ashby:ramp",
"atsBoardUrl": "https://jobs.ashbyhq.com/ramp",
"atsOpenRoles": 2,
"atsRemoteRoles": 0,
"atsRolesWithSalary": 1,
"atsSalaryCoverage": 0.5,
"atsRolesPublishedLast30Days": 0,
"atsPublishedDateBasis": "publishedAt",
"atsRoleFamilies": { "Sales": 1, "Security": 1 },
"atsDepartments": [{ "name": "Engineering", "count": 1 }, { "name": "Sales", "count": 1 }],
"atsWorkplaceTypes": { "remote": 0, "hybrid": 1, "onsite": 1, "unknown": 0 },
"atsTopRoles": [{ "title": "Account Executive", "roleFamily": "Sales", "location": "London", "workplaceType": "onsite" }]
}

Column groups:

  • Identity: atsProvider, atsBoardToken, atsBoardKey, atsBoardUrl, atsCheckedAt, inputIndex, atsDuplicateOf.
  • Result: atsStatus, atsStatusDetail, atsHttpStatus, atsNotes.
  • Facts from the board: atsOpenRoles, atsRoleFamilies, atsDepartments, atsLocations, atsWorkplaceTypes, atsRemoteRoles, atsRolesWithSalary, atsSalaryCoverage, atsRolesPublishedLast30Days, atsPublishedDateBasis, atsTopRoles.
  • Optional technology mentions: atsTechnologyMentions.
  • Changes (needs history): atsChangeComparison, atsBaselineAvailable, atsNewRoles, atsChangedRoles, atsRemovedRoles, atsChangeDetails, atsPreviousCheck.

Unknown is null, never 0.

How each number is calculated

ColumnRaw inputRuleResult
atsOpenRolesPostings listed on the public boardCount of postings returned right nowA fact about the board, not headcount and not "hiring momentum".
atsRoleFamiliesPosting title (and department)Fixed keyword rules (Engineering, Sales, Security, ...). A bracketed qualifier never decides the family.Counts per family. Rules are heuristic; unclear titles fall in Other.
atsRemoteRolesThe workplace type the board statesNumber of postings declared remotenull when the board states no workplace type at all (for example Greenhouse list feeds). Otherwise it is a lower bound: postings with no stated type are not counted as remote.
atsRolesWithSalary, atsSalaryCoveragePay ranges published on postingsPostings with a range, and that share of open rolesnull for Greenhouse (the feed has no pay data).
atsRolesPublishedLast30DaysPublish date per postingPostings published in the 30 days before the checkatsPublishedDateBasis says which date the vendor provides. null if the vendor gives none.
atsTechnologyMentionsPosting descriptions (opt-in)Per tool: coreRoles (named as required), optionalRoles (plus/preferred), exampleRoles (in an "e.g." or alternatives list)A mention in a job posting is not evidence that the company uses the tool.

Statuses

StatusMeaningDoes NOT meanCharged
SUCCESSBoard read, roles found.Yes
NO_PUBLIC_JOBSBoard exists and lists zero roles right now.Not proof the company is closed or not hiring.Yes
PARTIAL_SUCCESSRead, but truncated or incomplete (see notes).Yes
ATS_NOT_DETECTEDThe value is not a supported board link, or nothing was found on the company site (detail: NOT_AN_ATS_BOARD_URL, NO_ATS_EVIDENCE_FOUND, SKIPPED_ROBOTS_TXT).Not "not hiring". The company may use another ATS or a board we cannot see.No
SOURCE_UNAVAILABLEBoard or host unreachable or not found (detail says which, for example BOARD_NOT_FOUND).Not "no jobs".No
RATE_LIMITEDThe host throttled the request. Run again later.No
INVALID_INPUTThe row has no board value and website detection is off (detail: NO_BOARD_VALUE), or is otherwise unusable. The row is kept.No
NOT_PROCESSEDSkipped because of a time or cost limit. Run it again.No
DUPLICATE_ROWSame board as an earlier row, and its result was no longer in memory (very large lists). atsDuplicateOf points to the first row.No

Change detection

Turn on trackChanges (default) and run the same list again. The first run stores a baseline: atsChangeComparison is baseline and atsBaselineAvailable is false, so no changes are reported. From the second run on, atsBaselineAvailable is true and atsNewRoles, atsChangedRoles and atsRemovedRoles are filled. atsBaselineAvailable is empty when history is off.

  • A role counts as removed only after it is missing in two consecutive healthy runs (first it is not_seen).
  • If more than half of at least 10 known roles disappear at once, the board is flagged suspect instead of reporting removals.
  • A failed, partial or unavailable run never writes to history, so a source failure can never turn into mass closure.
  • Greenhouse updated_at is ignored on purpose because it is bulk-touched.

History lives in a named key-value store in your own account (stateStoreName). Use a different name per account list.

Limitations

  • Only Greenhouse, Lever and Ashby. A company on another ATS is ATS_NOT_DETECTED.
  • Role-family and technology extraction are keyword rules, audited on real boards but not guaranteed accurate. There is no labelled benchmark.
  • Raw counts are facts about a public board, not a measure of company growth.
  • Website detection is best effort and finds only boards linked from the checked pages.
  • Greenhouse has no pay data in the public list feed; technology mentions on Greenhouse need heavier requests, so they are opt-in.
  • Vendors publish no rate limits for these public GET endpoints; the Actor stays conservative (below).

Pricing

Pay-per-event: $0.003 per company processed (event company-processed), plus Apify's standard Actor-start event of $0.00005 per run. Apify platform usage (compute, storage) is covered by the publisher, so these events are the whole price. A company is charged once per distinct board that was actually read (SUCCESS, NO_PUBLIC_JOBS, PARTIAL_SUCCESS). Nothing is charged for ATS_NOT_DETECTED, SOURCE_UNAVAILABLE, RATE_LIMITED, INVALID_INPUT, NOT_PROCESSED or DUPLICATE_ROW.

Companies in your listMaximum company charge (before the start event)
10$0.03
100$0.30
1,000$3.00
10,000$30.00

These are upper bounds: if 40% of your rows are unavailable or have no ATS, you pay for the other 60%. Set a maximum cost per run in Run options to cap spending.

Measured on the Apify platform (owner runs, 1 GB memory): 10 companies about 6 s and 74 MB peak; 100 companies about 20 s and 101 MB; 1,000 companies about 5 minutes and 207 MB. Your own runs will vary with the boards you list.

Use it from code and tools

Replace <YOUR_API_TOKEN> with your own Apify API token. The Actor ID is yourname_mahi/ats-hiring-intelligence.

Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("yourname_mahi/ats-hiring-intelligence").call(run_input={
"boards": ["ashby:ramp", "greenhouse:airbnb", {"company": "WeRide", "board": "lever:weride"}],
"trackChanges": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["atsBoardKey"], row["atsStatus"], row["atsOpenRoles"])

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('yourname_mahi/ats-hiring-intelligence').call({
boards: ['ashby:ramp', 'greenhouse:airbnb', 'lever:weride'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

cURL

curl -X POST "https://api.apify.com/v2/acts/yourname_mahi~ats-hiring-intelligence/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"boards": ["ashby:ramp", "greenhouse:airbnb", "lever:weride"]}'

n8n

Add the Apify node, choose Run Actor, select this Actor and paste your input JSON, then add a second Apify node, Get dataset items, using the run's default dataset. Each item is one company row you can send to your CRM.

Make

Use the Apify app: Run an Actor, then Get Dataset Items, or trigger a scenario from the run's webhook. Map atsBoardKey, atsStatus and atsOpenRoles into your spreadsheet or CRM module.

AI agents and MCP

Apify Actors can be called by AI agents through Apify's MCP server (mcp.apify.com) once an Actor is public. The input is a plain list of boards and the output is one predictable row per company, which suits tool use. Agentic payments (x402, Skyfire) need the publisher's identity verification; that status is not verified at the time of writing, so rely on a normal Apify account and token.

Responsible use

  • Only public job postings are read, over the vendors' public JSON feeds, at a low request rate with per-host limits, retries and a circuit breaker.
  • Allowed hosts only: boards-api.greenhouse.io, api.lever.co, api.eu.lever.co, api.ashbyhq.com. HTTPS only, no redirects, private and local network addresses refused, 12 MB response cap.
  • Website detection refuses IP-literal hosts and ports other than 80/443, follows at most 4 redirects, scans the first 3 MB of at most 2 pages, and respects robots.txt.
  • You are responsible for how you use public job data and for the terms of the sites involved. Do not use the output to contact individuals; it contains no personal data about candidates or hiring managers.

FAQ

Is this a job scraper? No. It returns one summary row per company in your list, not a list of jobs.

Why is a company ATS_NOT_DETECTED? You gave no board and none could be found, or the company uses another system. It does not mean the company is not hiring.

Why is atsRemoteRoles empty? The board states no workplace type (common on Greenhouse). Unknown is null, not 0.

Why is atsSalaryCoverage empty on Greenhouse? Greenhouse's public list feed has no pay data.

Why were no changes reported on my second run? Check atsBaselineAvailable. If it is false, that run created the baseline or the comparison was skipped because the board was not read healthily.

Does it need a proxy or login? No. It uses plain public HTTP requests.

Will I be charged for failures? No. Unavailable sources, undetected ATS, invalid rows and duplicates are free.

Can I run it on a schedule? Yes. Use Apify schedules with the same stateStoreName and trackChanges on to get weekly change reports.