ATS Salary, Skills & Seniority Intelligence avatar

ATS Salary, Skills & Seniority Intelligence

Pricing

from $4.00 / 1,000 enriched jobs

Go to Apify Store
ATS Salary, Skills & Seniority Intelligence

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

Johnn Mottin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

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_JOB
JOB_CLOSED
JOB_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:

Greenhouse
Lever
Ashby

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 pay
maximum pay
currency
period
raw 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:

  1. normalizes the company slug;
  2. uses the requested ATS or auto-detects Greenhouse → Lever → Ashby;
  3. fetches the public job board;
  4. normalizes each posting;
  5. parses published salary when enabled;
  6. detects skills when enabled;
  7. derives seniority from title rules;
  8. creates a normalized title;
  9. applies optional skill and seniority filters;
  10. sends enriched records through the billable path;
  11. sends zero-enrichment records through the free path;
  12. builds free per-run aggregations;
  13. writes a free RUN_SUMMARY;
  14. stores operational diagnostics in STATS.

Input

{
"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

FieldDefaultDescription
companiesrequiredCompany ATS slugs. Accepts a string or { slug, ats }. Maximum 100 entries.
includeSalarytrueParse publicly published compensation when detectable.
includeSkillstrueMatch 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.
maxJobsPerCompany200Maximum jobs read per company before enrichment. Range: 1–2,000.
maxResults1000Maximum billable enriched records. Range: 1–5,000.
maxRuntimeMs300000Runtime cap in milliseconds.
debugfalseAdditional diagnostic logs.

Company input format

You can provide a bare slug:

{
"companies": [
"spotify",
"linear"
]
}

A bare slug uses:

ats: auto

The Actor tries:

greenhouse
lever
ashby

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:

USD
EUR
GBP
BRL
CAD
AUD
$
£
R$

Pay periods can be classified when terms such as:

year
annual
month
week
day
hour

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:

Python
Java
JavaScript
TypeScript
Go
Rust
Kotlin
C++
C#
React
Next.js
Vue
Angular
Node.js
Django
Spring
PostgreSQL
MongoDB
Redis
Kafka
Spark
Airflow
dbt
Snowflake
BigQuery
Kubernetes
Docker
Terraform
AWS
Google Cloud
Azure
Linux
Grafana
Datadog
GraphQL
Salesforce
HubSpot
Tableau
Looker
SEO
CRM
B2B
SaaS

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:

intern
junior
mid
senior
staff
principal
lead
manager
director
vp
c-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_JOB
RUN_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

FieldDescription
recordTypeENRICHED_JOB.
entityIdStable ATS/company/job identity.
atsSourcegreenhouse, lever, or ashby.
companySlugATS board slug.
jobIdSource job ID.
titlePublished title.
titleNormalizedDeterministically normalized title.
urlPublic job/apply URL.
locationPublished location.
isRemoteRemote flag when determinable.
departmentDepartment/team when available.
employmentTypeEmployment/commitment type when available.
publishedAtSource publish timestamp when available.
observedAtActor observation timestamp.
salaryParsed published compensation object.
skillsMatched skills.
skillsVersionDictionary version.
seniorityTitle-derived seniority or null.
enrichmentEmptyWhether 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:

salary
skills
seniority

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 detected
one or more dictionary skills detected
seniority 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:

billableRecords
enrichmentEmptyRecords
companiesNotFound
jobsProcessed
salaryCoverage
skillsCoverage
enrichmentEmptyCount
topSkills
bySeniority
byCompany
topLocations
skillsVersion
qualityAlert
warnings
cost
pricingLabel

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 demand
daily
before 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.


  1. Configure a set of competitor/company ATS slugs.
  2. Save the input as an Apify Task.
  3. Go to Console → Schedules → Create schedule.
  4. Choose a cadence.
  5. Send the enriched dataset to your destination.
  6. Use RUN_SUMMARY for 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

  1. Actor reads both public job boards.
  2. Salary, skills and seniority are extracted deterministically.
  3. Records are stored in the dataset.
  4. Summary provides salary/skills coverage and hiring mix.
  5. 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-start
enriched-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:

maxResults
maxJobsPerCompany
maxRuntimeMs

Output filters can also reduce billable results:

skillsFilter
seniorityFilter

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:

Greenhouse
Lever
Ashby

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?

intern
junior
mid
senior
staff
principal
lead
manager
director
vp
c-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.