Pay Transparency Checker: Salary Ranges in Job Postings
Pricing
from $1.50 / 1,000 jobs
Pay Transparency Checker: Salary Ranges in Job Postings
Audit job postings for salary ranges and pay transparency law signals by location (US states, cities, Canadian provinces). Greenhouse, Lever, Ashby, Workable, Recruitee. Not legal advice.
Pricing
from $1.50 / 1,000 jobs
Rating
0.0
(0)
Developer
Ad Astra Connect
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
an hour ago
Last modified
Categories
Share
Audit job postings for salary ranges and pay transparency law signals by location. Point it at employer job boards on Greenhouse, Lever, Ashby, Workable or Recruitee and get one row per job with the posted pay range (min, max, currency, interval), the matched jurisdictions (US states and cities such as California, New York, Colorado, Washington, Illinois, plus Canadian provinces such as Ontario and British Columbia) and a review status like missing_range or range_issue. Results describe jobs, never applicants or employees. These are signals for review, not legal advice.
Use cases
- HR, people ops and recruiting ops: check your own open roles for missing or open-ended salary ranges before a regulator or candidate does.
- Employment lawyers and compliance consultants: produce a dated, location-mapped evidence table for a client's postings.
- Compensation analysts: collect posted salary ranges from competitor job boards for pay benchmarking.
- Researchers and journalists: measure how many employers post pay ranges in states with pay transparency laws.
Sample output: salary range audit by location
Real rows from a prefill run on October 22, 2026 (Greenhouse board stripe), shortened:
| title | location | hasPayRange | jurisdictions | status | issues |
|---|---|---|---|---|---|
| Abuse Research Engineer | Remote from the US | false | us-co, us-ca, us-wa, us-ny-nyc, us-md, us-nj | missing_range | range_not_found |
| Abuse Investigator | Seattle, San Francisco, New York City | false | us-ca, us-ny, us-ny-nyc | depends_on_employer_size | range_not_found |
| Abuse Investigator | Dublin | false | unknown_location |
Each row also has platform, board, company, jobId, url, payMin, payMax, payCurrency, payInterval, paySource, payText, ruleNotes, rulesAsOf and a not-legal-advice disclaimer.
What data can you get: posted salary ranges and review signals
| Fields | Meaning |
|---|---|
platform, board, company | ATS platform, board slug and company display name |
jobId, title, department | Posting identifier and job metadata |
location, isRemote | Combined public locations and remote signal |
url, postedAt, updatedAt | Posting URL and available API timestamps |
hasPayRange, payMin, payMax | Whether both endpoints exist and the posted amounts |
payCurrency, payInterval | Explicit currency and pay period, without conversion |
paySource | structured, description or none |
payText | Short money excerpt or numeric range, at most 200 characters |
jurisdictions | Matched effective rule IDs |
status, issues, ruleNotes | Review signal, reason codes and coverage caveats |
disclaimer | Informational purpose, rule date and incomplete-data caveat |
rulesAsOf, scrapedAt | Rule review date and observation timestamp |
changeType | In monitoring: new_job, pay_changed or status_changed |
The overview dataset view shows salary and location fields. The flagged view shows review fields; enable onlyFlagged to collect only flagged rows.
| Status | Interpretation |
|---|---|
range_ok_signal | Observed pay endpoints have no issues detected by the implemented numeric checks. Signals for review only. |
missing_range | No pay found and at least one matched rule has no employee threshold. |
depends_on_employer_size | No pay found and every matched mandatory rule has an employee threshold. Employer size is unknown. |
range_issue | Open-ended, zero-minimum, reversed, currency missing, Ontario spread issue, or multiple tiers needing review. |
not_covered | No mandatory rule matched in this limited ruleset. EU entries remain informational. |
unknown_location | Location cannot be mapped confidently. Unqualified remote roles include remote_unspecified. |
How to audit job postings for pay transparency
- Enter employer boards as
platform:slug, a supported board URL, or a plain slug for auto-detection. Explicit platforms make runs faster. - Choose scan and output limits. The prefilled example scans 20 jobs and outputs at most 40 rows. An empty API input uses the example board with defaults of 20 scanned jobs per board and 40 output rows.
- Enable
scanDescriptionForPaywhen you want salary regex extraction from job descriptions as well as native pay fields. Descriptions are never included in output. - Run the Actor and review the dataset together with the
RUN_SUMMARYrecord. Download results using Apify dataset exports.
{"boards": ["greenhouse:stripe", "ashby:ramp"],"maxJobsPerBoard": 20,"maxResults": 40,"scanDescriptionForPay": true,"onlyFlagged": false,"requestDelayMs": 500}
keywords matches any supplied case-insensitive title substring. jurisdictionFilter accepts the IDs below, evaluates only those rules, and outputs only jobs matching at least one. onlyFlagged keeps missing_range, range_issue and depends_on_employer_size rows. Filtered rows are not billed.
Supported rule IDs: us-co, us-ca, us-wa, us-ny, us-ny-nyc, us-nj-jersey-city, us-il, us-mn, us-dc, us-md, us-hi, us-vt, us-ma, us-nj, us-oh-cleveland, us-va, us-me, us-ct, us-oh-columbus (from 2027-01-01), us-de (from 2027-09-26), ca-bc, ca-pe, ca-on, ca-nb, eu-directive. Rules with a future effective date are stored but only applied from that date.
The illustrative output below omits some timestamps and notes for brevity. The URL placeholder represents the real public job URL returned by a run.
{"platform": "ashby","board": "example","company": "Example Software","jobId": "engineer-42","title": "Software Engineer","department": "Engineering","location": "Toronto, ON","isRemote": false,"url": "<public job posting URL>","hasPayRange": true,"payMin": 120000,"payMax": 150000,"payCurrency": "CAD","payInterval": "year","paySource": "structured","payText": "CAD 120000 - 150000 / year","jurisdictions": ["ca-on"],"status": "range_ok_signal","issues": [],"ruleNotes": [{"ruleId":"ca-on","note":"Potential rule match depends on employer size (at least 25 employees); size is unknown."}],"rulesAsOf": "2026-10-22","disclaimer": "Informational signals for review, not legal advice. Rule data as of RULES_AS_OF (2026-10-22) may be incomplete.","scrapedAt": "2026-10-22T12:00:00.000Z"}
Pricing
This Actor uses pay per event pricing: $2.00 per 1,000 jobs returned (Apify Store discount tiers pay less). The price on the Store page is authoritative. Platform compute is included, so you pay for the rows you receive plus Apify's small per-run start fee, nothing else.
One job event is charged per dataset row. Filtered postings, unchanged monitored jobs and silent first-run baselines produce no job events. maxResults caps new output rows. The Actor stops gracefully when the SDK reports that the user's spending limit was reached.
Monitor salary range changes in job postings
Set monitorMode: true and choose a stable monitorKey (default default). State lives in the named key-value store pay-transparency-job-auditor-state and persists across runs.
The first successful scan of each board saves a baseline and emits nothing. Set emitBaselineOnFirstRun: true to output and bill those first observations as new_job. Later runs emit only new jobs, changed pay or changed status. Pay changes take priority if status changes at the same time. Description or title edits alone do not trigger an event. Jurisdiction or issue changes can trigger status_changed.
Use a different monitorKey for a different monitoring configuration. Result caps preserve pending alerts for subsequent runs. Failed boards retain their previous state. Partial scans retain unvisited entries; closed-job events are not produced. A silent baseline stores only the first maxJobsPerBoard jobs, so increase that limit if you need wider coverage. Deleting the named store resets monitoring.
Scheduling and integrations
Use Apify schedules for regular checks and webhooks to notify a downstream workflow when a run finishes. The Apify API and dataset exports support reporting pipelines. Connect results to Make, Zapier or n8n, or use MCP for AI agents. Monitoring is useful with schedules because unchanged jobs produce no rows.
Is it legal?
The Actor uses official public ATS endpoints, requires no login, sends no cookies and respects robots.txt. It uses plain HTTP requests, identifies itself and spaces requests per host. It does not collect applications, contact records or people profiles, and never outputs job description text. You are responsible for your use of public data and applicable terms and laws. Review signals are not legal advice or findings of a legal violation.
Limitations
- Rule data is as of
RULES_AS_OF(2026-10-22) and may be incomplete. This Actor provides informational signals for review, not legal advice. Only rules effective on or before the runtime date are evaluated. This is a maintained subset, not an exhaustive legal database. - Newfoundland and Labrador has no active entry: its job posting section is not yet in force. The EU entry only prompts
eu_directive_check_national_law; as of October 2026 only some member states have adopted national laws, so review current national implementation separately. - Every status and issue code is a factual flag about what was observed in the posting data (for example, no pay range found, or an open-ended range). It is not a finding that any law applies or was breached. Output is not legal advice.
- Employer size, local employer nexus, reporting lines, federally regulated Canadian employers, exceptions, posting-date transitions, benefits, commissions and actual good faith are not established by this tool.
- The implemented Ontario numeric heuristic flags annual CAD ranges with a spread over 50000 and a maximum of 200000 or less. Larger amounts prompt a note for review of potential exceptions. Other periods and currencies receive a note without assumed hours or currency conversion. These numeric checks do not determine legal scope.
- Location mapping uses explicit state/province names and codes, selected city aliases, countries and structured addresses. Unknown locations stay unknown. Broad remote country matches require manual coverage review; foreign reporting-line coverage is not inferred.
- Every publisher free-text output field, including job titles, company display names, departments, location labels and pay text, uses the same best-effort automated redaction as ATS Jobs Scraper. Emails (including common obfuscations), phones and detected personal names become [redacted email], [redacted phone] and [redacted name]. Context patterns and compromise NLP use an allowlist for roles, technologies, places and the board company. A trailing segment after a separator (for example "Engineer - Jane Doe") is redacted only when the NLP lexicon recognizes a first or last name, so labels like "(Japanese Fluency)" are kept; an unrecognized name in that position can pass through. Automated detection may miss names or redact legitimate text; review output before sharing or redistribution. Descriptions remain excluded.
- Native salary data depends on the employer's ATS configuration. Greenhouse boards can return empty pay arrays even when a range is written in the posting. Description scanning is off by default, so missing pay means not found in the requested API fields.
- A bare dollar sign has unknown currency. Multiple distinct structured tiers use the first tier in output and are flagged for manual location matching. Multiple prose ranges are left unparsed. A fixed explicit pay rate is represented by equal endpoints.
- Greenhouse does not provide a pay interval in its native range fields; this Actor leaves it unknown. Description scanning can fill an interval when exactly the same numeric range appears explicitly in text; otherwise it is a fallback when structured amounts are absent.
- Board list APIs can return more jobs than the scan limit. Lever pagination stops after enough postings have been fetched. Limits follow API order and do not sort by posting date.
- Requests use an 8-second timeout and at most four retries, within a 45-second run work budget. A platform timeout reserves 10 seconds for saving. Responses are capped at 8 MiB each. DNS addresses are checked at socket creation; private, local and metadata destinations are blocked, including robots redirects. Large or slow boards may yield partial results or be skipped.
- A blocked or failed board is recorded in
RUN_SUMMARY; other boards continue. The run fails only if all boards fail. A platform timeout safety stop saves partial results successfully.
FAQ
Can I use this just for salary extraction? Yes. Leave onlyFlagged off and use the pay fields together with the job metadata. Jobs outside this ruleset are still output.
What does range_ok_signal mean? The observed numeric range has no issues detected by these checks. It is a signal for review, not a legal assessment. Review the original posting and rule notes.
Why is my first monitoring dataset empty? The default first run saves a baseline. Enable emitBaselineOnFirstRun if you want those rows.
Why are some missing ranges marked as depending on employer size? The APIs do not establish the employer's employee count. A threshold-only match cannot establish coverage.
Does not_covered mean no law applies? No. It means no mandatory rule in this ruleset matched. EU jobs include an informational national-law check.
Can one bad board stop other boards? No. Per-board errors are isolated and summarized. Invalid overall input and a run where every board fails return a failed run.
Trademarks and non-affiliation
Greenhouse, Lever, Ashby, Workable, Recruitee, Stripe, Ramp, Apify, Make, Zapier and n8n are trademarks of their respective owners. This Actor is not affiliated with, endorsed or sponsored by Greenhouse, Lever, Ashby, Workable, Recruitee, Stripe, Ramp, Apify, Make, Zapier or n8n.
Support
Use the Issues tab on this Actor's Apify Store page. Include your input, run ID and a posting example, without personal information.