[ ENGINEERING_GUIDE ][ JSON-LD ][ SCHEMA.ORG ][ SEO ][ NEXTJS ]

JSON-LD i Schema.org — SEO strony firmowej w Next.js (przewodnik 2026)

10 czerwca 20269 min czytania
Autor: DevStudio.itStudio Web & AI

Organization, WebSite, BreadcrumbList, BlogPosting i FAQPage — implementacja w App Router, getStructuredData, hreflang i testy Rich Results dla wielojęzycznych stron usługowych.

READ_TIME: 9 MIN_COMPLEXITY: MED_
STAMP: VERIFIED_BY_DS_

TL;DR

JSON-LD to najprostszy sposób, by Google zrozumiał, że Twoja strona to firma usługowa z blogiem, a nie losowy zbiór divów. Na produkcyjnym Next.js 15 (App Router) wystarczą pięć typów: Organization i WebSite w layoucie (getStructuredData w src/lib/structured-data.ts), BreadcrumbList + BlogPosting na artykułach blogu, FAQPage gdy w markdown jest sekcja FAQ. Każda wersja językowa (/pl, /en, /de) musi mieć osobny JSON-LD z poprawnym inLanguage i hreflang w metadanych — nie jeden globalny blok po angielsku. Testuj w Rich Results Test i Search Console, nie tylko „czy skrypt jest w DOM”.

Dla kogo to jest

  • Firm usługowych z wielojęzyczną stroną na Next.js App Router
  • Developerów wdrażających SEO techniczne bez WordPressa i pluginów
  • Zespołów, które mają już meta title/description, ale brakuje im rich snippets i spójnej encji organizacji
  • Autorów blogu firmowego — chcesz, żeby artykuły miały poprawny BlogPosting, nie tylko og:article

Fraza (SEO)

json-ld schema.org strona firmowa, structured data nextjs 2026, organization website breadcrumblist blogposting, faqpage seo, rich results test google, hreflang json-ld

Dlaczego JSON-LD, a nie microdata w HTML

Google oficjalnie obsługuje trzy formaty: JSON-LD, Microdata i RDFa. W React/Next.js JSON-LD w <script type="application/ld+json"> wygrywa praktycznie zawsze:

Format Zalety Wady w Next.js
JSON-LD Oddzielone od JSX, łatwe generowanie z danych Wymaga walidacji (jeden błąd JSON = cały blok ignorowany)
Microdata „Widoczne” w HTML Mieszanie atrybutów z komponentami, trudny refactor
RDFa Rzadko używane Niska adopcja w ekosystemie React

JSON-LD nie zastępuje dobrego contentu — ale bez niego Google często nie wie, że DevStudio.it to ta sama firma co logo w stopce, a artykuł na /pl/blog/... to blog post, nie zwykła podstrona.

Pięć typów, które realnie pomagają stronie firmowej

1. Organization — encja firmy

Organization opisuje podmiot: nazwa, logo, kontakt, usługi, oferty. W projekcie DevStudio.it generuje go getStructuredData(locale) — funkcja w src/lib/structured-data.ts zwraca obiekt z @type: Organization, @id (https://devstudioit.com/#organization), contactPoint, sameAs, listą service i offers.

Kluczowe pola dla firmy usługowej:

  • @id — stabilny identyfikator; inne typy mogą się do niego odwoływać (publisher, provider)
  • logo jako ImageObject z width/height — Google wymaga czytelnego logo dla niektórych rich results
  • contactPoint — telefon, email, areaServed, availableLanguage
  • sameAs — LinkedIn, GitHub, Twitter — potwierdza tożsamość encji

Uwaga: aggregateRating w Organization jest często audytowany — jeśli nie masz realnych recenzji zgodnych z polityką Google, nie dodawaj ocen „na sztywno”. W tym repo recenzje idą osobnym blokiem getReviewStructuredData z testimonialów na stronie.

2. WebSite — witryna i SearchAction

WebSite łączy domenę z organizacją: name, url, inLanguage, publisher. Opcjonalnie potentialAction typu SearchAction — jeśli masz wyszukiwarkę (/search?q=).

W getStructuredData pole inLanguage zawiera ['pl', 'en', 'de'] — sygnał, że witryna jest wielojęzyczna. URL w WebSite wskazuje na wersję locale (https://devstudioit.com/pl itd.), nie tylko root domeny.

3. BreadcrumbList — ścieżka w wynikach wyszukiwania

BreadcrumbList to lista itemListElement z pozycjami 1…n. Na blogu w src/app/[locale]/blog/[slug]/page.tsx generujesz:

  1. DevStudio.it → https://devstudioit.com/{locale}
  2. Blog → https://devstudioit.com/{locale}/blog
  3. Tytuł artykułu → canonical URL posta

Każdy element ma @type: ListItem, position, name, item (pełny URL). Breadcrumbs w UI i JSON-LD powinny pokrywać tę samą hierarchię — rozjazd nie zawsze karze, ale utrudnia debug w Search Console.

4. BlogPosting — artykuł, nie WebPage

Dla wpisów blogowych używaj BlogPosting (lub Article), nie generycznego WebPage jako głównej encji. W kodzie articleJsonLd zawiera:

  • headline, description, datePublished, dateModified
  • author (Person lub Organization z URL autora)
  • publisher z logo Organization
  • mainEntityOfPage wskazujący canonical
  • image — absolutny URL OG (https://devstudioit.com/og-image-large.png lub per-post ogImage)
  • inLanguagepl-PL, en-US, de-DE
  • wordCount — liczone z treści markdown
  • speakable — opcjonalnie cssSelector dla asystentów głosowych

Canonical musi być identyczny z alternates.canonical w generateMetadata — ten sam string w JSON-LD i w <link rel="canonical">.

5. FAQPage — tylko gdy FAQ jest w treści

FAQPage w Google wymaga realnych pytań i odpowiedzi widocznych dla użytkownika. W tym projektu FAQ wyciąga getBlogFaq(post.content) z sekcii ## FAQ w markdown — każde ### Pytanie + akapit odpowiedzi.

Jeśli FAQ jest tylko w JSON-LD, a na stronie nie ma — ryzyko manual action za structured data spam. Zawsze: treść najpierw, JSON-LD drugie.

Implementacja w Next.js App Router

Layout locale — Organization + WebSite

W src/app/[locale]/layout.tsx po getStructuredData(locale) wstrzykujesz trzy skrypty JSON-LD:

<script
  type="application/ld+json"
  dangerouslySetInnerHTML={{
    __html: JSON.stringify(structuredData.organization),
  }}
/>
<script
  type="application/ld+json"
  dangerouslySetInnerHTML={{
    __html: JSON.stringify(structuredData.website),
  }}
/>

Dodatkowo hostingService jako Service i getReviewStructuredData z testimonialów — rozszerza encję firmy o konkretną ofertę hostingu.

Server Components — JSON-LD generujesz na serwerze; nie potrzeba useEffect. To ważne dla crawlers i dla pierwszego HTML z edge.

Strona blogu — wiele bloków JSON-LD

Na [slug]/page.tsx typowy zestaw to cztery skrypty:

  1. BreadcrumbList
  2. BlogPosting
  3. FAQPage (warunkowo, gdy faqItems.length > 0)
  4. WebPage z mainEntity wskazującym na #article

Wiele bloków jest poprawne — Google łączy encje przez @id i URL. Alternatywa: jeden @graph z wszystkimi typami; w Next.js często wygodniej emitować osobne <script>.

getStructuredData — jeden plik, trzy locale

src/lib/structured-data.ts trzyma tłumaczenia organization (services, offers, description) i buduje pełne obiekty schema.org. Wzorzec:

  • tablica translations keyed by pl | en | de
  • baseUrl = 'https://devstudioit.com'
  • URL locale: pl/pl, inne → /{locale}

Gdy dodajesz nową usługę na stronie — aktualizuj też structured data, żeby Google widział spójny katalog service z landing page.

hreflang i JSON-LD — dwa równoległe sygnały

hreflang żyje w metadanych HTML (alternates.languages w Next.js), nie w JSON-LD. Dla blogu getBlogPostHreflangLanguages łączy posty przez translationId w frontmatter — ten sam translationId we wszystkich trzech plikach markdown.

Sygnał Gdzie Co mówi Google
hreflang <link rel="alternate" hreflang="..."> „Ta treść ma odpowiednik w PL/EN/DE”
inLanguage w BlogPosting JSON-LD „Ten artykuł jest po polsku”
Canonical meta + JSON-LD mainEntityOfPage „Oficjalny URL tej wersji”

Błąd typu: hreflang wskazuje /en/blog/wrong-slug, a canonical i JSON-LD na inny slug — split sygnałów, często bez rich result, mimo poprawnego JSON.

Dla strony głównej firmowej upewnij się, że każdy locale ma Organization z URL https://devstudioit.com/{locale}, nie tylko angielski opis w JSON-LD na /pl.

Testowanie — Rich Results i poza nim

Google Rich Results Test

  1. Wejdź na Rich Results Test.
  2. Podaj produkcyjny URL (np. https://devstudioit.com/pl/blog/json-ld-schema-org-seo-strona-firmowa-2026).
  3. Sprawdź wykryte typy: Article/BlogPosting, FAQ (jeśli jest), Breadcrumb.
  4. Napraw błędy krytyczne (brak image, zły format daty).

Test pobiera renderowany HTML — działa na Vercel production. Preview URL często ma inne env i robots — do SEO structured data testuj devstudioit.com.

Schema Markup Validator (schema.org)

Walidator na schema.org sprawdza poprawność względem specyfikacji, nie tylko rich results Google. Przydatny przy skomplikowanym Organization z offers i shippingDetails.

Search Console

Po wdrożeniu: Enhancements → FAQ, Articles (jeśli kwalifikują). „Valid” nie gwarantuje wyświetlenia rich snippet — Google decyduje per query — ale „Error” zawsze wymaga naprawy.

DevTools — praktyczna checklist

  • View Source (nie tylko Elements) — JSON-LD musi być w pierwszym HTML
  • JSON.parse treści skryptu — jeden trailing comma psuje cały blok
  • Porównaj liczbę FAQ w DOM z mainEntity w FAQPage

Typowe błędy na stronach firmowych

  1. Jeden Organization na całą domenę bez locale — gorszy sygnał dla DE/EN.
  2. Duplikat BlogPosting — plugin + ręczny skrypt = dwa @type: BlogPosting z różnymi datami.
  3. FAQPage bez widocznego FAQ — treść ukryta w display:none też jest problemem.
  4. Relatywne URL w image i item — schema wymaga absolutnych https://.
  5. author bez URL — Person z url do strony autora wzmacnia E-E-A-T.
  6. dateModified zawsze = datePublished — aktualizacja treści bez zmiany updated w frontmatter to sygnał przestarzały.

Rozszerzenia — kiedy dodawać więcej typów

Typ Kiedy Uwaga
LocalBusiness Fizyczna lokal + mapa, NAP Wymaga adresu i godzin; nie mylić z Organization
Service Landing usługi (strony-www) Można per usługa z provider → Organization @id
HowTo Artykuły krok po kroku W repo: getHowToStructuredData na homepage
SoftwareApplication Produkty SaaS w portfolio Osobna funkcja w structured-data.ts

Nie dodawaj wszystkiego na każdej stronie — relevancy matters. Strona kontaktu ≠ Product, chyba że sprzedajesz produkt.

Wydajność i bezpieczeństwo

JSON-LD jest lekki (kilka–kilkadziesiąt KB). Nie ładuj go z zewnętrznego API w runtime — generuj statycznie przy SSG/ISR. dangerouslySetInnerHTML jest tu zamierzone; dane pochodzą z Twojego kodu, nie z user input na blogu (frontmatter jest w repo).

Dla bardzo dużych Organization z dziesiątkami offers rozważ skrócenie listy do top ofert — mniejszy HTML, ten sam sygnał biznesowy.

JSON-LD na stronach usługowych (landing pages)

Oprócz blogu warto emitować structured data na landingach typu /pl/strony-www. Minimum: WebPage z about wskazującym na Service lub Organization @id. Jeśli landing opisuje konkretną usługę z ceną „od X zł”, Offer z priceCurrency i provider wzmacnia sygnał lokalnego SEO usługowego — bez konieczności fałszywego LocalBusiness, gdy firma działa remote-first.

W getStructuredData lista service w Organization powinna pokrywać te same usługi co menu nawigacji. Rozjazd „w menu chatboty, w JSON-LD tylko strony WWW” to utracona spójność encji. Przy wdrożeniu nowego landinga: (1) treść + meta, (2) hreflang jeśli wielojęzyczny, (3) JSON-LD Service lub link z WebPage do globalnej Organization.

Audyt structured data — 15 minut przed launch

  1. Homepage każdego locale — Rich Results Test: Organization + WebSite.
  2. Jeden artykuł blogu — BlogPosting + Breadcrumb + FAQ (jeśli jest).
  3. Jeden landing usługi — WebPage/Service.
  4. Search Console → URL Inspection → „Detected structured data”.
  5. Porównaj dateModified w JSON-LD z polem updated w frontmatter po edycji treści.

Zapisz wyniki w ticketu deploy — ułatwia rollback decyzji „czy SEO zepsuliśmy w tym PR”.

FAQ

Czy Google zawsze pokaże gwiazdki i FAQ w wynikach?

Nie. Structured data to kwalifikacja, nie gwarancja UI. FAQ rich results Google ograniczał w ostatnich latach — nadal warto mieć poprawny FAQPage dla AEO i alternatywnych formatów, ale nie oczekuj magicznego skoku CTR.

Jeden skrypt JSON-LD czy wiele?

Oba OK. Google łączy encje. W Next.js wiele <script type="application/ld+json"> jest czytelniejsze przy warunkowym FAQPage.

Czy JSON-LD musi być w <head>?

Google czyta JSON-LD w head i body. App Router często renderuje skrypty w komponencie strony — działa, jeśli są w SSR HTML.

Jak powiązać BlogPosting z Organization?

Użyj publisher: { '@type': 'Organization', name: '...', logo: ... } i globalne @id Organization. Opcjonalnie isPartOf: { '@type': 'WebSite', '@id': '...' }.

Czy hreflang zastępuje tłumaczenie JSON-LD?

Nie. hreflang łączy URL wersji językowych; JSON-LD opisuje treść pod jednym URL. Potrzebujesz obu.

Podsumowanie

SEO strony firmowej w 2026 to warstwa encji (Organization, WebSite) plus per-page typy (BreadcrumbList, BlogPosting, FAQPage). W Next.js App Router trzymaj generatory w src/lib/structured-data.ts i w page.tsx blogu, zsynchronizuj canonical, hreflang i inLanguage, testuj na produkcji Rich Results Testem. Bez widocznej treści FAQ nie emituj FAQPage — structured data wspiera marketing, nie zastępuje uczciwego contentu.

Chcesz wdrożyć structured data u siebie?

  • Skontaktuj się — audyt JSON-LD i hreflang pod Twoją domenę
  • Strony WWW — Next.js, SEO techniczne i rich results od pierwszego wdrożenia
  • Blog — więcej przewodników o wydajności i konwersji

O autorze

Budujemy szybkie strony WWW, aplikacje web/mobile, chatboty AI i hosting — z naciskiem na SEO i konwersję.

Przydatne linki

Od teorii do produkcji — Branchly, hosting, opieka i realizacje.

PODOBA CI SIĘ NASZA ARCHITEKTURA MYŚLENIA? ZBUDUJMY COŚ RAZEM.

[ ROZPOCZNIJ_KONFIGURACJĘ_PROJEKTU ]