EU Pay Transparency Compliance Checker
Pricing
from $4.00 / 1,000 job advert checkeds
EU Pay Transparency Compliance Checker
Audit any company's job adverts against the EU Pay Transparency Directive. Flags missing salary ranges, vague pay wording, and illegal pay-history questions. Reads public ATS feeds from Greenhouse, Lever, Ashby, Recruitee and Personio. No login or API key needed.
Pricing
from $4.00 / 1,000 job advert checkeds
Rating
0.0
(0)
Developer
Mike Zyke
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Audit any company's job adverts against the EU Pay Transparency Directive — every open role, in seconds.
Since 7 June 2026, employers hiring in the EU must state the salary or salary range for a role. "Competitive salary" no longer satisfies the law. Penalties reach the five- to six-figure range per breach, and in a pay dispute the burden of proof falls on the employer.
Point this Actor at a careers page. It tells you, role by role, whether the pay disclosure holds up.
Real example
A live scan of a Berlin AI company's job board (16 open roles, all EU):
| Job | Status | Pay found |
|---|---|---|
| Senior Computer Vision Engineer | ✅ compliant | €80,000 – €120,000 / year |
| Senior Backend Engineer | ✅ compliant | €70,000 – €90,000 / year |
| Account Executive | ✅ compliant | €70,000 – €90,000 / year |
| Sales Development Representative | ✅ compliant | €40,000 – €50,000 / year |
| Field Installation Engineer | ✅ compliant | €45,000 – €58,000 / year |
| Senior/Staff Robotics Engineer | ❌ no pay disclosed | — |
| VLM Research Engineer | ❌ no pay disclosed | — |
| Senior Edge Infrastructure Engineer | ❌ no pay disclosed | — |
Compliance score: 69% — 11 of 16 roles disclosed pay. Five did not, including one posted after the directive took effect.
That is the report. One run, no configuration.
What you get
One row per job:
| Field | Example |
|---|---|
complianceStatus | compliant · review · non_compliant · out_of_scope |
issueCodes | ["VAGUE_PAY_LANGUAGE"] |
salaryMin / salaryMax | 70000 / 90000 |
salaryCurrency / salaryInterval | EUR / year |
salaryEvidence | the exact text the figure came from |
jurisdiction | EU · US-transparency-state · unknown |
applyUrl | direct link to the advert |
Plus one company_summary row per employer with a 0–100 score.
{"recordType": "job","company": "almetra","title": "Senior Backend Engineer (m/f/d)","location": "Berlin","complianceStatus": "compliant","issueCodes": [],"salaryMin": 70000,"salaryMax": 90000,"salaryCurrency": "EUR","salaryInterval": "year","salarySource": "ats_field","jurisdiction": "EU","jurisdictionConfidence": "high","applyUrl": "https://jobs.ashbyhq.com/almetra/ec1bfd2d-..."}
What it catches
| Issue | Meaning |
|---|---|
NO_PAY_INFORMATION | No pay figure anywhere in the advert |
VAGUE_PAY_LANGUAGE | "Competitive salary", "attraktives Gehalt", "salaire compétitif", "según experiencia" — 60+ phrases across 8 languages |
RANGE_TOO_WIDE | €30k–€120k. Technically a range; arguably not informative. Threshold configurable |
SINGLE_VALUE_ONLY | One figure, no range |
SALARY_HISTORY_QUESTION | Asking what a candidate currently earns — banned outright by Art. 5(2) |
AI_DETECTED_PAY | Found by AI review but not deterministic rules — verify before relying on it |
Pay parsing built for European adverts
European job ads write money in ways that break naive parsing. 45.000 means forty-five thousand in Berlin and forty-five point zero in Boston. All of these are handled:
€45,000 – €60,000 per year 55.000 EUR bis 70.000 EURzwischen 55.000 € und 70.000 € 40 000 € à 55 000 € par an€ 3.500 tot € 4.500 per maand 15 000 - 22 000 PLN85k - 110k $255k - $290k per year
Numbers that are not pay — headcounts, funding rounds, version numbers, "up to 6% matching" — are ignored.
Who uses this
- HR and compliance teams — audit your own postings before a regulator or candidate does
- Recruitment agencies — check client adverts before they go live
- Pay-equity and HR-tech vendors — a live external signal alongside internal payroll analysis
- Sales teams — set
onlyNonCompliant: truefor a prospecting list of companies with a visible, dated problem - Journalists and researchers — measure real compliance rates across an industry or country
Supported job boards
Reads the public, keyless JSON feeds each ATS publishes so customers can embed job widgets on their own sites. No login, no API key, no HTML scraping, no anti-bot fight.
| ATS | Identifier | Notes |
|---|---|---|
| Greenhouse | greenhouse:stripe | Widely used by tech |
| Lever | lever:netflix | |
| Ashby | ashby:notion | Exposes structured salary data |
| Recruitee | recruitee:acme | Common with EU scale-ups |
| Personio | personio:acme | Common with German mid-market |
Accepts ats:slug, a full board URL (https://jobs.lever.co/netflix), or a bare slug to auto-detect.
Input
{"companies": ["ashby:almetra", "greenhouse:stripe"],"onlyNonCompliant": false,"maxRangeRatio": 2.0}
| Option | Default | Notes |
|---|---|---|
companies | — | Required. Slugs, URLs, or ats:slug |
atsHint | auto | Force a platform instead of probing |
maxJobsPerCompany | 200 | Stops one large board dominating a run |
onlyNonCompliant | false | Output only problem roles |
maxRangeRatio | 2.0 | Flag bands wider than this multiple |
assumeEuOnly | false | Skip jurisdiction detection, check everything |
useAiReview | true | Only used where rules find nothing |
geminiApiKey | — | Optional. Blank = rules-only |
Optional AI review
The rules engine is deterministic and conservative: it reports only pay it can prove is there. A minority of adverts bury pay in prose or phrase it unusually.
Add a free Gemini API key and those get a second look — only on jobs the rules engine could not resolve, so cost scales with ambiguity, not volume.
Three safety rules, each covered by tests:
- The model can never overturn a deterministic extraction. A hallucinated figure cannot overwrite a real one.
- An AI-only finding is capped at
review, nevercompliant. A human confirms. - Low-confidence verdicts are discarded.
No key? Everything still works. You'll just see slightly more NO_PAY_INFORMATION on unusually worded adverts.
Model availability is handled for you. Google retires Gemini models on a fast cycle and blocks older ones for newly created API keys. If the selected model isn't available to your key, the Actor logs a warning, switches to the next current model automatically, and carries on. If none are reachable it drops to rules-only rather than failing the run.
Pricing
Pay-per-event. Boards that return nothing cost nothing.
| Event | Charged when |
|---|---|
company-scanned | A board resolves successfully |
job-checked | A job is analysed and returned |
ai-review | Only when AI review actually changed a verdict |
Scope and limitations
Read this before acting on the output.
A non_compliant result is a risk flag, not proof of a breach. Article 5(1) lets an employer disclose pay before the first interview instead of in the advert. This Actor can only observe the advert. Some member states (Ireland and the Netherlands among them) go further and require it in the advert itself — but the base directive does not.
Also:
- Heuristics, not legal advice. A screening tool for human review.
- Jurisdiction is inferred from location text and can be wrong, especially for "Remote" roles. Use
assumeEuOnlywhen you already know the board's scope. maxRangeRatiois a judgement call, not a legal threshold. The directive doesn't define a maximum width.- Only published jobs appear in public ATS feeds. Internal or unlisted roles are invisible.
- Company data only. No personal data about applicants or employees is collected.
- Pay-gap reporting duties (Art. 9) apply to employers with 100+ staff and are assessed from internal payroll — outside what any external tool can see.
Legal basis for the data
Every endpoint used is the public, unauthenticated feed each ATS provides so that customer job boards can be embedded and syndicated. This is the same data any visitor sees on the company's careers page. No authentication is bypassed, no personal data is collected, and no login-walled content is accessed.
FAQ
Does this need an API key or login? No. The ATS feeds are public and keyless. The Gemini key is optional.
Can it check LinkedIn or Indeed job ads? No. It reads employers' own ATS feeds, which are published for syndication. Aggregator sites prohibit scraping.
Why is a job marked out_of_scope?
The role appears to sit outside the EU/EEA and outside a US pay-transparency state, so no disclosure duty applies. Set assumeEuOnly: true to check everything regardless.
A company scored badly — are they breaking the law? Not necessarily. See Scope and limitations above. They may disclose pay before interview, which the directive permits.
How do I find a company's slug?
Look at their careers page URL. boards.greenhouse.io/acme → greenhouse:acme. jobs.ashbyhq.com/acme → ashby:acme. You can also paste the full URL.
Development
npm installnpm test # 54 tests, no network requiredapify runapify push
src/main.js orchestration, billing, dataset outputats.js one adapter per ATS, normalised to a common shapecompliance.js rules engine — extraction, checks, scoringgemini.js optional AI adjudication + safe mergelogger.js SDK-safe logging shimtext.js HTML/entity handling, interval normalisation