ATS Salary, Skills & Seniority Intelligence
Pricing
from $4.00 / 1,000 enriched jobs
ATS Salary, Skills & Seniority Intelligence
Turn public Greenhouse, Lever and Ashby job boards into structured salary, skills and seniority intelligence. Parse published pay ranges, detect skills with a versioned dictionary, normalize titles, filter jobs, and get free coverage and hiring summaries. No salary estimates or AI-generated fields.
Pricing
from $4.00 / 1,000 enriched jobs
Rating
0.0
(0)
Developer
Johnn Mottin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Turn public ATS job boards into salary, skills & seniority intelligence
Read current jobs from Greenhouse, Lever, and Ashby and transform each posting into structured hiring intelligence.
This Actor keeps the source data honest:
- salary ranges are parsed only when the company publicly publishes compensation;
- skills are matched with a versioned deterministic dictionary;
- seniority is derived from job-title rules;
- missing salary or skills are not filled with guesses;
- there is no LLM or AI inference in runtime.
Each run is a fresh snapshot of the current public board. It is designed for salary research, talent intelligence, competitor hiring analysis, recruiting data, workforce research, and automated hiring-intelligence pipelines.
Key features
- Greenhouse, Lever & Ashby public job boards
- ATS auto-detection from company slug
- Published salary range parsing
- Currency and pay-period extraction
- Versioned skills dictionary
- Deterministic seniority classification
- Normalized job titles
- Location, department and remote signals
- Skill filtering
- Seniority filtering
- Free hiring aggregations
- Honest salary coverage
- Honest skills coverage
- Free records when enrichment is empty
- No salary estimation
- No AI-generated skills
- No login
- No browser automation
- Pay Per Event
Unofficial community Actor. Not affiliated with, sponsored by, or endorsed by Greenhouse, Lever, Ashby, or any company whose public job board is read. Data comes from public ATS job-board endpoints and remains subject to the availability and policies of each source.
What this Actor is for
A basic ATS scraper answers:
What jobs are open?
This Actor is built to answer richer questions:
- What salary ranges are competitors publishing?
- Which technical and business skills appear most often?
- What seniority mix is a company hiring for?
- Which locations are active?
- Are competitors hiring staff/principal talent or mostly junior/mid-level roles?
- Which skills appear across a set of companies?
- How much of the current hiring board actually exposes salary information?
The output can support:
- salary benchmarking;
- talent intelligence;
- recruiting research;
- competitive intelligence;
- workforce planning research;
- hiring-signal analysis;
- market research;
- job-data products;
- dashboards;
- scheduled reports;
- n8n, Make, webhook and database workflows.
Important: this is enrichment, not a change monitor
Every run reads the current public job board and enriches the jobs it finds.
It does not maintain a user-facing diff state for:
NEW_JOBJOB_CLOSEDJOB_CHANGED
If you need persistent hiring-change events, use the separate ATS Hiring Signals Monitor.
Use this Actor when you need:
current job board+salary intelligence+skills intelligence+seniority intelligence
Supported ATS platforms
The current implementation supports:
GreenhouseLeverAshby
The Actor uses their public job-board endpoints.
Greenhouse
The Actor requests job content because salary and skills often appear in the published description.
Lever
The Actor reads the public postings API and combines the available description/list content for enrichment.
Ashby
The Actor reads the public Ashby job-board API and can use structured compensation when Ashby exposes it.
Who it's for
Recruiting and talent intelligence teams
Analyze:
- published salary bands;
- in-demand skills;
- seniority distribution;
- hiring locations;
- departments;
- competitor hiring mix.
Salary and compensation research
Use the publicly disclosed salary values without estimating missing compensation.
The Actor can structure:
minimum paymaximum paycurrencyperiodraw published salary text
when the source exposes enough information.
B2B and competitive intelligence teams
Hiring can reveal:
- new departments;
- geographic expansion;
- technical investment;
- senior leadership hiring;
- shifts in skill demand.
This Actor enriches the current job inventory so those signals are easier to analyze downstream.
Data and automation teams
Connect the structured records to:
- n8n;
- Make;
- Google Sheets;
- databases;
- BI tools;
- CRM;
- webhooks;
- internal applications;
- AI agents downstream.
The Actor itself does not use an LLM to generate enrichment fields.
How it works
For each company input, the Actor:
- normalizes the company slug;
- uses the requested ATS or auto-detects Greenhouse → Lever → Ashby;
- fetches the public job board;
- normalizes each posting;
- parses published salary when enabled;
- detects skills when enabled;
- derives seniority from title rules;
- creates a normalized title;
- applies optional skill and seniority filters;
- sends enriched records through the billable path;
- sends zero-enrichment records through the free path;
- builds free per-run aggregations;
- writes a free
RUN_SUMMARY; - stores operational diagnostics in
STATS.
Input
Recommended example
{"companies": [{"slug": "spotify","ats": "lever"},{"slug": "linear","ats": "ashby"},{"slug": "gitlab","ats": "greenhouse"}],"includeSalary": true,"includeSkills": true,"skillsFilter": [],"seniorityFilter": [],"maxJobsPerCompany": 200,"maxResults": 1000,"maxRuntimeMs": 300000}
Input fields
| Field | Default | Description |
|---|---|---|
companies | required | Company ATS slugs. Accepts a string or { slug, ats }. Maximum 100 entries. |
includeSalary | true | Parse publicly published compensation when detectable. |
includeSkills | true | Match skills with the versioned deterministic dictionary. |
skillsFilter | [] | Keep only jobs containing one of the selected skill keys. |
seniorityFilter | [] | Keep only jobs matching selected seniority values. |
maxJobsPerCompany | 200 | Maximum jobs read per company before enrichment. Range: 1–2,000. |
maxResults | 1000 | Maximum billable enriched records. Range: 1–5,000. |
maxRuntimeMs | 300000 | Runtime cap in milliseconds. |
debug | false | Additional diagnostic logs. |
Company input format
You can provide a bare slug:
{"companies": ["spotify","linear"]}
A bare slug uses:
ats: auto
The Actor tries:
greenhouseleverashby
in that order.
For more control, specify the ATS:
{"companies": [{"slug": "spotify","ats": "lever"}]}
How to find the ATS slug
The slug is the company identifier in the public ATS URL.
Greenhouse
Example:
https://boards.greenhouse.io/gitlab
Slug:
gitlab
Lever
Example:
https://jobs.lever.co/spotify
Slug:
spotify
Ashby
Example:
https://jobs.ashbyhq.com/linear
Slug:
linear
This Actor does not discover an ATS from a normal company homepage/domain.
Salary intelligence
Salary parsing is deterministic.
The Actor never creates a salary because a role should pay a certain amount.
When compensation is publicly present, the output can contain:
{"detected": true,"min": 107483,"max": 153547,"currency": "USD","period": "year","raw": "$107,483 –$153,547 USD"}
When compensation is not detected:
{"detected": false,"min": null,"max": null,"currency": null,"period": null,"raw": null}
Supported salary behavior
The parser handles common published ranges and single-value compensation patterns using deterministic rules.
Currencies/codes supported by the current parser include cases involving:
USDEURGBPBRLCADAUD$€£R$
Pay periods can be classified when terms such as:
yearannualmonthweekdayhour
are available near the published amount.
Important
Salary coverage depends entirely on what the employer publishes.
A company that publishes no compensation can legitimately produce:
salaryCoverage: 0
Skills intelligence
The Actor uses a versioned dictionary.
Current records carry a value such as:
ats-skills-2026-08.1
in:
skillsVersion
This makes historical datasets easier to interpret when the dictionary evolves.
Skill categories
The current dictionary covers categories such as:
- programming languages;
- frameworks;
- databases/data tooling;
- cloud and infrastructure;
- engineering practices;
- design;
- analytics;
- business tooling.
Examples include:
PythonJavaJavaScriptTypeScriptGoRustKotlinC++C#ReactNext.jsVueAngularNode.jsDjangoSpringPostgreSQLMongoDBRedisKafkaSparkAirflowdbtSnowflakeBigQueryKubernetesDockerTerraformAWSGoogle CloudAzureLinuxGrafanaDatadogGraphQLSalesforceHubSpotTableauLookerSEOCRMB2BSaaS
The dictionary is finite.
A skill outside the current dictionary is not invented or inferred.
Skill matching safety
Skill matching uses boundary-aware deterministic rules.
For example, a text containing:
antitrust
must not be counted as:
Rust
because the substring happens to contain the letters rust.
This type of false-positive protection is part of the dictionary design.
Seniority intelligence
The Actor derives seniority from job-title rules.
Possible values include:
internjuniormidseniorstaffprincipalleadmanagerdirectorvpc-level
If no supported title signal is detected:
seniority: null
The Actor does not guess seniority from the job description.
Title normalization
The Actor also creates:
titleNormalized
The normalization removes supported seniority/noise tokens and simplifies a title for grouping.
Example:
Senior Android Engineer II (Remote)
can normalize to a cleaner title representation.
Normalization is deterministic.
Filters
Skill filter
Example:
{"skillsFilter": ["python","kubernetes"]}
Only jobs with one of the requested dictionary keys remain in output.
Seniority filter
Example:
{"seniorityFilter": ["staff","principal","director"]}
The filters narrow the output.
They do not change how the source board itself is fetched.
Output
The default dataset contains:
ENRICHED_JOBRUN_SUMMARY
ENRICHED_JOB
Every delivered current job is normalized to one schema.
Example
{"recordType": "ENRICHED_JOB","entityId": "ats:lever/spotify/1e33d918","atsSource": "lever","companySlug": "spotify","jobId": "1e33d918","title": "Android Engineer - Advertising","titleNormalized": "android engineer","url": "https://jobs.lever.co/spotify/...","location": "New York, NY","isRemote": null,"department": "Engineering","employmentType": "Full-time","publishedAt": null,"observedAt": "2026-08-16T22:10:44.107Z","salary": {"detected": true,"min": 107483,"max": 153547,"currency": "USD","period": "year","raw": "$107,483 –$153,547 USD"},"skills": [{"key": "kotlin","label": "Kotlin","category": "language"},{"key": "agile","label": "Agile","category": "practice"}],"skillsVersion": "ats-skills-2026-08.1","seniority": null,"enrichmentEmpty": false}
Output fields
| Field | Description |
|---|---|
recordType | ENRICHED_JOB. |
entityId | Stable ATS/company/job identity. |
atsSource | greenhouse, lever, or ashby. |
companySlug | ATS board slug. |
jobId | Source job ID. |
title | Published title. |
titleNormalized | Deterministically normalized title. |
url | Public job/apply URL. |
location | Published location. |
isRemote | Remote flag when determinable. |
department | Department/team when available. |
employmentType | Employment/commitment type when available. |
publishedAt | Source publish timestamp when available. |
observedAt | Actor observation timestamp. |
salary | Parsed published compensation object. |
skills | Matched skills. |
skillsVersion | Dictionary version. |
seniority | Title-derived seniority or null. |
enrichmentEmpty | Whether salary, skills and seniority are all empty. |
Billing honesty: empty enrichment is free
A job can be useful even when the Actor does not detect:
salaryskillsseniority
The job is still delivered.
When all three are empty:
enrichmentEmpty: true
the record is pushed through the free path.
It is not charged as:
enriched-job
You pay for enrichment, not for a copy of a public job row with no detected enrichment.
What makes an enriched job billable
A record is considered enriched when at least one of these is present:
published salary detectedone or more dictionary skills detectedseniority detected
If any of those signals exists:
enrichmentEmpty: false
and the delivered record can be charged as:
enriched-job
RUN_SUMMARY
The final run summary is free.
It can include:
billableRecordsenrichmentEmptyRecordscompaniesNotFoundjobsProcessedsalaryCoverageskillsCoverageenrichmentEmptyCounttopSkillsbySenioritybyCompanytopLocationsskillsVersionqualityAlertwarningscostpricingLabel
This gives you an immediate view of the usefulness and coverage of the current run.
Honest coverage metrics
Salary coverage
salaryCoverage
is the percentage of delivered job records where a public salary was actually detected.
It is not an estimate of what missing roles probably pay.
Skills coverage
skillsCoverage
is the percentage of delivered records with at least one dictionary skill match.
A low number can mean:
- sparse descriptions;
- jobs outside the current dictionary;
- source limitations.
Free hiring aggregations
The free summary can include:
Top skills
topSkills
Seniority mix
bySeniority
Jobs by company
byCompany
Top locations
topLocations
These aggregations are based on the job records actually delivered in the run.
Company not found
When a slug is not found on the requested ATS:
NOT_FOUND
is recorded at the unit/run level.
One missing company does not automatically fail the whole batch.
With:
ats: auto
the Actor tries each supported ATS before declaring the slug not found.
Scheduling
This Actor is a snapshot transformation product.
Typical cadence:
weekly
for competitor hiring intelligence.
You can also run it:
on demanddailybefore a recruiting or compensation review
Because every run returns the current board, repeated schedules can contain the same current jobs.
If you need only new/changed hiring events, use the separate monitor product.
Recommended scheduled workflow
- Configure a set of competitor/company ATS slugs.
- Save the input as an Apify Task.
- Go to Console → Schedules → Create schedule.
- Choose a cadence.
- Send the enriched dataset to your destination.
- Use
RUN_SUMMARYfor high-level hiring intelligence.
Possible destinations:
- Google Sheets;
- Slack;
- n8n;
- Make;
- webhook;
- database;
- BI dashboard;
- internal application.
Example competitor hiring workflow
Input
{"companies": [{"slug": "spotify","ats": "lever"},{"slug": "linear","ats": "ashby"}],"includeSalary": true,"includeSkills": true,"maxJobsPerCompany": 500,"maxResults": 1000}
Downstream use
- Actor reads both public job boards.
- Salary, skills and seniority are extracted deterministically.
- Records are stored in the dataset.
- Summary provides salary/skills coverage and hiring mix.
- A downstream workflow can:
- compare salary bands;
- rank skills;
- watch seniority mix;
- populate a recruiting dashboard;
- generate a management report;
- pass structured records to an AI analysis step.
API
Run the Actor through the Apify API:
curl -s "https://api.apify.com/v2/acts/<YOUR_USERNAME>~ats-salary-skills-intelligence/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"companies":[{"slug":"spotify","ats":"lever"},{"slug":"linear","ats":"ashby"}],"includeSalary":true,"includeSkills":true,"maxResults":1000}'
Replace:
<YOUR_USERNAME><YOUR_TOKEN>
with your Apify account values.
Integrations
Use with:
- Apify API;
- Tasks;
- Schedules;
- webhooks;
- n8n;
- Make;
- Google Sheets;
- Slack;
- databases;
- BI tools;
- CRM;
- internal applications;
- AI agents downstream.
Pricing
This Actor uses Pay Per Event.
The code uses two custom events:
actor-startenriched-job
actor-start
Charged once after valid input has been accepted.
Invalid input is rejected before the start charge is opened.
enriched-job
Charged per delivered ENRICHED_JOB where:
enrichmentEmpty: false
A job with no detected salary, skills, or seniority is delivered for free.
The Pricing tab on the Actor page is always the authoritative source for current prices.
Cost control
The main controls are:
maxResultsmaxJobsPerCompanymaxRuntimeMs
Output filters can also reduce billable results:
skillsFilterseniorityFilter
Smaller research run
Use:
- fewer companies;
- a lower
maxJobsPerCompany; - narrower skills/seniority filters;
- a smaller
maxResults.
Larger market scan
Use:
- more companies;
- larger board caps;
- broad filters.
Run health
Operational statistics are written to:
STATS
in the default Key-Value Store.
Depending on the run, statistics can include:
- HTTP requests;
- retries;
- companies completed;
- companies failed;
- companies not found;
- billable records;
- free records;
- quality warnings;
- source availability;
- runtime;
- spend/cost metrics.
Honest limits
Only Greenhouse, Lever and Ashby
The current implementation does not support:
- Workday;
- SmartRecruiters;
- Workable;
- Recruitee;
- Personio;
- custom career sites.
It needs the ATS slug
A normal company domain such as:
example.com
is not automatically converted into an ATS board.
Provide the correct ATS slug or use a bare slug with ats: auto.
Auto-detection uses a fixed order
ats: auto tries:
GreenhouseLeverAshby
in that order.
If the same slug happens to be valid on multiple ATS platforms, the first successful board wins.
Specify ats explicitly when you need certainty.
Salary is never estimated
No public compensation means:
salary.detected: false
The Actor does not infer salary from:
- title;
- location;
- seniority;
- market averages.
Salary text can vary
Compensation language is free text on some boards.
The parser handles supported patterns but cannot guarantee detection of every salary format a company might write.
The skills dictionary is finite
Skills outside the current version are not returned.
This is intentional: deterministic output is preferred over invisible model inference.
Seniority comes from the title
The Actor does not inspect the full description to guess seniority.
A title without a supported seniority token can return:
seniority: null
This is not a change monitor
Repeated runs can return the same current jobs.
Use the separate ATS Hiring Signals Monitor for new/changed job monitoring.
Source behavior can change
Greenhouse, Lever or Ashby can change public API behavior or response contracts.
The Actor includes retries, health checks, and explicit contract errors to surface unexpected changes instead of inventing fields.
FAQ
Do I need an ATS account?
No.
Do I need a Greenhouse, Lever or Ashby API key?
No for the public job-board endpoints used by this Actor.
Does it use a browser?
No.
Can it auto-detect the ATS?
Yes, from the company slug.
It does not discover a slug from a normal company website.
Does it return salaries?
Yes, when compensation is publicly published and the deterministic parser can detect it.
Does it estimate missing salaries?
No.
Does it use AI to infer skills?
No.
Does it use AI to infer seniority?
No.
Which seniority levels are supported?
internjuniormidseniorstaffprincipalleadmanagerdirectorvpc-level
Can I filter for Python jobs?
Yes.
{"skillsFilter": ["python"]}
Can I filter senior roles?
Yes.
{"seniorityFilter": ["senior","staff","principal"]}
What does enrichmentEmpty: true mean?
The job was valid, but the Actor detected no salary, no dictionary skill, and no seniority signal.
The row is still delivered and is not charged as enriched-job.
Are summary records charged?
No.
What is salary coverage?
The percentage of delivered records with a detected published salary.
What is skills coverage?
The percentage of delivered records with at least one dictionary skill.
Can I schedule the Actor?
Yes.
Weekly is a practical starting point for competitor hiring research.
Will a scheduled run return only new jobs?
No.
This Actor returns current-board snapshots.
What am I charged for?
The custom start event shown in Pricing plus delivered job records that contain at least one enrichment.
Is this affiliated with Greenhouse, Lever or Ashby?
No.
This is an independent community Actor using their public job-board endpoints.
Support
For bugs, questions, or skill-dictionary requests:
johnatan291303@gmail.com
You can also use the Issues tab on the Actor page.
Part of the JM Forge suite
Also from the same developer:
- ATS Hiring Signals Monitor — persistent hiring-signal monitoring across supported ATS platforms.
- GitHub Release Monitor & Dependency Alerts — monitor genuinely new GitHub releases.
- Shopify Competitor Sale & New Arrival Insights — Shopify promotion and assortment intelligence.
JM Forge Actors remain independent tools.
Use the tool that matches the problem you need to solve.