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)logojakoImageObjectz width/height — Google wymaga czytelnego logo dla niektórych rich resultscontactPoint— telefon, email,areaServed,availableLanguagesameAs— 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:
- DevStudio.it →
https://devstudioit.com/{locale} - Blog →
https://devstudioit.com/{locale}/blog - 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,dateModifiedauthor(Person lub Organization z URL autora)publisherz logo OrganizationmainEntityOfPagewskazujący canonicalimage— absolutny URL OG (https://devstudioit.com/og-image-large.pnglub per-postogImage)inLanguage—pl-PL,en-US,de-DEwordCount— liczone z treści markdownspeakable— 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:
BreadcrumbListBlogPostingFAQPage(warunkowo, gdyfaqItems.length > 0)WebPagezmainEntitywskazują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
translationskeyed bypl | 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
- Wejdź na Rich Results Test.
- Podaj produkcyjny URL (np.
https://devstudioit.com/pl/blog/json-ld-schema-org-seo-strona-firmowa-2026). - Sprawdź wykryte typy: Article/BlogPosting, FAQ (jeśli jest), Breadcrumb.
- 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.parsetreści skryptu — jeden trailing comma psuje cały blok- Porównaj liczbę FAQ w DOM z
mainEntityw FAQPage
Typowe błędy na stronach firmowych
- Jeden Organization na całą domenę bez locale — gorszy sygnał dla DE/EN.
- Duplikat BlogPosting — plugin + ręczny skrypt = dwa
@type: BlogPostingz różnymi datami. - FAQPage bez widocznego FAQ — treść ukryta w
display:noneteż jest problemem. - Relatywne URL w
imageiitem— schema wymaga absolutnychhttps://. - author bez URL — Person z
urldo strony autora wzmacnia E-E-A-T. - dateModified zawsze = datePublished — aktualizacja treści bez zmiany
updatedw 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
- Homepage każdego locale — Rich Results Test: Organization + WebSite.
- Jeden artykuł blogu — BlogPosting + Breadcrumb + FAQ (jeśli jest).
- Jeden landing usługi — WebPage/Service.
- Search Console → URL Inspection → „Detected structured data”.
- Porównaj
dateModifiedw JSON-LD z polemupdatedw 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