JobPosting-Schema: Wo deutsche Stellenanzeigen scheitern

JobPosting-Schema: Wo deutsche Stellenanzeigen scheitern

Wer eine Stellenanzeige mit JobPosting-Schema markiert und trotzdem nicht in Google for Jobs auftaucht, hat fast nie ein fehlendes Pflichtfeld übersehen. title, description, datePosted und hiringOrganization sind meist da, weil sie sich fast mechanisch aus dem CMS füllen lassen. Gescheitert wird an etwas Kleinerem: employmentType bekommt einen deutschen Freitext statt eines der festen Google-Werte, baseSalary wird flach statt verschachtelt geschrieben, jobLocation zeigt nur den Hauptsitz für eine Stelle, die an vierzig Filialen offen ist, oder eine Remote-Position ist als telecommute markiert, ohne dass Google weiß, aus welchem Land Bewerber überhaupt kommen dürfen.

Dieser Beitrag geht genau diese vier Stellen durch, weil sie in deutschen Stellenanzeigen am häufigsten falsch gesetzt sind. Was nach der Veröffentlichung mit einer Anzeige passiert, wie lange sie sichtbar bleibt und wie man eine besetzte Stelle sauber entfernt, ist ein eigenes Thema mit eigenen Regeln (validThrough, die Wahl zwischen 404 und 410) und wird hier bewusst nicht wiederholt. Es geht ausschließlich um die Felder, die darüber entscheiden, ob eine Anzeige überhaupt und korrekt aufgenommen wird.

employmentType: feste Werte statt deutscher Freitexte

employmentType ist keine Textbeschreibung, sondern ein Aufzählungstyp mit einer festen Liste erlaubter Werte. Google akzeptiert FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM und OTHER, und nichts davon lässt sich frei erfinden. Der häufigste Fehler in deutschen Feeds ist simpel: Ein CMS trägt direkt "Vollzeit" oder "40 Std./Woche" in das Feld ein, weil das für Menschen lesbar ist. Google erkennt diesen String nicht als gültigen Wert und die Stelle wird für die entsprechende Filterfunktion in Google for Jobs schlicht ignoriert, selbst wenn der Rest der Anzeige einwandfrei ist.

Schwieriger wird es bei Beschäftigungsformen, die im deutschen Arbeitsmarkt üblich sind, aber keine eigene Entsprechung im Schema haben. Für eine Werkstudentenstelle gibt es keinen Werkstudent-Wert; je nach Stundenumfang ist PART_TIME die naheliegende Zuordnung, ergänzt um eine klare Beschreibung im description-Feld, die den Status ausbuchstabiert. Eine duale Ausbildung landet mangels eigenem Enum-Wert am ehesten bei OTHER, wieder mit der Erklärung im Fließtext, weil das Enum die Nuance nicht abbilden kann und auch nicht abbilden soll. Ein Minijob ist in der Regel PART_TIME, unabhängig davon, dass die geringfügige Beschäftigung steuerlich eine eigene Kategorie ist; das Schema kennt nur den zeitlichen Umfang, keine steuerrechtliche Einordnung.

Wo eine Stelle wirklich zu mehreren Kategorien passt, etwa ein befristeter Vertrag mit Option auf Übernahme, erlaubt das Schema mehrere Werte im selben Feld als Array. Das ist der korrekte Weg, zwei zutreffende Eigenschaften abzubilden, nicht ein einzelner kombinierter String wie "Vollzeit, befristet", den Google als einen einzigen, ungültigen Wert liest.

Der Testtool-Bericht macht diesen Fehler außerdem nicht immer sichtbar. Ein ungültiger employmentType-String wird in der Regel nicht als roter Fehler markiert, sondern schlicht ignoriert, weil das Feld selbst optional ist; die Anzeige besteht die Prüfung, verliert aber unbemerkt ihre Filterbarkeit nach Beschäftigungsart. Wer nur auf die Fehleranzahl im Testtool schaut, hält eine Anzeige für vollständig, obwohl der Wert im Hintergrund verworfen wurde. Ein kurzer manueller Blick in das gerenderte JSON-LD, ob dort tatsächlich einer der Enum-Werte in Großbuchstaben steht und kein deutscher Satz, ersetzt diese blinde Stelle zuverlässig.

  • FULL_TIME und PART_TIME: der Stundenumfang, nicht die Vertragsdauer
  • CONTRACTOR: Freelance- und Werkvertragsrollen ohne Anstellungsverhältnis
  • TEMPORARY: befristete Anstellung, unabhängig vom Stundenumfang
  • INTERN: Praktikum; für duale Ausbildung meist ungeeignet, dort eher OTHER
  • OTHER: der Auffangwert für alles ohne eigene Kategorie, immer mit erklärendem Text in description

baseSalary: die Verschachtelung, an der Feeds am häufigsten scheitern

baseSalary ist kein einzelnes Feld, sondern eine dreistufige Struktur. Ganz außen steht ein MonetaryAmount mit der Währung, hier fast immer EUR. Darin steckt ein value, das wiederum ein eigenständiges Objekt vom Typ QuantitativeValue ist und entweder einen festen value-Betrag trägt oder minValue und maxValue für eine Spanne, dazu unitText mit HOUR, MONTH oder YEAR. Wer diese Verschachtelung falsch herum baut, etwa die Währung in das QuantitativeValue statt in das äußere MonetaryAmount schreibt, oder minValue und maxValue direkt auf oberster Ebene ablegt, produziert ein Objekt, das zwar valides JSON-LD ist, aber nicht die Struktur, die Google für baseSalary erwartet, und das Feld wird beim Parsen verworfen.

Der zweithäufigste Fehler ist ein Bruch zwischen unitText und den tatsächlichen Zahlen. Eine Spanne von 48000 bis 58000 mit unitText YEAR ist ein Jahresgehalt und plausibel. Dieselben Zahlen mit unitText MONTH behauptet ein Monatsgehalt von fast 50.000 Euro, was offensichtlich falsch ist und in der Regel daher kommt, dass die Jahreszahl aus dem Text kopiert wurde, während das Unit-Feld beim letzten Kampagnen-Update auf den Standardwert des CMS zurückgesetzt wurde. Diese Inkonsistenz wird in Testtools nicht immer als Fehler markiert, weil das JSON-LD formal korrekt bleibt; sie fällt erst auf, wenn die Anzeige mit einem absurden Gehalt in der gefilterten Suche erscheint.

Die Gehaltsangabe ist von Google aus nicht verpflichtend, wird aber zunehmend zu einer Angabe, die Unternehmen ohnehin machen müssen. Die EU-Richtlinie (EU) 2023/970 zur Entgelttransparenz verpflichtet die Mitgliedstaaten, Regelungen zu erlassen, nach denen Arbeitgeber Bewerbern ein Einstiegsgehalt oder eine Gehaltsspanne offenlegen, spätestens vor dem ersten Vorstellungsgespräch. Die Frist zur nationalen Umsetzung dieser Richtlinie lief am 7. Juni 2026 ab. Für die Praxis heißt das: Die Zahl, die ohnehin offengelegt werden muss, lässt sich in baseSalary strukturieren, statt sie nur als Text in der Stellenbeschreibung stehen zu lassen, wo sie für gefilterte Suchen nicht auswertbar ist.

Wo tatsächlich noch keine feste Spanne feststeht, etwa weil das Gehalt individuell verhandelt wird, ist die ehrlichere Lösung, baseSalary vollständig wegzulassen, statt einen Platzhalter wie 0 oder eine bewusst irreführend niedrige minValue einzutragen, nur damit das Feld formal befüllt ist. Ein Platzhalterwert wird von Google als reale Zahl gelesen und in der gehaltsgefilterten Suche genauso angezeigt wie eine echte Angabe; die Anzeige taucht dann für ein Gehalt auf, das niemand tatsächlich zahlt, was Bewerbererwartungen von Anfang an falsch setzt. Ein fehlendes baseSalary kostet Sichtbarkeit in einem Filter, ein falsches kostet Vertrauen in die Anzeige selbst, sobald die Diskrepanz im Gespräch auffällt.

jobLocation bei mehreren Standorten

Eine Filialleitung, die an vierzig Standorten gleichzeitig ausgeschrieben ist, braucht nicht vierzig Seiten und nicht vierzig JobPosting-Objekte. jobLocation akzeptiert ein Array von Place-Einträgen, und das ist die korrekte Struktur für eine Rolle, die an mehreren Adressen zugleich offen ist: ein JobPosting, eine Beschreibung, dafür mehrere Orte. Jeder Eintrag im Array braucht eine vollständige PostalAddress mit streetAddress, postalCode, addressLocality und addressCountry; eine Liste, die nur Städtenamen ohne Adressobjekt enthält, wird von Google nicht zuverlässig als gültige Standortangabe erkannt.

Der Fehler, der bei dezentralen Arbeitgebern am häufigsten vorkommt, ist die umgekehrte Vereinfachung: jobLocation zeigt nur die Zentrale, weil die Anzeige im CMS an der Unternehmensadresse hängt, obwohl die Stelle tatsächlich in der Fläche besetzt wird. Damit taucht die Anzeige in der ortsbezogenen Suche nur an einem einzigen Ort auf, während sie an vierzig anderen unsichtbar bleibt, obwohl der Text der Anzeige explizit von mehreren Standorten spricht. Die andere Richtung, für jeden Standort eine separate, fast identische Seite anzulegen, löst das Sichtbarkeitsproblem zwar, multipliziert aber jede der oben genannten Fehlerquellen um die Zahl der Standorte und macht Pflege bei jeder Änderung an Gehalt oder Beschäftigungsart entsprechend aufwendiger.

Wo eine Stelle bundesweit ohne festen Standort ausgeschrieben ist, etwa im Außendienst mit wechselndem Gebiet, ist eine grobe Ortsangabe wie nur "Deutschland" ohne addressRegion oder addressLocality technisch zulässig, aber wenig hilfreich für lokale Filterung. Wo sich das Einsatzgebiet eingrenzen lässt, etwa auf ein Bundesland oder eine Region, lohnt sich die genauere Angabe, weil sie die Anzeige in genau den lokalen Suchen ausspielbar macht, in denen Bewerber tatsächlich suchen.

Ein Sonderfall ist der Arbeitgeber, der zwar juristisch nur eine einzige eingetragene Adresse hat, dessen Mitarbeitende aber verteilt an Kundenstandorten arbeiten, etwa bei IT-Dienstleistern oder im Facility Management. Hier in jobLocation ausschließlich die Firmenadresse einzutragen ist zwar formal korrekt, weil es die einzige feste Adresse ist, beschreibt aber nicht, wo die Arbeit tatsächlich stattfindet. Wenn sich die Einsatzorte eingrenzen lassen, etwa auf bestimmte Regionen, in denen Kundenprojekte laufen, gehört diese Information ins jobLocation-Array; wenn nicht, ist die Firmenadresse zusammen mit einer klaren Beschreibung des Reise- oder Einsatzmusters im Text die ehrlichste verfügbare Lösung.

  • jobLocation als Array, ein Place-Objekt pro tatsächlichem Standort
  • Jedes Place-Objekt mit vollständiger PostalAddress, nicht nur einem Städtenamen
  • Keine Duplizierung der ganzen Anzeige pro Stadt, wenn ein Array genügt
  • Bei großflächigem Einsatzgebiet: so genau wie möglich, nicht pauschal nur das Land

Remote und Hybrid: der Unterschied, den Google prüft

jobLocationType mit dem Wert TELECOMMUTE markiert eine Stelle als vollständig ortsunabhängig. Allein reicht dieser Wert Google nicht: Zusammen mit TELECOMMUTE verlangt Google applicantLocationRequirements, eine Angabe darüber, aus welchem Land oder welchen Ländern sich Bewerber befinden dürfen. Fehlt applicantLocationRequirements, wird die gesamte Anzeige als nicht förderfähig für den Rich-Ergebnis-Eintrag behandelt, selbst wenn title, description, datePosted und hiringOrganization tadellos sind. Das ist einer der Fälle, in denen eine auf den ersten Blick vollständige Anzeige aus einem einzigen, leicht zu übersehenden Grund komplett aus Google for Jobs verschwindet.

Im deutschen Sprachgebrauch wird "Homeoffice möglich" häufig mit "remote" gleichgesetzt, ist strukturell aber meist etwas anderes. Eine Stelle mit gelegentlichem oder tageweisem Homeoffice ist keine telecommute-Stelle; sie hat weiterhin einen realen Arbeitsort, an dem die Präsenztage stattfinden, und genau dieser Ort gehört in ein normales jobLocation-Objekt mit vollständiger Adresse. TELECOMMUTE ist für Rollen reserviert, die grundsätzlich ohne festen Büroanwesenheitszwang auskommen. Eine hybride Stelle, die versehentlich als telecommute markiert wird, weil das im internen Sprachgebrauch als "flexibel" durchgeht, wird Bewerbern angezeigt, die eigentlich keinen realistischen Zugriff auf die Präsenztage haben, was zu Fehlbewerbungen führt und dem eigentlichen Zweck der Markierung widerspricht.

applicantLocationRequirements wird als Country-Objekt angegeben, meist mit dem Namen oder dem ISO-Ländercode. Für eine Stelle, die nur Bewerber mit Wohnsitz in Deutschland zulässt, reicht ein einzelnes Country-Objekt; steht die Stelle für den gesamten deutschsprachigen Raum offen, lässt sich das Feld als Array mit mehreren Country-Einträgen füllen. Wichtig ist, dass diese Angabe die tatsächliche arbeitsrechtliche oder steuerliche Realität widerspiegelt und nicht großzügiger formuliert wird, als die Anstellung es tatsächlich erlaubt.

Wenn die Anzeige aus einem Bewerbermanagementsystem kommt

Die wenigsten JobPosting-Fehler entstehen, weil jemand JSON-LD von Hand schreibt. In der Praxis stammt die Struktur meist aus einem Bewerbermanagementsystem oder Recruiting-Feed, der aus Formularfeldern automatisch Markup generiert, und die vier Fehlerquellen aus diesem Beitrag sind dann fast immer Abbildungsfehler zwischen dem, was eine Personalabteilung in ein Dropdown oder Freitextfeld einträgt, und dem, was das System daraus für employmentType, baseSalary oder jobLocation erzeugt.

Ein typisches Muster: Das System bietet im Formular ein Dropdown mit unternehmensinternen Bezeichnungen wie "Festanstellung", "Werkstudent" oder "Aushilfe" an, und irgendwo in der Konfiguration liegt eine Zuordnungstabelle, die diese Begriffe auf die Google-Enum-Werte abbildet. Wird diese Tabelle beim Anlegen einer neuen, unternehmensspezifischen Kategorie nicht gepflegt, bekommt die neue Kategorie keinen gültigen employmentType zugewiesen, sondern entweder gar keinen oder den zuletzt verwendeten Standardwert der Vorlage. Das Ergebnis sieht in der Vorschau des Systems unauffällig aus, weil der interne Name korrekt angezeigt wird, obwohl das ausgespielte Schema etwas anderes oder gar nichts enthält.

Dieselbe Lücke betrifft baseSalary und jobLocation, sobald ein Standort oder eine Gehaltsstufe neu angelegt wird, ohne dass jemand prüft, ob die zugehörige Adress- oder Währungszuordnung tatsächlich existiert. Wer für eine der vier Fehlerquellen aus diesem Beitrag eine Ursache im eigenen Content sucht und keine findet, sollte als Nächstes die Zuordnungstabelle des Feed-Systems prüfen, nicht die einzelne Anzeige; ein einziger falsch konfigurierter Mapping-Eintrag reproduziert denselben Fehler über sämtliche Anzeigen hinweg, die diese Kategorie verwenden.

Wie sich diese Fehler von Warnungen unterscheiden

Die Google Search Console und der Rich-Suchergebnisse-Test unterscheiden zwischen Fehlern, die eine Anzeige komplett aus Google for Jobs entfernen, und Warnungen, die sie zwar zulassen, aber in ihrer Auffindbarkeit einschränken. Ein fehlendes Pflichtfeld wie title oder hiringOrganization ist ein Fehler und blockiert die Anzeige vollständig. Ein fehlendes employmentType oder baseSalary erscheint dagegen meist nur als Warnung, weil beide Felder offiziell empfohlen und nicht vorgeschrieben sind, die Anzeige also grundsätzlich erscheint, aber aus den gefilterten Suchen herausfällt, in denen Bewerber gezielt nach Vollzeitstellen oder einem Gehaltsrahmen suchen.

Ein falsch gesetztes applicantLocationRequirements bei TELECOMMUTE dagegen wirkt wie ein Fehler, obwohl es sich um zwei formal getrennte Felder handelt, weil Google die Kombination als Einheit prüft. Wer im Testtool nur nach fehlenden Pflichtfeldern sucht und findet, dass alle vorhanden sind, übersieht diesen Fall regelmäßig, weil kein einzelnes Feld als fehlend markiert wird. Es lohnt sich deshalb, bei Remote-Stellen gezielt die Kombination aus jobLocationType und applicantLocationRequirements zu prüfen, statt sich auf die allgemeine Fehlerliste zu verlassen.

Kurzcheck vor der Veröffentlichung

Die vier Bereiche aus diesem Beitrag lassen sich vor jeder Veröffentlichung in wenigen Minuten durchgehen, unabhängig vom CMS oder Feed-System, aus dem die Anzeige stammt.

  • employmentType: einer der festen Enum-Werte, nicht Freitext; bei Doppelnatur ein Array statt eines kombinierten Strings
  • baseSalary: MonetaryAmount außen mit currency, QuantitativeValue innen mit value oder minValue/maxValue und passendem unitText
  • jobLocation: ein Array von Place-Objekten mit vollständiger PostalAddress für jeden tatsächlichen Standort, nicht nur die Zentrale
  • TELECOMMUTE niemals ohne applicantLocationRequirements; hybride Stellen behalten ein reales jobLocation und bekommen keinen TELECOMMUTE-Wert
  • Bei Remote-Stellen gezielt die Kombination aus Standort- und Ortsanforderungsfeldern prüfen, nicht nur die allgemeine Fehlerliste

Häufige Fragen

Kann employmentType mehrere Werte gleichzeitig enthalten?

Ja, das Feld akzeptiert ein Array, wenn eine Stelle tatsächlich zu mehreren Kategorien passt, etwa eine befristete Vollzeitstelle mit Option auf Übernahme. Ein einzelner kombinierter String wie "Vollzeit, befristet" ist dagegen kein gültiger Wert und wird von Google nicht als employmentType erkannt.

Ist eine Gehaltsangabe in baseSalary Pflicht für die Aufnahme in Google for Jobs?

Nein, baseSalary ist wie employmentType offiziell empfohlen, nicht vorgeschrieben; ihr Fehlen verhindert die Aufnahme nicht. Es schränkt aber die Sichtbarkeit in gehaltsgefilterten Suchen ein, und da viele Arbeitgeber eine Gehaltsspanne aufgrund der EU-Entgelttransparenzvorgaben ohnehin offenlegen müssen, lässt sich dieselbe Zahl direkt strukturiert einsetzen.

Warum wird eine Remote-Stelle trotz vollständiger Beschreibung nicht angezeigt?

Der häufigste Grund ist ein fehlendes applicantLocationRequirements neben jobLocationType TELECOMMUTE. Google verlangt beide Angaben gemeinsam, weil der Ortstyp allein nicht sagt, aus welchen Ländern Bewerber kommen dürfen; ohne diese Ergänzung gilt die gesamte Anzeige als nicht förderfähig.

Braucht ein Arbeitgeber mit vielen Filialen für jeden Standort eine eigene Stellenanzeige-Seite?

Nein, ein einzelnes JobPosting mit einem jobLocation-Array aus mehreren Place-Objekten deckt eine Rolle ab, die an mehreren Standorten gleichzeitig offen ist. Separate, fast identische Seiten pro Stadt lösen kein technisches Problem, sondern vervielfachen nur die Pflege und die Fehlerquellen der übrigen Felder.

Gehört die Frage, wann eine besetzte Stelle entfernt wird, auch zu diesem Thema?

Das ist eine eigene Frage der Anzeigen-Lebensdauer mit eigenen Mechanismen wie validThrough und der Wahl zwischen einem 404- und einem 410-Status beim Entfernen, unabhängig von der Feldkorrektheit einer aktiven Anzeige. Dieser Beitrag behandelt ausschließlich die Felder, die über die Aufnahme entscheiden, nicht die Frage, wie lange eine Anzeige danach sichtbar bleibt.

Aktualisiert: 13 Oktober 2026

Alle Artikel