EU Pay Transparency Job Ad Auditor: salary evidence
Pricing
from $5.00 / 1,000 postings
EU Pay Transparency Job Ad Auditor: salary evidence
I find stated pay, vague wording and pay-history requests across seven public ATS boards and career pages. Every finding includes source text. Missing advertised pay is a review flag, not a legal verdict.
Pricing
from $5.00 / 1,000 postings
Rating
0.0
(0)
Developer
Jessy Mariau
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share
EU Pay Transparency Job Ad Auditor
Review a company's job board without reading every advert into a spreadsheet. Get the pay figures found, any vague wording, and evidence of a pay-history request, with source text beside each result.
Missing pay in an advert is a review flag. It is not proof of a legal breach: the disclosure can happen before an interview, and national rules differ. This tool reads the public advert, not the employer's entire recruitment process.
See three sample results: leave all sources empty and run the demo with no Actor event charge. When you supply real postings, 100 readable adverts cost $0.50 in Actor events. Failed sources and unreadable postings are not charged. An optional OpenAI second pass uses your own key and has its own usage costs.
Sample output
These fictional adverts are bundled with the Actor. The table was checked against the actual demo output on 8 September 2026.
| Role | Pay in advert | Pay-history request | Review status |
|---|---|---|---|
| Store Manager, Amsterdam | EUR 42,000–48,000/year | No | OK |
| Head of Marketing, Berlin | Vague | No | ATTENTION |
| Finance Analyst, Paris | Missing | Yes | REVIEW_REQUIRED |
OK describes these text checks only. Open pay_evidence and history_evidence to review what was matched before taking action.
What it does
You give it job boards, career pages, single posting URLs, or any mix. It reads the postings and works out three things for each one.
Is pay stated? PROVIDED when there is an actual figure or range, VAGUE when the advert only gestures at pay with wording like competitive salary or à négocier or leistungsgerechte Vergütung, and MISSING when there is nothing. Figures are read from a structured field where the applicant tracking system publishes one, from JSON-LD baseSalary on a career page, and from the advert text otherwise. Text detection handles European number formats and currencies: 45.000 – 55.000 €, €45k-55k, 45 000 EUR brutto/Jahr, 25 000 - 32 000 zł miesięcznie, 450 000 kr per år. Vague wording is matched in English, German, French, Spanish, Italian, Dutch and Polish.
Does it ask for pay history? That is the Article 5(2) point, and it is kept strictly apart from asking what salary someone wants. "Gehaltsvorstellung", "prétentions salariales" and "salary expectations" are recorded in their own field and are never counted as a breach, because the directive bans asking about pay history, not pay expectations. A payroll job that lists "Gehaltsabrechnung" as a duty is not asking anyone for a payslip either, so document wording only counts when the advert is asking the applicant to send one.
Is the posting in the geographic filter? Country comes from the posting's own location field where it has one, from JSON-LD jobLocation, or from the location text. The geographic filter includes EU-27 plus Iceland, Liechtenstein and Norway; this does not determine national legal applicability. A role advertised across the Union with no single country is kept as EU rather than thrown away.
Those three combine into a verdict: OK when pay is stated and no pay history is asked for, ATTENTION when the wording is vague or pay is stated but history is asked for, REVIEW_REQUIRED when an in-scope posting states no pay at all, OUT_OF_SCOPE for a posting outside the EU and EEA, and UNREADABLE when the posting was fetched but carried no usable text.
Seven applicant tracking systems are read through their own public postings APIs:
- Greenhouse
- Lever
- Ashby
- Personio
- Workable
- SmartRecruiters
- Recruitee
None of them needs a key or a login, and there is no proxy or browser anywhere in the chain.
What you need
Nothing. Every source is a public endpoint.
There is one optional field. If you paste an OpenAI key, postings where the rules found no pay wording at all get a second look from a model, which catches unusual phrasing and languages the lexicon does not cover. It never overrides a figure the rules already found, and rows it decided are marked pay_source: "llm" so you can tell them apart. Leave it empty and the audit runs in full.
Run it with no sources at all and you get three sample rows in demo mode, nothing charged, so you can see the shape before you point it at anything.
How to run it
Audit a few company boards:
{"atsBoards": "greenhouse:getyourguide\nlever:qonto\npersonio:orderbird\nrecruitee:channable\nworkable:skroutz","maxPostingsPerSource": 50}
The identifier after the colon is whatever that system puts in the board URL: the Greenhouse board token, the Lever site name, the Ashby job board name, the Personio subdomain, the Workable subdomain, the SmartRecruiters company identifier, the Recruitee company name.
Audit a career page and a single advert:
{"careerPageUrls": "https://jobs.channable.com/","jobUrls": "https://jobs.channable.com/o/apar-specialist-join-our-finance-team","maxPostingsPerSource": 25}
On a career page, JobPosting JSON-LD is read where the page publishes it, and job links on the page are followed where it does not.
The OUTPUT record in the key-value store holds the run summary: how many postings were audited and charged, the count for each verdict, a per-employer breakdown with the postings that ask for pay history listed out, and any source that returned nothing along with why.
Output fields
| Field | What it holds |
|---|---|
employer, title, url | the company, the role, the live advert |
source | greenhouse, lever, ashby, personio, workable, smartrecruiters, recruitee, or page |
verdict | OK, ATTENTION, REVIEW_REQUIRED, OUT_OF_SCOPE or UNREADABLE |
pay_disclosed | PROVIDED, VAGUE or MISSING |
pay_min, pay_max, currency, period | the parsed figures, ISO currency, and year, month, week, day or hour |
pay_source | ats, json-ld, text or llm: where the pay finding came from |
pay_evidence | the exact text the pay finding was matched on |
asks_pay_history, history_evidence | whether the advert asks what the applicant earns or earned, and the sentence |
asks_pay_expectations, expectations_evidence | whether it asks what they want, reported separately and never a breach |
location_country, in_scope_eu_eea, remote, location | ISO 3166-1 alpha-2 or EU, whether the location falls in the EU/EEA geography filter; not a legal scope determination, and the location as advertised |
date_posted, department, employment_type | as published by the source |
checked_at, error | when the row was produced, and why a posting could not be read |
Pricing
Pay per event: one posting-audited charge per posting that was fetched and audited. A posting that came back with no usable text costs nothing, a board that 404s costs nothing, and a source that returns an error costs nothing. Demo mode is free.
Limits
This is a text audit of public job adverts. It is not legal advice, and it does not tell you whether an employer is breaking the law.
Three things worth being clear about. National rules vary, because member states transposed the directive at different times and some went further than the minimum, so what a given advert has to say depends on where the job is. The directive allows pay information before the interview rather than necessarily in the advert. Whether a particular employer meets the applicable national rules needs a separate review. And a MISSING verdict means one thing only: the posting itself does not state pay. Treat it as a place to look, not a finding.
Two practical limits on sources. Teamtailor is not supported, because its jobs API needs an API key issued per company; give the career page URL instead. Personio's public XML feed often ships with the description field empty, and its job pages sit behind a bot challenge, so a Personio board can come back UNREADABLE even though the adverts read fine in a browser. When that happens the run says so rather than guessing.
Sources that fail are reported by name with their HTTP status in source_errors, never quietly dropped.
Pair it with a workflow
If you run n8n, my free templates on https://n8n.io/creators/fractional-hq take a list like this Actor's output and turn it into lead scoring, outreach drafts and follow-ups without another tool in the chain.
There is a longer write-up of how the audit works, and what it deliberately does not claim, at https://fractionalhq.uk/use-cases/pay-transparency-audit
Directive text: https://eur-lex.europa.eu/eli/dir/2023/970/oj
Use it from an AI agent
Inside an AI agent this Actor works as an MCP server, which I set up for my own agents first. Add https://fractionalhqforyou--eu-pay-transparency-job-ad-auditor.apify.actor/mcp and call the single tool, audit_job_postings, with the same job ad URLs the input form takes. The audit costs the same per event whichever way it is started. If a raw endpoint cannot be added, apify/actors-mcp-server with fractionalhqforyou/eu-pay-transparency-job-ad-auditor in its list exposes the same tool.
Related Actors I publish
Pay transparency sits beside two other EU obligations and one hiring signal, all of which have their own Actor here.
- European Accessibility Act Reporter: collects automated accessibility findings and writes a remediation report.
- E-Invoice Validator: validates XRechnung, ZUGFeRD and Peppol invoices before they bounce.
- First-Time Hire Signals: tracks newly observed hiring functions and explicit founding-role signals.
Built by Fractional HQ
Independent design and automation by Jessy Mariau. For setup or a custom integration, send a brief.
Output change, 8 September 2026
REVIEW_REQUIRED replaces LIKELY_NON_COMPLIANT for missing advertised pay. Update filters that used the old verdict. The pay and evidence fields keep their existing names. OK and ATTENTION remain text-review statuses, not legal conclusions.