Ask a Question
Back to All

Access jobs/open positions xml CORS

I am trying to integrate on the company's website the open jobs listings. I wanted to have more control over the stylisation and fetch the job listings on the client side.

I have read through: https://developer.personio.de/docs/integration-of-open-positions and tried to modify the PHP sample into JS (see below). However I run into CORS issues.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://personio.de/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 308.

Is what I am trying to achieve possible, or must I gather the details server-side?

<script type="text/javascript" charset="utf-8">
const hostname = 'myaccountshostname';
// const lang = getLang(); // Replace this with your language retrieval logic
const lang = 'en'
const positionsURL = `https://${hostname}.jobs.personio.de/xml?language=${lang}`;

// const options = {method: 'GET', headers: {accept: 'application/xml'}};
  .then(response => response.text())
  .then(data => {
    const parser = new DOMParser();
    const xmlData = parser.parseFromString(data, 'text/xml');
    const positions = xmlData.getElementsByTagName('position');
    const jobs_loading_el = getElementById("jobs_loading_el");
    const categories = [];
    for (const position of positions) {
      const category = position.querySelector('recruitingCategory').textContent;
      if (category && !categories.includes(category)) {
    const translations = {
      "full-time": {
        "de": "Vollzeit",
        "en": "Full-time"
      "part-time": {
        "de": "Teilzeit",
        "en": "Part-time"
      "permanent": {
        "de": "Festanstellung",
        "en": "Permanent Employment"
      "intern": {
        "de": "Praktikum",
        "en": "Internship"
      "trainee": {
        "de": "Trainee Stelle",
        "en": "Trainee Position"
      "freelance": {
        "de": "Freelance Position",
        "en": "Freelance Position"
    const channel = new URLSearchParams(window.location.search).get('channel');
    const job_embed_container = document.getElementById('jobs_embed_block')
    // Print job postings
    // TODO
    // for (const category of categorise) {
    // const job_embed_element = document.getElementById('jobs_embed_block')

    // }
    for (const position of positions) {
      const positionName = position.querySelector('name').textContent;
      const employmentType = position.querySelector('employmentType').textContent;
      const schedule = position.querySelector('schedule').textContent;
      const detailLink = `https://${hostname}.jobs.personio.de/job/${position.getAttribute('id')}`;
      let detailLinkWithChannel = detailLink;
      if (channel) {
        detailLinkWithChannel += `?_pc=${channel}`;
      const jobDetailsHTML =
        `<div class="job-item">
<a href="${detailLinkWithChannel}" target="_blank" alt="Job Details">
<h3 class="job-title">${positionName}</h2>
<ul class="job-items">
<li class="job-dept"><span>Team:</span></li>
<li class="job-location"><span>Location</span></li>
<li class="job-date"><span>Creation date:</span></li>
<p class="job-info"><span class="job-type">${translations[employmentType][lang]}</span>, ${translations[schedule][lang]}</p>
<li class="job-code"><span>Code:</span></li>
      // Insert job details HTML into your desired element
      // For example:

      job_block = document.getElementById('jobs_embed_block').innetHTML()
  .catch(error => {
    console.error('Error fetching job positions:', error);