TL;DR
JSON-LD ist der einfachste Weg, Google mitzuteilen, dass Ihre Site ein Dienstleister mit Blog ist — nicht ein zufälliger Haufen von Divs. Auf produktivem Next.js 15 (App Router) reichen fünf Typen: Organization und WebSite im Locale-Layout (getStructuredData in src/lib/structured-data.ts), BreadcrumbList + BlogPosting auf Blogartikeln und FAQPage, wenn im Markdown eine FAQ-Sektion steht. Jede Sprachversion (/pl, /en, /de) braucht eigenes JSON-LD mit korrektem inLanguage und hreflang in den Metadaten — kein globaler englischer Block. Testen mit Rich Results Test und Search Console, nicht nur „Skript im DOM?“.
Für wen das ist
- Dienstleistungsunternehmen mit mehrsprachiger Next.js App Router-Website
- Entwickler, die technisches SEO ohne WordPress-Plugins umsetzen
- Teams mit Meta Title/Description, aber ohne Rich Snippets und konsistente Organisation-Entität
- Corporate-Blog-Autoren, die echtes BlogPosting wollen, nicht nur
og:article
Keywords (SEO)
json-ld schema.org unternehmenswebsite, structured data nextjs 2026, organization website breadcrumblist blogposting, faqpage seo, google rich results test, hreflang json-ld
Warum JSON-LD, nicht Microdata im HTML
Google unterstützt offiziell drei Formate: JSON-LD, Microdata und RDFa. In React/Next.js gewinnt fast immer JSON-LD in <script type="application/ld+json">:
| Format | Vorteile | Nachteile in Next.js |
|---|---|---|
| JSON-LD | Getrennt vom JSX, einfach aus Daten | Ein JSON-Fehler = ganzer Block ignoriert |
| Microdata | „Sichtbar“ im HTML | Attribute in Komponenten, Refactoring schwer |
| RDFa | Selten | Geringe Adoption im React-Ökosystem |
JSON-LD ersetzt keinen guten Content — ohne JSON-LD erkennt Google oft nicht, dass DevStudio.it dieselbe Firma wie das Footer-Logo ist oder dass /de/blog/... ein Blogpost ist.
Fünf Typen, die Unternehmensseiten wirklich helfen
1. Organization — die Firmenentität
Organization beschreibt den wirtschaftlichen Auftritt: Name, Logo, Kontakt, Services, Angebote. Im DevStudio.it-Projekt liefert getStructuredData(locale) in src/lib/structured-data.ts ein Objekt mit @type: Organization, @id (https://devstudioit.com/#organization), contactPoint, sameAs, service-Liste und offers.
Wichtige Felder für Dienstleister:
@id— stabile ID; andere Typen verweisen darauf (publisher,provider)logoalsImageObjectmit width/heightcontactPoint— Telefon, E-Mail,areaServed,availableLanguagesameAs— LinkedIn, GitHub, Twitter
Hinweis: aggregateRating bei Organization wird oft geprüft — ohne echte Bewertungen laut Google-Richtlinie keine Sterne „hardcoded“. Im Repo kommen Reviews über getReviewStructuredData aus Testimonials auf der Seite.
2. WebSite — Website und SearchAction
WebSite verbindet Domain und Organisation: name, url, inLanguage, publisher. Optional SearchAction über potentialAction bei Suche (/search?q=).
In getStructuredData enthält inLanguage ['pl', 'en', 'de']. Die WebSite-url zeigt auf die Locale-Root (https://devstudioit.com/de, etc.).
3. BreadcrumbList — Pfad in Suchergebnissen
BreadcrumbList ist eine itemListElement-Liste 1…n. Im Blog baut src/app/[locale]/blog/[slug]/page.tsx:
- DevStudio.it →
https://devstudioit.com/{locale} - Blog →
https://devstudioit.com/{locale}/blog - Artikeltitel → Canonical des Posts
Jedes Element: @type: ListItem, position, name, item (volle URL). UI-Breadcrumbs und JSON-LD sollten dieselbe Hierarchie haben.
4. BlogPosting — Artikel, nicht generische WebPage
Für Blogposts BlogPosting (oder Article), nicht nur WebPage. articleJsonLd enthält:
headline,description,datePublished,dateModifiedauthor(Person oder Organization mit Autor-URL)publishermit Organization-LogomainEntityOfPage→ Canonicalimage— absolute OG-URLinLanguage—pl-PL,en-US,de-DEwordCountaus Markdown- optional
speakable
Canonical muss identisch zu alternates.canonical in generateMetadata sein.
5. FAQPage — nur mit FAQ im Content
Google FAQPage verlangt echte Fragen und Antworten sichtbar für Nutzer. Hier parst getBlogFaq(post.content) die ## FAQ-Sektion — jedes ### Frage plus Antwortabsatz.
FAQ nur in JSON-LD ohne Seiteninhalt riskiert Manual Action wegen Structured-Data-Spam. Immer: Content zuerst, JSON-LD danach.
Implementierung in Next.js App Router
Locale-Layout — Organization + WebSite
In src/app/[locale]/layout.tsx nach getStructuredData(locale):
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(structuredData.organization),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(structuredData.website),
}}
/>Zusätzlich hostingService als Service und getReviewStructuredData aus Testimonials.
Server Components — JSON-LD serverseitig, kein useEffect. Wichtig für Crawler und erstes HTML vom Edge.
Blog-Post — mehrere JSON-LD-Blöcke
Auf [slug]/page.tsx typisch vier Skripte:
BreadcrumbListBlogPostingFAQPage(wennfaqItems.length > 0)WebPagemitmainEntity→#article
Mehrere Blöcke sind korrekt — Google verknüpft über @id und URL. Alternative: ein @graph; in Next.js sind separate <script> oft klarer.
getStructuredData — eine Datei, drei Locales
src/lib/structured-data.ts hält organization-Übersetzungen und baut vollständige schema.org-Objekte:
translationsfürpl | en | debaseUrl = 'https://devstudioit.com'- Locale-URL:
pl→/pl, sonst/{locale}
Neue Service auf der Marketing-Site → structured data mitaktualisieren.
hreflang und JSON-LD — parallele Signale
hreflang steht in HTML-Metadaten (alternates.languages), nicht in JSON-LD. Für den Blog verknüpft getBlogPostHreflangLanguages Posts über translationId im Frontmatter — gleiche translationId in allen drei Markdown-Dateien.
| Signal | Ort | Botschaft an Google |
|---|---|---|
| hreflang | <link rel="alternate" hreflang="..."> |
„Diese Inhalte haben PL/EN/DE-Pendants“ |
inLanguage in BlogPosting |
JSON-LD | „Dieser Artikel ist deutsch“ |
| Canonical | Meta + JSON-LD mainEntityOfPage |
„Offizielle URL dieser Version“ |
Fehler: hreflang zeigt /de/blog/falscher-slug, Canonical und JSON-LD einen anderen — geteilte Signale, oft kein Rich Result.
Für die Firmenhomepage: jedes Locale mit Organization-url https://devstudioit.com/{locale}.
Testen — Rich Results und mehr
Google Rich Results Test
- Rich Results Test öffnen.
- Produktions-URL eingeben (z. B.
https://devstudioit.com/de/blog/json-ld-schema-org-seo-strona-firmowa-2026). - Typen prüfen: Article/BlogPosting, FAQ, Breadcrumb.
- Kritische Fehler beheben.
Test liest gerendertes HTML — funktioniert auf Vercel Production. Preview-URLs oft andere env/robots — Structured Data auf devstudioit.com testen.
Schema Markup Validator (schema.org)
Prüft Spec-Konformität, nicht nur Google Rich Results. Hilfreich bei komplexem Organization mit offers.
Search Console
Nach Deploy: Enhancements → FAQ, Articles. „Valid“ ≠ garantiertes Rich-Snippet-UI — „Error“ immer fixen.
DevTools — Checkliste
- View Source — JSON-LD im ersten HTML
JSON.parsedes Skripts — trailing comma bricht alles- FAQ-Zahl im DOM vs. FAQPage
mainEntity
Typische Fehler auf Unternehmensseiten
- Eine Organization ohne Locale — schwächeres Signal für DE/EN.
- Doppeltes BlogPosting — Plugin + manuelles Skript.
- FAQPage ohne sichtbare FAQ — auch
display:noneproblematisch. - Relative URLs in
imageunditem— absolutehttps://nötig. - author ohne URL — Person mit
urlstärkt E-E-A-T. - dateModified = datePublished immer —
updatedim Frontmatter vergessen.
Erweiterungen — wann mehr Typen
| Typ | Wann | Hinweis |
|---|---|---|
| LocalBusiness | Standort + Karte, NAP | Adresse und Öffnungszeiten |
| Service | Service-Landing | provider → Organization @id |
| HowTo | Schritt-für-Schritt | getHowToStructuredData auf Homepage |
| SoftwareApplication | SaaS im Portfolio | eigene Funktion in structured-data.ts |
Nicht alles auf jeder Seite — Relevanz zählt.
Performance und Sicherheit
JSON-LD ist leicht (wenige bis einige Dutzend KB). Nicht von externer API zur Laufzeit laden — statisch mit SSG/ISR generieren. dangerouslySetInnerHTML ist hier beabsichtigt; Daten stammen aus eigenem Code, nicht aus User Input (Frontmatter liegt im Repo).
Sehr große Organization mit vielen offers — Liste auf Top-Angebote kürzen: kleineres HTML, gleiches Business-Signal.
JSON-LD auf Service-Landingpages
Neben dem Blog structured data auf Landings wie /de/strony-www ausgeben. Minimum: WebPage mit about auf Service oder Organization @id. Beschreibt die Landing eine Dienstleistung mit Preis „ab X €“, verstärkt Offer mit priceCurrency und provider das Service-SEO — ohne falsches LocalBusiness bei remote-first Firmen.
In getStructuredData soll die service-Liste in Organization dieselben Leistungen abdecken wie die Navigation. Widerspruch („Chatbots im Menü, nur Websites in JSON-LD“) schwächt die Entität. Bei neuem Landing: (1) Content + Meta, (2) hreflang bei Mehrsprachigkeit, (3) Service-JSON-LD oder WebPage-Link zur globalen Organization.
Implementierungsdetails in page.tsx (Blog)
Die Blog-Seite src/app/[locale]/blog/[slug]/page.tsx berechnet wordCount aus Markdown-Body — dieses Feld erscheint im BlogPosting-JSON-LD und hilft Suchmaschinen die Tiefe des Artikels einzuschätzen. speakable mit cssSelector auf .blog-content h2, h3, p ist optional für Sprachassistenten; es schadet nicht, wenn die Selektoren im gerenderten HTML existieren.
faqJsonLd wird nur erzeugt, wenn getBlogFaq Einträge liefert — leeres FAQ im Markdown bedeutet kein FAQPage-Skript. Das verhindert leere mainEntity-Arrays, die Validator-Warnungen erzeugen.
webPageJsonLd ergänzt BlogPosting: die Seite ist WebPage, die Hauptentität ist der Artikel unter #article. Diese Trennung ist gängig in Next.js-Projekten und entspricht Google-Empfehlungen für Artikel-URLs.
hreflang im Blog — translationId praktisch
Jeder Post in content/blog/{locale}/ hat Frontmatter translationId — identisch über PL/EN/DE für Übersetzungen. getBlogPostHreflangLanguages baut die Map pl, en, de → absolute URLs. Fehlt eine Sprachversion, hreflang für diese Locale fehlt — kein erfundener Link.
Beim Anlegen eines neuen Artikels: zuerst translationId festlegen, dann drei Markdown-Dateien mit gleichem ID — JSON-LD und hreflang bleiben synchron ohne manuelle URL-Listen.
Rich Results Test — Schritt-für-Schritt
- Produktions-URL einfügen (nicht localhost, nicht Preview ohne Index).
- „Test URL“ — Google fetcht gerendertes HTML von Vercel Edge.
- Prüfen: Artikel (BlogPosting), FAQ (falls Sektion), Breadcrumbs.
- Warnungen lesen: „optional field missing“ oft OK; „invalid object“ immer fixen.
- Nach Deploy erneut testen — ISR/SSG kann ersten Fetch verzögern.
Schema.org Validator parallel: strenger bei nested offers in Organization (wie in structured-data.ts). Fehler dort können Rich Results trotzdem passieren — beide Tools nutzen.
Typische Fehler im Detail
Doppeltes @id: Zwei Organization-Blöcke mit gleichem @id aber unterschiedlichen name — Google kann Entität verwerfen. Eine Quelle: getStructuredData.
image nur relative Pfad: /og-image-large.png in JSON-LD ohne https://devstudioit.com — Rich Results Test markiert als Fehler. Im Code immer absolute URLs wie in articleJsonLd.
FAQ nur auf Englisch in JSON-LD, UI auf Deutsch — Policy-Risiko. FAQPage-Text muss der sichtbaren Sprache der Seite entsprechen (inLanguage konsistent).
Structured-Data-Audit vor Launch (15 Min.)
- Homepage je Locale — Organization + WebSite.
- Ein Blogartikel — BlogPosting, Breadcrumb, FAQ.
- Ein Service-Landing — WebPage/Service.
- Search Console URL Inspection.
dateModifiedvs Frontmatterupdatednach Content-Edit.
Ergebnisse im Deploy-Ticket speichern — erleichtert „SEO durch diesen PR kaputt?“.
Zusammenspiel mit Open Graph und Twitter Cards
JSON-LD ergänzt — nicht ersetzt — openGraph und twitter in generateMetadata auf Blog-Posts. OG liefert Social-Preview; BlogPosting liefert Such-Signale. ogImage im Frontmatter sollte dieselbe absolute URL wie image in BlogPosting verwenden (post.ogImage oder Fallback /og-image-large.png). Inkonsistente Bilder verwirren QA, obwohl Google oft nur JSON-LD für Rich Results nutzt.
FAQ
Zeigt Google immer Sterne und FAQ?
Nein. Structured Data = Berechtigung, keine UI-Garantie. FAQ Rich Results sind eingeschränkt — korrektes FAQPage trotzdem sinnvoll für AEO.
Ein Skript oder mehrere?
Beides OK. In Next.js mehrere <script type="application/ld+json"> bei bedingtem FAQPage klarer.
JSON-LD nur im <head>?
Google liest JSON-LD in head und body. App Router rendert oft in Page-Komponenten — OK bei SSR.
BlogPosting mit Organization verknüpfen?
publisher: { '@type': 'Organization', ... } und globale Organization @id. Optional isPartOf: WebSite.
Ersetzt hreflang übersetztes JSON-LD?
Nein. hreflang verknüpft URLs; JSON-LD beschreibt Inhalt unter einer URL. Beides nötig.
Zusammenfassung
Unternehmens-SEO 2026: Entitätsschicht (Organization, WebSite) plus per-page Typen (BreadcrumbList, BlogPosting, FAQPage). In Next.js App Router Generatoren in src/lib/structured-data.ts und Blog-page.tsx, Canonical, hreflang und inLanguage synchron, auf Produktion mit Rich Results Test prüfen. Ohne sichtbares FAQ kein FAQPage — Structured Data unterstützt Marketing, ersetzt keinen ehrlichen Content.