Personio Jobs Scraper & API: Any Company Careers Page
Pricing
from $0.80 / 1,000 jobs
Personio Jobs Scraper & API: Any Company Careers Page
Scrape any company's Personio careers page: job title, office, department, employment type, seniority, schedule, salary band and full description. CSV/JSON.
Pricing
from $0.80 / 1,000 jobs
Rating
0.0
(0)
Developer
MRSLM Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Security
Limited permissionsShare
Open roles from any company's Personio careers page: office, department, employment type, seniority, schedule, salary band and full description. $1.00 per 1,000 jobs.
Personio is the leading HR system for German-speaking SMEs, so it is the best source for DACH hiring data.
Quick start
- Press Start. The form is already filled with this example input, so the first run returns real rows in under a minute:
{"companies": ["tado","https://1komma5grad.jobs.personio.de"],"maxJobsPerCompany": 20}
- Swap in your own values, or call the Actor through the Apify API, Make, Zapier, n8n or the Python/JS clients with the same JSON.
- Download the results as JSON, CSV or Excel from the Output tab, or schedule the run to repeat.
Full guide: How to Scrape Personio Job Listings from Any Company Careers Page (Real Run: 31 Jobs from 4 German Companies)
What the Personio Jobs Scraper does
You give the Actor a list of companies, either the board name (tado) or the careers page URL (https://1komma5grad.jobs.personio.de, .de or .com). For each one it reads the company's public Personio job feed, https://<company>.jobs.personio.de/xml?language=en, the same list the careers page shows, and saves one row per open role.
Each row has the platform, the board name and the company's display name, the job ID, title, department and team (Personio's recruiting category), the first office and all offices, employment type, seniority, schedule (full-time, part-time), years of experience, keywords, occupation and occupation category, the salary band when published (minimum, maximum, currency and period), the posting date, the job page and apply links, and the board URL. With Include description on, the full job description is added as plain text (up to 5,000 characters, with e-mail addresses and phone numbers removed).
You can filter by title words (include or exclude), location, department or team, remote, and posting date, sort newest first, and cap the jobs per company and per run. Nothing needs a login, and the Actor reads only public job ads.
Who it is for
- Recruiters and staffing agencies who want a daily list of new roles at target companies in DACH and Europe, including the ones that never reach LinkedIn.
- Sales teams that sell to companies that are hiring: a company opening five sales roles is growing; a company hiring its first Head of Finance is about to buy finance software.
- Job seekers and job board builders who want a clean feed of roles from a curated list of employers.
- Investors and analysts who track headcount plans of private companies through their open roles, departments and locations.
- HR and compensation teams who benchmark published salary bands.
Real example: open roles at four German companies
Say you track hiring at a handful of German scale-ups and want the newest roles from each, capped at 10 per company so one big employer does not drown the rest.
Step 1: Enter the input
Open the Personio Jobs Scraper in Apify Console, switch the input form to JSON and paste this. It is the exact input used for the run:
{"companies": ["tado","https://1komma5grad.jobs.personio.de","ottonova","chrono24"],"maxJobsPerCompany": 10,"newestFirst": true}
What each setting does:
companies: four boards.tado,ottonovaandchrono24are board names (the part before.jobs.personio.de); 1KOMMA5° is given as its full careers page URL, which works the same way. You can mix both styles in one list.maxJobsPerCompany:10, the most roles saved per company. 0 means all open roles.newestFirst:true(the default) sorts each company's jobs by posting date before the per-company cap is applied, so the cap keeps the newest roles.
The other inputs on the form:
titleKeywords: keep jobs whose title contains any of these words, for exampleengineerorsales.excludeTitleKeywordsdrops titles with any of these words, for exampleWerkstudentorintern.locationKeywords: keep jobs whose location contains any of these, for exampleBerlin,Münchenorremote.departmentKeywords: keep jobs whose department or team contains any of these, for exampleengineeringorfinance.remoteOnly: keep only remote jobs (see the note on remote below).postedWithinDays: keep only jobs posted in the last N days. 0 means any date.includeDescription: add the full description as plain text. Rows get much larger, so leave it off for lists.maxResults: a safety cap on jobs saved across the whole run, and so on cost.proxyConfiguration: usually not needed; the feeds are public.
Step 2: Run it
Press Start. The run finished with status SUCCEEDED in about 6 seconds and saved 31 rows. It was charged 31 job events plus the start event, $0.0311 on the Free/Bronze tier.
The run log shows what each board had open:
- tado (tado GmbH): 2 open roles, 2 saved.
- ottonova: 9 open roles, 9 saved.
- Chrono24 (Chrono24 GmbH): 12 open roles, 10 saved (the cap).
- 1KOMMA5° (1KOMMA5° GmbH): 311 open roles, 10 saved (the cap).
Only the saved rows are charged, so the 301 1KOMMA5° roles that the cap skipped cost nothing.
Step 3: Read the output
All 31 rows, cut to the most useful columns:
| company | title | department | location | employmentType | seniority | salary | postedAt |
|---|---|---|---|---|---|---|---|
| tado | Werkstudent:in Accounting (m/w/d) | Finance | Germany - Munich | intern | student | – | 2026-10-13 |
| tado | Team Lead Accounting (m/f/d) | Finance | Germany - Munich | permanent | experienced | 80,000–100,000 EUR/yearly | 2026-01-22 |
| ottonova | Senior Key Account Manager (m/w/d) - Partnervertrieb / Krank | B2B Sales | München | permanent | experienced | – | 2026-10-19 |
| ottonova | Werkstudent - Product Management / Health (m/w/d) | Product | München | intern | student | – | 2026-09-30 |
| ottonova | Quereinstieg Leistungssachbearbeitung (Zahn) als Medizinisch | Claims Management | München | permanent | experienced | – | 2026-09-28 |
| ottonova | Head of Finance & Controlling (m/w/d) | Finance | München | permanent | experienced | – | 2026-09-22 |
| ottonova | Key Account Manager/in, Maklerbetreuer/in Firmengeschäft für | B2B Sales | München | permanent | experienced | – | 2026-09-14 |
| ottonova | Werkstudent – Kommunikationsdesign (m/w/d) | Design | München | intern | student | – | 2026-09-10 |
| ottonova | Senior AI Engineer – Architecture & Platform (m/w/d) | Data & Analytics | München | permanent | experienced | – | 2026-06-29 |
| ottonova | (Senior) Aktuar (m/w/d) mit Schwerpunkt Solvency II (20h) (m | Risk Management & Actuary | München | permanent | experienced | – | 2026-03-23 |
| ottonova | Initiativ bewerben (m/w/d) | People & Culture | München | permanent | experienced | – | 2026-02-27 |
| chrono24 | Resolution Specialist (m/w/d) | Operations | Karlsruhe | temporary | experienced | 38,000–40,000 EUR/yearly | 2026-10-29 |
| chrono24 | Transfer Pricing Accountant (m/w/d) | Finance | Remote | permanent | experienced | – | 2026-10-08 |
| chrono24 | Prozessmanager Accounting – Schwerpunkt Automatisierung & KI | Finance | Karlsruhe | permanent | experienced | – | 2026-10-08 |
| chrono24 | Director of US Marketing | Marketing & Branding | New York City | permanent | experienced | – | 2026-10-05 |
| chrono24 | (Senior) Full Stack Engineer (Backend Focus) (m/f/d) | Product & Technology | Remote | permanent | experienced | – | 2026-10-05 |
| chrono24 | Complaint Specialist | Operations | Miami | permanent | experienced | – | 2026-10-01 |
| chrono24 | Customer Care Manager (1-year contract) | Operations | Japan | fixed-term | entry-level | – | 2026-08-10 |
| chrono24 | Customer Care Manager (1-year contract) | Operations | Hong Kong | fixed-term | entry-level | – | 2026-08-10 |
| chrono24 | AI Solution Engineer (m/f/d) | Data | Karlsruhe | permanent | experienced | – | 2026-07-30 |
| chrono24 | Android Developer (m/f/d) | Product & Technology | Remote | permanent | experienced | – | 2026-07-28 |
| 1komma5grad | Technische Betriebsleitung & Elektromeister / Elektroinstall | Elektronik & Technik | München | permanent | experienced | – | 2026-10-30 |
| 1komma5grad | Software Engineer - Edge & Cloud (m/f/d) | Tech | Remote | permanent | experienced | – | 2026-10-30 |
| 1komma5grad | Product Manager Energy Markets & Flexibility (m/f/d) | Tech | Remote | permanent | experienced | – | 2026-10-30 |
| 1komma5grad | Technischer Planer (m/w/d) Wärmepumpe - 1KOMMA5° Breidenbach | Planung & Projektmanagement | Breidenbach | permanent | experienced | – | 2026-10-30 |
| 1komma5grad | Werkstudent*in Vertrieb & Kundenbetreuung (m/w/d) – Erneuerb | Backoffice | Bremen | intern | entry-level | – | 2026-10-30 |
| 1komma5grad | Werkstudent (m/w/d) Auftragsmanagement - 1KOMMA5° Riederich | Auftragsmanagement | Riederich | working-student | student | – | 2026-10-29 |
| 1komma5grad | Management Trainee (m/w/d) – Future Leadership Program / 1KO | Commercial GmbH | Hamburg | trainee | entry-level | – | 2026-10-28 |
| 1komma5grad | Leitender Elektriker / Elektroniker (m/w/d) für gewerbliche | Elektronik & Technik | Frankfurt am Main | permanent | experienced | – | 2026-10-28 |
| 1komma5grad | Bauleiter für PV-Großanlagen, Batteriespeicher und Ladeinfra | Handwerk | Berlin | permanent | experienced | – | 2026-10-28 |
| 1komma5grad | Bauleiter für PV-Großanlagen, Batteriespeicher und Ladeinfra | Handwerk | Berlin | permanent | experienced | – | 2026-10-28 |
One full row as JSON:
{"platform": "Personio","company": "tado","companyName": "tado GmbH","jobId": "2502124","title": "Team Lead Accounting (m/f/d)","department": "Finance","team": "People & Culture","location": "Germany - Munich","locations": ["Germany - Munich"],"country": null,"workplaceType": null,"isRemote": null,"employmentType": "permanent","seniority": "experienced","salary": {"min": 80000,"max": 100000,"currency": "EUR","period": "yearly","text": null},"postedAt": "2026-01-22T09:48:25.000Z","updatedAt": null,"url": "https://tado.jobs.personio.de/job/2502124","applyUrl": "https://tado.jobs.personio.de/job/2502124#apply","schedule": "full-time","yearsOfExperience": "7-10","keywords": ["Accounting","Finance","Buchhaltung","general ledger","account payables","account receivables","financial reporting","IFRS","UGB","HGB","audit"],"occupation": "bookkeeping","occupationCategory": "accounting_and_finance","boardUrl": "https://tado.jobs.personio.de/"}
What the 31 real rows show:
- 1KOMMA5° is hiring at scale. 311 open roles, and all 10 newest were posted between 28 and 30 October 2026: site managers for large PV and battery projects in Berlin, electricians in Frankfurt, a heat pump planner in Breidenbach, software and product roles listed as Remote. The
teamfield shows which local business each role belongs to (for example "1K5° Commercial" or "1K5° Augsburg"), which reflects the company's network of regional installers. - Salary bands are rare but useful. 2 of 31 roles publish a band: tado's Team Lead Accounting in Munich at 80,000–100,000 EUR a year, and Chrono24's Resolution Specialist in Karlsruhe at 38,000–40,000 EUR a year. When a company does publish them, they are in a structured field, not buried in the text.
- Seniority and schedule are structured. Personio companies tag each role with
employmentType(permanent, temporary, fixed-term, intern, trainee, working-student),seniority(student, entry-level, experienced) andschedule(full-time, part-time, full-or-part-time). Filtering out working students is one column filter, not a keyword guess. - Chrono24 hires beyond Germany. Its 10 newest roles include a Director of US Marketing in New York City, a Complaint Specialist in Miami, and Customer Care Managers in Japan and Hong Kong, alongside Karlsruhe and Remote roles.
- Titles are often German. "Werkstudent", "Quereinstieg Leistungssachbearbeitung" and "Bauleiter" are typical. If you filter by title, include the German words (
Werkstudent,Entwickler,Vertrieb) as well as the English ones. - Occupation categories make cross-company counts easy.
occupationCategoryputs every role in a broad family such asaccounting_and_finance,it_softwareorsales_and_business_development; in this sample, finance and accounting roles appear at three of the four companies.
Finding a company's Personio board
Most companies link to their Personio careers page from the "Jobs" or "Karriere" page of their website; the address ends in .jobs.personio.de or .jobs.personio.com. The part before .jobs is the board name. If a name is wrong or the company has left Personio, the run reports that board as "not found" in the log and continues with the others, and nothing is charged for it.
A company's companyName comes from the feed and can be a legal entity or subsidiary name (for example "ottonova Krankenversicherung AG - 9698"), while company is always the board name you entered. Group by company when you count jobs per employer.
A note on remote jobs
Personio's feed has no separate remote flag, so for Personio rows isRemote and workplaceType are always empty (null). remoteOnly keeps a job when its location text contains the word "remote", as Chrono24's and 1KOMMA5°'s "Remote" roles do. Roles that are remote but list a city as the office will not match. For a looser filter, use locationKeywords: ["remote", "homeoffice"] and check the description.
Output fields
| Field | What it means | Example from this run |
|---|---|---|
platform | Always Personio. | Personio |
company / companyName | Board name you entered and the company name in the feed. | tado / tado GmbH |
jobId | Personio job ID. | 2502124 |
title | Job title as posted. | Team Lead Accounting (m/f/d) |
department / team | Department and Personio recruiting category. | Finance / People & Culture |
location / locations | First office and all offices. | Germany - Munich / ["Germany - Munich"] |
country / workplaceType / isRemote | Not in Personio feeds, always null. | null / null / null |
employmentType | permanent, temporary, fixed-term, intern, trainee, working-student and so on. | permanent |
seniority | student, entry-level, experienced and so on. | experienced |
schedule | full-time, part-time or full-or-part-time. | full-time |
yearsOfExperience | Required experience band, when given. | 7-10 |
salary | min, max, currency and period when the company publishes a band; otherwise null. | 80000 / 100000 / EUR / yearly |
keywords | Keywords the company tagged the job with. | Accounting, Finance, Buchhaltung, IFRS, HGB… |
occupation / occupationCategory | Personio occupation and broad category. | bookkeeping / accounting_and_finance |
postedAt / updatedAt | When the job was created; updatedAt is not in the feed (null). | 2026-01-22T09:48:25.000Z / null |
url / applyUrl / boardUrl | Job page, apply anchor and careers page. | https://tado.jobs.personio.de/job/2502124 |
description | Full description as plain text, only with includeDescription. | (off in this run) |
scrapedAt | When the row was read. | 2026-10-30T23:15:02.555Z |
Export Personio jobs to CSV, Excel or Google Sheets
Every run saves its rows to a dataset, and a dataset can be downloaded in any common format without code.
From Apify Console. Open the run, go to the Output tab and click Export. Pick CSV, Excel (XLSX), JSON, XML, HTML or RSS, and tick only the columns you want. Nested values such as lists and objects are flattened into columns like name/0 or object/field in CSV and Excel.
From a URL. The same export is a plain HTTPS link. Replace <DATASET_ID> with the dataset ID shown on the run's Storage tab:
# CSV with just the columns you needcurl -H "Authorization: Bearer $APIFY_TOKEN" \"https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=csv&clean=1&fields=company,companyName,title,department,location,employmentType,seniority,schedule,salary/min,salary/max,salary/currency,postedAt,url" -o personio-jobs.csv# Excelcurl -H "Authorization: Bearer $APIFY_TOKEN" \"https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=xlsx&clean=1" -o personio-jobs.xlsx
Into Google Sheets. Three options, from simplest to most automatic:
- One-off: download the CSV and use File > Import > Upload in Google Sheets. Choose "Replace current sheet" to refresh an existing tab.
- Automatic, no code: use Make, Zapier or n8n as described in the next section, ending in a Google Sheets "Add row" step.
- Formula:
=IMPORTDATA("https://api.apify.com/v2/actor-tasks/<USERNAME>~<TASK_NAME>/runs/last/dataset/items?status=SUCCEEDED&format=csv&token=<YOUR_TOKEN>")always pulls the latest successful run of a saved task. The token sits in the formula, so anyone who can open the sheet can see it. Only use this in a private sheet.
Use it from Make, Zapier or n8n
All three automation tools have an official Apify app, so you can run this Actor and pass its rows on without writing code.
- Trigger. Use a schedule in the automation tool, or Apify's "Watch Actor runs" / "Watch task runs" trigger if you already schedule the task in Apify.
- Run. Add the Apify "Run Actor" (or "Run task") action, choose
mrslm_data/personio-jobsand paste the JSON input from Step 1. Turn on "wait for finish" so the next step gets the data. - Get the rows. Add "Get dataset items" and map the run's default dataset ID from the previous step.
- Send them on. Add a Google Sheets "Add row" step for a hiring tracker, a HubSpot or Pipedrive step that tags the company as "hiring" when a sales or finance role appears, or a Slack message per new role with its title, location and link.
Each module only moves data; the Actor's pricing is the same as when you run it in Console.
Schedule a daily new-roles alert
Companies add and close roles every day. A daily run with postedWithinDays: 1 (or 2, to be safe across weekends) returns only roles created in the last one or two days, so each run is a short list of what is new (remove repeats by url if the windows overlap). Closed roles simply disappear from the feed.
- In the Actor's input form, set up the input from Step 1 and click Save as new task. Give it a clear name such as
personio-new-roles-daily. - Go to Schedules > Create new, set the cron expression to
0 8 * * 1-5and pick your timezone, so it runs at 8 AM every weekday. - Add the task to the schedule and save. Each run gets its own fresh dataset.
- Optional: on the task's Integrations tab, add a webhook, Slack or email notification for "Run succeeded", or connect Make, Zapier or n8n, so the new rows go where you need them.
To fetch the newest results without looking up a run ID, use the task's last-run link: https://api.apify.com/v2/actor-tasks/<USERNAME>~personio-new-roles-daily/runs/last/dataset/items?status=SUCCEEDED&format=json.
Call it from the API (Python, JavaScript or curl)
Start the Actor from your own code with the official Apify clients. Put your API token (Console > Settings > API & Integrations) in an environment variable called APIFY_TOKEN rather than in the code.
Python (pip install "apify-client>=3"):
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run_input = {"companies": ["tado","https://1komma5grad.jobs.personio.de","ottonova","chrono24"],"maxJobsPerCompany": 10,"newestFirst": true}run = client.actor("mrslm_data/personio-jobs").call(run_input=run_input)# apify-client 3.x returns a Run object, so use run.default_dataset_idfor item in client.dataset(run.default_dataset_id).iterate_items():print(item["company"], item["title"], item["location"], item["postedAt"])
In apify-client 3.x, call() returns a typed object. Older examples that use run["defaultDatasetId"] were written for 1.x and 2.x and fail in 3.x with TypeError: 'Run' object is not subscriptable.
JavaScript / Node.js (npm install apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const input = {"companies": ["tado","https://1komma5grad.jobs.personio.de","ottonova","chrono24"],"maxJobsPerCompany": 10,"newestFirst": true};const run = await client.actor('mrslm_data/personio-jobs').call(input);const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.length, items[0].title);
curl, one request that runs the Actor and returns the rows as CSV (it waits up to 5 minutes, so keep the input small):
curl -X POST "https://api.apify.com/v2/acts/mrslm_data~personio-jobs/run-sync-get-dataset-items?format=csv" \-H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \-d '{"companies": ["tado", "https://1komma5grad.jobs.personio.de", "ottonova", "chrono24"], "maxJobsPerCompany": 10, "newestFirst": true}' -o personio-jobs.csv
Use it from AI agents and chat assistants (MCP)
Apify runs a hosted Model Context Protocol (MCP) server, so assistants such as Claude Desktop, Cursor, VS Code or any other MCP client can call this Actor as a tool. Add this server URL to your MCP client and sign in with your Apify account (or send your API token as a Bearer header):
https://mcp.apify.com/?tools=mrslm_data/personio-jobs
The assistant then sees the Actor's input fields, can start a run with the input it builds from your request, and reads the dataset rows back. A prompt like this works well:
Using Personio, list the open engineering roles at tado, chrono24 and 1komma5grad posted in the last 14 days, with location and seniority.
Runs started through MCP are billed exactly like any other run, per row saved, so it is worth asking the assistant to set maxResults.
What it costs
The Actor uses pay-per-event pricing: one job event per role saved, and nothing for compute or for roles that your filters or caps skip.
Price per event
| Event (per 1,000) | Free / Bronze | Silver | Gold / Platinum / Diamond |
|---|---|---|---|
Job saved (job) | $1.00 | $0.90 | $0.80 |
| Actor start (once per run at the default memory, not per 1,000) | $0.00005 | $0.00005 | $0.00005 |
You are charged only for the events in this table: nothing for compute, and nothing for searches that return no rows beyond the start fee.
| Scenario | Free / Bronze | Silver | Gold |
|---|---|---|---|
| The run in this guide (31 jobs) | $0.0311 | $0.0280 | $0.0249 |
| Daily new-roles alert for 50 companies, ~20 new roles a day (22 runs a month) | $0.44 | $0.40 | $0.35 |
| Weekly full snapshot of 50 companies, ~1,000 roles (4 runs a month) | $4.00 | $3.60 | $3.20 |
| One-off: all 311 open roles at 1KOMMA5° | $0.3111 | $0.2800 | $0.2489 |
The daily and weekly rows are estimates; your counts depend on the companies you track. To cap spending, set Maximum cost per run in the run options (or maxTotalChargeUsd in the API), or use maxResults.
Tips
- Filter before you pay. Title, location, department and date filters run before rows are saved, so roles they drop are never charged.
- Exclude students in German too.
excludeTitleKeywords: ["Werkstudent", "Praktikum", "intern"]removes most student roles; or filter onseniority= student in your sheet. - Use
maxJobsPerCompanywithnewestFirst. It keeps the newest roles from each company, so big employers do not crowd out small ones. - Turn descriptions on only when you need them, for example to search for a technology or to feed an AI summariser.
- One run, many companies. Put all your boards in one task; the run reads each feed once.
Limits
- Only companies that use Personio and publish a public careers page. Other applicant tracking systems need their own Actor (see the FAQ).
- What you get is what the company publishes: salary bands, experience and keywords are optional in Personio, so many rows have them empty.
- Personio feeds have no country, remote flag or last-updated date, so those fields are null.
- Each run is a snapshot of open roles. Closed roles are not kept; save runs if you need history.
- Descriptions are cut at 5,000 characters.
FAQ
Where does the data come from? From each company's public Personio job feed, the same list of open roles the company shows on its careers page.
Do I need a Personio account? No. The feeds are public and need no login.
Does it include recruiter or applicant data? No. Only the public job ad. E-mail addresses and phone numbers in descriptions are removed.
How do I find a company's board name?
Open the company's careers page. If its address is <name>.jobs.personio.de or .com, use <name> or the full URL.
What happens if a board does not exist? The log says that board was not found, the other companies still run, and nothing is charged for the missing one.
Can I get jobs in English? The Actor asks the feed for English. Companies that write their ads only in German still return German titles and text.
Do you have other ATS platforms? Yes: Greenhouse Jobs, Lever Jobs and the multi-platform ATS Jobs scraper.
Does it work with Make, Zapier or n8n? Yes. All three have an Apify app. Use "Run Actor" (or run a saved task), then "Get dataset items" to pass the rows on to Google Sheets, Airtable, a CRM or Slack.
Can AI agents use it?
Yes, through Apify's MCP server at https://mcp.apify.com/?tools=mrslm_data/personio-jobs, as shown above.
Is it legal?
This Actor only reads pages and feeds that the website itself publishes to every visitor without a login. It obeys each site's robots.txt, keeps a polite request rate, and never tries to get past logins, paywalls, captchas or bot checks. It does not collect personal data such as emails, phone numbers or names of private individuals. You are responsible for how you use the data: follow the source site's terms, copyright and the privacy laws that apply to you (GDPR, CCPA, etc.). This tool is independent and not affiliated with or endorsed by the platforms it reads.