Personio Jobs Scraper & API: Any Company Careers Page avatar

Personio Jobs Scraper & API: Any Company Careers Page

Pricing

from $0.80 / 1,000 jobs

Go to Apify Store
Personio Jobs Scraper & API: Any Company Careers Page

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

MRSLM Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Categories

Security

Limited permissions

Share

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

  1. 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
}
  1. 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.
  2. 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, ottonova and chrono24 are 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 example engineer or sales. excludeTitleKeywords drops titles with any of these words, for example Werkstudent or intern.
  • locationKeywords: keep jobs whose location contains any of these, for example Berlin, München or remote.
  • departmentKeywords: keep jobs whose department or team contains any of these, for example engineering or finance.
  • 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:

companytitledepartmentlocationemploymentTypesenioritysalarypostedAt
tadoWerkstudent:in Accounting (m/w/d)FinanceGermany - Munichinternstudent–2026-10-13
tadoTeam Lead Accounting (m/f/d)FinanceGermany - Munichpermanentexperienced80,000–100,000 EUR/yearly2026-01-22
ottonovaSenior Key Account Manager (m/w/d) - Partnervertrieb / KrankB2B SalesMünchenpermanentexperienced–2026-10-19
ottonovaWerkstudent - Product Management / Health (m/w/d)ProductMüncheninternstudent–2026-09-30
ottonovaQuereinstieg Leistungssachbearbeitung (Zahn) als MedizinischClaims ManagementMünchenpermanentexperienced–2026-09-28
ottonovaHead of Finance & Controlling (m/w/d)FinanceMünchenpermanentexperienced–2026-09-22
ottonovaKey Account Manager/in, Maklerbetreuer/in Firmengeschäft fürB2B SalesMünchenpermanentexperienced–2026-09-14
ottonovaWerkstudent – Kommunikationsdesign (m/w/d)DesignMüncheninternstudent–2026-09-10
ottonovaSenior AI Engineer – Architecture & Platform (m/w/d)Data & AnalyticsMünchenpermanentexperienced–2026-06-29
ottonova(Senior) Aktuar (m/w/d) mit Schwerpunkt Solvency II (20h) (mRisk Management & ActuaryMünchenpermanentexperienced–2026-03-23
ottonovaInitiativ bewerben (m/w/d)People & CultureMünchenpermanentexperienced–2026-02-27
chrono24Resolution Specialist (m/w/d)OperationsKarlsruhetemporaryexperienced38,000–40,000 EUR/yearly2026-10-29
chrono24Transfer Pricing Accountant (m/w/d)FinanceRemotepermanentexperienced–2026-10-08
chrono24Prozessmanager Accounting – Schwerpunkt Automatisierung & KIFinanceKarlsruhepermanentexperienced–2026-10-08
chrono24Director of US MarketingMarketing & BrandingNew York Citypermanentexperienced–2026-10-05
chrono24(Senior) Full Stack Engineer (Backend Focus) (m/f/d)Product & TechnologyRemotepermanentexperienced–2026-10-05
chrono24Complaint SpecialistOperationsMiamipermanentexperienced–2026-10-01
chrono24Customer Care Manager (1-year contract)OperationsJapanfixed-termentry-level–2026-08-10
chrono24Customer Care Manager (1-year contract)OperationsHong Kongfixed-termentry-level–2026-08-10
chrono24AI Solution Engineer (m/f/d)DataKarlsruhepermanentexperienced–2026-07-30
chrono24Android Developer (m/f/d)Product & TechnologyRemotepermanentexperienced–2026-07-28
1komma5gradTechnische Betriebsleitung & Elektromeister / ElektroinstallElektronik & TechnikMünchenpermanentexperienced–2026-10-30
1komma5gradSoftware Engineer - Edge & Cloud (m/f/d)TechRemotepermanentexperienced–2026-10-30
1komma5gradProduct Manager Energy Markets & Flexibility (m/f/d)TechRemotepermanentexperienced–2026-10-30
1komma5gradTechnischer Planer (m/w/d) Wärmepumpe - 1KOMMA5° BreidenbachPlanung & ProjektmanagementBreidenbachpermanentexperienced–2026-10-30
1komma5gradWerkstudent*in Vertrieb & Kundenbetreuung (m/w/d) – ErneuerbBackofficeBremeninternentry-level–2026-10-30
1komma5gradWerkstudent (m/w/d) Auftragsmanagement - 1KOMMA5° RiederichAuftragsmanagementRiederichworking-studentstudent–2026-10-29
1komma5gradManagement Trainee (m/w/d) – Future Leadership Program / 1KOCommercial GmbHHamburgtraineeentry-level–2026-10-28
1komma5gradLeitender Elektriker / Elektroniker (m/w/d) für gewerblicheElektronik & TechnikFrankfurt am Mainpermanentexperienced–2026-10-28
1komma5gradBauleiter für PV-Großanlagen, Batteriespeicher und LadeinfraHandwerkBerlinpermanentexperienced–2026-10-28
1komma5gradBauleiter für PV-Großanlagen, Batteriespeicher und LadeinfraHandwerkBerlinpermanentexperienced–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 team field 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) and schedule (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. occupationCategory puts every role in a broad family such as accounting_and_finance, it_software or sales_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

FieldWhat it meansExample from this run
platformAlways Personio.Personio
company / companyNameBoard name you entered and the company name in the feed.tado / tado GmbH
jobIdPersonio job ID.2502124
titleJob title as posted.Team Lead Accounting (m/f/d)
department / teamDepartment and Personio recruiting category.Finance / People & Culture
location / locationsFirst office and all offices.Germany - Munich / ["Germany - Munich"]
country / workplaceType / isRemoteNot in Personio feeds, always null.null / null / null
employmentTypepermanent, temporary, fixed-term, intern, trainee, working-student and so on.permanent
senioritystudent, entry-level, experienced and so on.experienced
schedulefull-time, part-time or full-or-part-time.full-time
yearsOfExperienceRequired experience band, when given.7-10
salarymin, max, currency and period when the company publishes a band; otherwise null.80000 / 100000 / EUR / yearly
keywordsKeywords the company tagged the job with.Accounting, Finance, Buchhaltung, IFRS, HGB…
occupation / occupationCategoryPersonio occupation and broad category.bookkeeping / accounting_and_finance
postedAt / updatedAtWhen the job was created; updatedAt is not in the feed (null).2026-01-22T09:48:25.000Z / null
url / applyUrl / boardUrlJob page, apply anchor and careers page.https://tado.jobs.personio.de/job/2502124
descriptionFull description as plain text, only with includeDescription.(off in this run)
scrapedAtWhen 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 need
curl -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
# Excel
curl -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:

  1. One-off: download the CSV and use File > Import > Upload in Google Sheets. Choose "Replace current sheet" to refresh an existing tab.
  2. Automatic, no code: use Make, Zapier or n8n as described in the next section, ending in a Google Sheets "Add row" step.
  3. 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.

  1. 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.
  2. Run. Add the Apify "Run Actor" (or "Run task") action, choose mrslm_data/personio-jobs and paste the JSON input from Step 1. Turn on "wait for finish" so the next step gets the data.
  3. Get the rows. Add "Get dataset items" and map the run's default dataset ID from the previous step.
  4. 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.

  1. 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.
  2. Go to Schedules > Create new, set the cron expression to 0 8 * * 1-5 and pick your timezone, so it runs at 8 AM every weekday.
  3. Add the task to the schedule and save. Each run gets its own fresh dataset.
  4. 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 os
from apify_client import ApifyClient
client = 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_id
for 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 / BronzeSilverGold / 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.

ScenarioFree / BronzeSilverGold
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 on seniority = student in your sheet.
  • Use maxJobsPerCompany with newestFirst. 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.

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.