# Personio jobs scraper and vacancy change monitor

> Personio jobs scraper for public XML job boards. Save job rows or track new, changed and removed jobs between runs. Export JSON, CSV or Excel.

URL: https://cliqtomedia.com/actors/personio-jobs-monitor-scraper/

Category: Jobs & hiring · Status: live on Apify Store · Apify page: https://apify.com/cliqtomedia/personio-jobs-monitor-scraper?fpr=cliqto

Add the Personio board of a company you know. The tool reads its public XML feed. You get job rows, or only the jobs that are new, changed or removed.

## How to use it: 3 steps

1. **Make a free Apify account.** Apify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
2. **Paste your input and press Start.** No code needed: you fill in a form (the input). It already has a working example. For example: `teamative` in Personio board names or URLs. Each start is one run.
3. **Download the results.** When the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

## What it does

Watch known Personio boards for new, changed and removed jobs. This Personio jobs scraper reads public XML feeds and saves job rows or change events. It keeps the last complete board state when a check fails, so a failed check does not report every old job as removed.





## Price

Pay per event. Apify bills you, not us.

| What you pay for | Price | When |
|---|---|---|
| Complete board check | $0.018 | One complete successful Personio board check, including a valid empty feed. |
| Saved current job | $0.00045 | One unique saved baseline, new, changed or requested unchanged job from a complete board. Removed/failed/truncated results have no event fee. Platform usage may be charged separately as shown in Pricing. |

- One job: about $0.02.
- 1,000 jobs: about $0.47.
- Every day 100 jobs, for 30 days: about $1.89 a month.

Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed.

Prices checked on 24 October 2026. Current price: https://apify.com/cliqtomedia/personio-jobs-monitor-scraper?fpr=cliqto

## Questions

### Do I need a Personio account?

No. The tool reads known public XML boards only. It reads no applicant data.

### Can I use a job link or custom domain?

No. Use the board name or the Personio board or XML URL.

### Why does my first change run show every job?

There is no saved state yet. That first run becomes the baseline.

### What happens when a check fails?

The tool keeps the last complete state. Old jobs are not marked as removed.

### Does removed mean the company filled the job?

No. It means the ID disappeared from a complete accepted feed. The employer may have hidden, moved or removed the listing for another reason.

### Why is the first delta a baseline?

There is no prior complete board snapshot under this key and language. Later delta runs compare with the saved state. Changing the key starts a new comparison.

### Does snapshot mode affect my monitor?

Yes. A complete snapshot updates the selected state record. Use a separate key for an export that should not move your delta baseline.

### Is createdAt the job's last change date?

No. It is the source creation value. updatedAt remains null. changed events compare content; they do not supply an employer update timestamp.

### Are all fields always filled?

No. Null means the mapped value is absent or not safe to use. Empty arrays mean no values were supplied. Optional event timestamps can be absent. A job row with null source fields is different from a failed board fetch.

### Are repeated runs free if no jobs change?

No free-run promise is made. Source checks and state work still use platform resources. Check the Pricing tab and run usage.

## Data fields

- `_type` (string): Stable record type marker.
- `_schemaVersion` (string): Job record schema version.
- `_source` (string): Upstream source marker.
- `tenant` (string): Canonical Personio tenant slug.
- `jobId` (string): Stable upstream job identifier.
- `title` (string): Public job title.
- `publicUrl` (string): Canonical public job URL.
- `applyUrl` (string): Public application URL when supplied.
- `subcompany` (string): Public subcompany value when supplied.
- `office` (string): Primary public office value when supplied.
- `additionalOffices` (array): Additional public office values.
- `department` (string): Public department value when supplied.
- `recruitingCategory` (string): Public recruiting category when supplied.
- `employmentType` (string): Public employment type when supplied.
- `seniority` (string): Public seniority value when supplied.
- `schedule` (string): Public schedule value when supplied.
- `yearsOfExperience` (string): Public experience requirement when supplied.
- `keywords` (array): Normalized public keyword values.
- `occupation` (string): Public occupation value when supplied.
- `occupationCategory` (string): Public occupation category when supplied.
- `createdAt` (string): Public upstream creation timestamp when supplied.
- `descriptionSections` (array): Structured public description sections.
- `descriptionText` (string): Normalized public description text when supplied.
- `salaryInformation` (object): Public salary information when supplied.
- `eventType` (string): Delta event classification.
- `observedAt` (string): UTC observation timestamp.
- `changedFields` (array): Job fields that changed for a changed event.
- `contentHash` (string): Deterministic content hash used for comparisons.
- `previousObservedAt` (string): Previous observation timestamp for a changed event.
- `removedAt` (string): Removal observation timestamp for a removed event.
- `company` (string): Canonical tenant alias for existing consumers.
- `url` (string): Validated public job URL alias.
- `location` (string): Primary source office alias.
- `allLocations` (array): Unique source offices, primary first; null when absent.
- `postedAt` (string): UTC source creation timestamp when timezone is explicit; null otherwise.
- `commitment` (string): Source schedule with initial uppercase, compatible with the leader.
- `_scrapedAt` (string): UTC timestamp of this extraction, excluded from content hash.
- `team` (null): Not exposed as a dedicated source field; never inferred.
- `country` (null): Not exposed as a dedicated source field; never inferred.
- `workplaceType` (null): Not exposed as a dedicated source field; never inferred.

## Input settings

- `boards` (array, required): Use the tenant from a company public Personio careers board, such as teamative, or its exact board URL. Job titles/search words are not verified tenants. Unavailable or redirected XML feeds may fail the run.
- `language` (string): Language query parameter used for the public Personio XML board.
- `mode` (string): Use snapshot for your first export. Delta compares saved complete-board state and may return zero rows when nothing changed.
- `maxJobsPerBoard` (integer): Maximum number of positions accepted from each board before the board is marked incomplete.
- `maxBodyBytes` (integer): Maximum response body size accepted from one public XML request.
- `boardTimeoutMs` (integer): Limits the whole board fetch, including retries and waits. Keep 30000 first; a lower value can stop a slow board before all attempts.
- `maxAttempts` (integer): Maximum bounded request attempts per board, including the initial attempt.
- `stateKey` (string): Record key in named KVS personio-jobs-monitor-state. Keep one key per monitor; use a new key to start a fresh baseline. INPUT, OUTPUT, RUN_SUMMARY and STATE_SNAPSHOT are reserved.
- `includeUnchanged` (boolean): In delta mode, save a row for each job with unchanged core content. Ignored in snapshot mode. This can increase Dataset rows and usage.

## Step by step on Apify

1. Open the Actor you have access to in Apify Console, then open Input.
2. Switch to JSON input and paste the minimal example below. Use a tenant from the company public Personio careers board, such as `teamative`. A job title or search word such as `mediabuyer` is not a verified tenant.
3. Keep `language` as en and choose snapshot for this first check.
4. Click Start. Wait for the run to finish.
5. Open Output or the run's default Dataset. Check `tenant`, `jobId`, `title` and `eventType`.
6. Open the default Key-value store and read `RUN_SUMMARY`. Check each board's `status` and `complete`.

## Use cases

| Buyer task | Input | Key fields | Next step |
|---|---|---|---|
| Keep a current vacancy list | snapshot on known boards | tenant, jobId, title, publicUrl | Export JSON or CSV; replace your current list only from complete boards. |
| Track added or edited jobs | delta with a stable stateKey | eventType, changedFields, contentHash | Upsert by tenant + jobId in your database. |
| Mark a job as no longer listed | delta with complete source | removedAt, previousObservedAt, jobId | Archive the saved role; keep its last-known content. |
| Check locations and published pay | either mode | allLocations, salaryInformation | Filter these values in your own worksheet or application. |

## Tips

- A plain board name points to jobs.personio.de. Use a full URL for .com boards.
- Pick the job text language with the language setting, for example en or de.
- Use a separate state key for one-off exports. Your monitor baseline stays safe.

## Limits

Input safety caps are 50 boards, 5000 positions per board and 10 MiB per response. Real Cloud checks covered up to 22 current jobs across 3 boards at 256 MB. A local synthetic test accepted 5000 positions on one board. The local test is not a Cloud capacity or throughput guarantee. Start small and inspect the results for your source.



## Sample result

```json
{
  "_type": "job",
  "_schemaVersion": "1.0",
  "_source": "personio",
  "tenant": "teamative",
  "jobId": "2681315",
  "title": "Junior SAP Funkčný Konsultant – SAP CE / SAP IS-U",
  "publicUrl": "https://teamative.jobs.personio.de/job/2681315",
  "applyUrl": null,
  "subcompany": "teamative Slovakia s.r.o.",
  "office": "SK - Bratislava",
  "additionalOffices": [
    "SK - Košice"
  ],
  "department": "Delivery",
  "recruitingCategory": "SK - application process IT/SAP",
  "employmentType": "permanent",
  "seniority": "entry-level",
  "schedule": "full-time",
  "yearsOfExperience": "1-2",
  "keywords": [
    "SAP IS-U,SAP CE,ISU,CE,Junior"
  ],
  "occupation": "enterprise_software_implementation_consulting",
  "occupationCategory": "it_software",
  "createdAt": "2026-06-22T11:07:27+00:00",
  "descriptionSections": [],
  "descriptionText": null,
  "salaryInformation": {
    "minimum": 2000,
    "maximum": null,
    "currency": "EUR",
    "period": "monthly"
  },
  "company": "teamative",
  "url": "https://teamative.jobs.personio.de/job/2681315",
  "location": "SK - Bratislava",
  "allLocations": [
    "SK - Bratislava",
    "SK - Košice"
  ],
  "postedAt": "2026-06-22T11:07:27.000Z",
  "commitment": "Full-time",
  "team": null,
  "country": null,
  "workplaceType": null,
  "updatedAt": null,
  "observedAt": "2026-10-01T11:43:33.910Z",
  "contentHash": "6b6d47abef37ae0392319d40644adbbefd20f280ac210875376111463339dbfe",
  "_scrapedAt": "2026-10-01T11:43:33.910Z",
  "eventType": "baseline",
  "changedFields": []
}
```

## Use it from code

Actor ID: `cliqtomedia/personio-jobs-monitor-scraper`

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/personio-jobs-monitor-scraper").call(run_input={
    "boards": [
        "teamative"
    ],
    "language": "en"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

```bash
curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~personio-jobs-monitor-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"boards": ["teamative"], "language": "en"}'
```

```python
# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("cliqtomedia/personio-jobs-monitor-scraper")
result = tool.invoke({"run_input": {"boards": ["teamative"], "language": "en"}})
print(result)
```

run-sync waits up to 300 seconds; for longer runs start a run and use a webhook. LlamaIndex and MCP: https://cliqtomedia.com/actors/ai-agents/

## Use cases with this tool

- [Reach out when the company is ready](https://cliqtomedia.com/actors/use-cases/buying-signals/): Know when a company hires, raises money or wins a contract. Reach out at the right moment.

## Similar tools

- [Greenhouse Jobs Monitor & Scraper](https://cliqtomedia.com/actors/greenhouse-jobs-monitor-scraper/)
- [Lever Job Scraper](https://cliqtomedia.com/actors/lever-jobs-scraper/)
- [Wellfound Jobs Scraper](https://cliqtomedia.com/actors/wellfound-jobs-scraper/)
- [Ashby Jobs Scraper](https://cliqtomedia.com/actors/ashby-jobs-scraper/)
- [Recruitee Job Snapshots & Changes](https://cliqtomedia.com/actors/recruitee-jobs-monitor-scraper/)
- [SmartRecruiters Jobs Monitor & Scraper](https://cliqtomedia.com/actors/smartrecruiters-jobs-monitor-scraper/)
