Skip to content

Commit 7bfeaee

Browse files
committed
feat: publish new blog post on JSON-LD modeling
- Added a detailed walkthrough article titled "JSON+LD is geen SEO-truc, maar een modelleerprobleem." - Included various examples of JSON-LD structures for `Person`, `Organization`, `Podcast`, and related entities. - Highlighted lessons in structured data modeling and the importance of correct relationships and identifiers. - Added cover image with descriptive caption aligning with post themes.
1 parent 52a7c8e commit 7bfeaee

2 files changed

Lines changed: 305 additions & 0 deletions

File tree

61.8 KB
Loading
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
---
2+
title: "JSON+LD is geen SEO-truc, maar een modelleerprobleem"
3+
description: "JSON+LD dwingt je om expliciet na te denken over entiteiten, rollen en context. Geen snelle SEO-winst, wel een correct en toekomstvast model."
4+
summary: "Ik dacht dat JSON+LD draaide om zoekmachines. Het bleek vooral te gaan over verantwoordelijkheid, identiteit en nuance. Deze walkthrough laat zien waarom correcte modellering meer oplevert dan snelle optimalisatie."
5+
author: "Maarten"
6+
date: 2026-01-08
7+
lastmod: 2026-01-08
8+
slug: "202601-jsonld-is-geen-seo-truc"
9+
draft: false
10+
tags: ["json-ld", "schema-org", "webontwikkeling"]
11+
cover:
12+
image: "cover.webp"
13+
alt: "Conceptuele illustratie van verbonden entiteiten zoals een persoon, een podcast en een website, weergegeven als losse elementen die via lijnen met elkaar in relatie staan."
14+
caption: "JSON+LD als modelleerprobleem: niet de pagina staat centraal, maar de relaties tussen entiteiten."
15+
images: ["cover.webp"]
16+
---
17+
18+
Ik begon aan JSON+LD met een fout idee in mijn hoofd.
19+
Ik dacht dat het ging over zichtbaarheid, over zoekmachines helpen, over _"structured data toevoegen"_.
20+
Iets technisch, iets dat je er snel bijneemt.
21+
22+
Wat ik onderschat had, is dat JSON+LD je dwingt om expliciet te zijn over identiteit, rollen en context.
23+
Dingen die in tekst logisch aanvoelen, blijken plots vaag of zelfs fout wanneer je ze moet modelleren.
24+
25+
Deze post is geen checklist en geen quick win. Het is een walkthrough van hoe ik JSON+LD heb opgezet voor mijn persoonlijke blog [casteels.dev](https://casteels.dev "Bezoek mijn persoonlijke blog.") en voor de podcastsite [jcast.dev](https://jcast.dev "Bezoek de JCast podcastsite.").
26+
Inclusief de momenten waarop _"het bijna juist"_ bleek, maar toch niet klopte.
27+
28+
## Je beschrijft geen pagina’s, je beschrijft entiteiten
29+
30+
Het eerste inzicht dat alles veranderde, was eenvoudig maar confronterend:
31+
[schema.org](https://schema.org "Open de schema.org documentatie.") gaat niet over webpagina’s. Het gaat over **entiteiten** die los bestaan van waar je ze beschrijft.
32+
33+
* Een persoon bestaat los van zijn website.
34+
* Een podcast bestaat los van haar homepage.
35+
* Een aflevering of blogpost bestaat los van de HTML waarin ze staat.
36+
37+
Zodra je dat accepteert, kan je niet meer _"even wat JSON toevoegen"_. Je moet eerst beslissen wat je eigenlijk aan het beschrijven bent.
38+
39+
## Begin met jezelf, maar wees precies
40+
41+
Voor casteels.dev was dat nog relatief eenvoudig. Die site gaat over mij, dus ik begin met mezelf als `Person`.
42+
43+
```html
44+
<script type="application/ld+json">
45+
{
46+
"@context": "https://schema.org",
47+
"@type": "Person",
48+
"@id": "https://casteels.dev/#maarten-casteels",
49+
"name": "Maarten Casteels",
50+
"url": "https://casteels.dev"
51+
}
52+
</script>
53+
```
54+
55+
Die `@id` is geen detail. Dit is mijn vaste identiteit. Alles wat later over mij gaat, moet hiernaar verwijzen.
56+
Niet via naam, niet via tekst, maar via exact deze identifier.
57+
58+
Dit voelt overdreven, tot je meerdere sites begint te koppelen.
59+
60+
## De basisgraph voorkomt losse brokken
61+
62+
Losse entiteiten zijn nuttig, maar zonder basisgraph missen ze context. De combinatie van `Organization`, `WebSite` en `WebPage` zorgt dat alles aan je site hangt, en dat een pagina duidelijk maakt wie of wat er centraal staat.
63+
64+
```html
65+
<script type="application/ld+json">
66+
{
67+
"@context": "https://schema.org",
68+
"@graph": [
69+
{
70+
"@type": "Organization",
71+
"@id": "https://casteels.dev/#org",
72+
"name": "Maarten's Blog",
73+
"url": "https://casteels.dev/",
74+
"logo": {
75+
"@type": "ImageObject",
76+
"@id": "https://casteels.dev/#logo",
77+
"url": "https://casteels.dev/maarten.webp"
78+
}
79+
},
80+
{
81+
"@type": "WebSite",
82+
"@id": "https://casteels.dev/#website",
83+
"name": "Maarten's Blog",
84+
"url": "https://casteels.dev/",
85+
"publisher": { "@id": "https://casteels.dev/#org" }
86+
},
87+
{
88+
"@type": "WebPage",
89+
"@id": "https://casteels.dev/posts/202601-jsonld-is-geen-seo-truc/#webpage",
90+
"url": "https://casteels.dev/posts/202601-jsonld-is-geen-seo-truc/",
91+
"name": "JSON+LD is geen SEO-truc, maar een modelleerprobleem",
92+
"isPartOf": { "@id": "https://casteels.dev/#website" }
93+
},
94+
{
95+
"@type": "BlogPosting",
96+
"@id": "https://casteels.dev/posts/202601-jsonld-is-geen-seo-truc/#article",
97+
"headline": "JSON+LD is geen SEO-truc, maar een modelleerprobleem",
98+
"mainEntityOfPage": { "@id": "https://casteels.dev/posts/202601-jsonld-is-geen-seo-truc/#webpage" },
99+
"publisher": { "@id": "https://casteels.dev/#org" }
100+
}
101+
]
102+
}
103+
</script>
104+
```
105+
106+
Zo blijft elke entiteit herbruikbaar, maar ook netjes gelinkt aan de juiste pagina.
107+
108+
## sameAs is geen verzamelbak
109+
110+
Mijn eerste reflex was om alles te linken wat _"iets met mij te maken heeft"_. Sociale profielen, projecten, podcasts. Maar `sameAs` betekent iets heel strengs.
111+
112+
Het betekent niet _"gerelateerd aan"_.
113+
Het betekent _"beschrijft exact dezelfde entiteit"_.
114+
115+
Daarom is het belangrijk om `sameAs` alleen te gebruiken voor dingen die ook **zichtbaar en herkenbaar** zijn als jij op je website.
116+
Profielen waar iemand effectief jou ziet, met jouw naam, jouw identiteit.
117+
118+
Geen projecten waar je aan meewerkt.
119+
Geen sites waar je af en toe verschijnt.
120+
Geen _"handige"_ links om maar iets te linken.
121+
122+
Dat lijkt beperkend, maar het helpt zoekmachines net. Je geeft minder signalen, maar wel correcte.
123+
124+
## Lid zijn is iets anders dan hetzelfde zijn
125+
126+
Ik ben co-host van JCast, maar ik ben JCast niet. Dat onderscheid is cruciaal.
127+
128+
Wat ik wél correct kan zeggen, is dat ik lid ben van de organisatie achter de podcast. Dat modelleer je met `memberOf`, niet met `sameAs`.
129+
130+
```html
131+
<script type="application/ld+json">
132+
{
133+
"@context": "https://schema.org",
134+
"@type": "Person",
135+
"@id": "https://casteels.dev/#maarten-casteels",
136+
"name": "Maarten Casteels",
137+
"url": "https://casteels.dev",
138+
"memberOf": {
139+
"@id": "https://jcast.dev/#org"
140+
}
141+
}
142+
</script>
143+
```
144+
145+
Dit hoort thuis op mijn persoonlijke site, omdat ik daar de primaire entiteit ben. Ik beschrijf wie ik ben en waar ik deel van uitmaak.
146+
147+
## Maar een relatie werkt pas als beide kanten ze erkennen
148+
149+
Als je hier stopt, laat je iets onuitgesproken. JCast weet dan alleen wat ik er over zeg, niet wat het over zichzelf zegt.
150+
151+
Op jcast.dev moet de organisatie zichzelf beschrijven, los van mij.
152+
153+
```html
154+
<script type="application/ld+json">
155+
{
156+
"@context": "https://schema.org",
157+
"@type": "Organization",
158+
"@id": "https://jcast.dev/#org",
159+
"name": "JCast",
160+
"url": "https://jcast.dev/"
161+
}
162+
</script>
163+
```
164+
165+
En pas daarna zegt die organisatie wie erbij hoort.
166+
167+
```html
168+
<script type="application/ld+json">
169+
{
170+
"@context": "https://schema.org",
171+
"@type": "Organization",
172+
"@id": "https://jcast.dev/#org",
173+
"member": {
174+
"@type": "Person",
175+
"@id": "https://casteels.dev/#maarten-casteels",
176+
"name": "Maarten Casteels"
177+
}
178+
}
179+
</script>
180+
```
181+
182+
Dit voelt als duplicatie, maar dat is het niet. Elke site vertelt haar eigen waarheid, met gedeelde identifiers. Zo hoeven zoekmachines niets te raden.
183+
184+
## Een podcast is meer dan één ding
185+
186+
Tot hier ging het over mensen en organisaties. Maar een podcast zelf is ook een entiteit, en die leeft in lagen.
187+
188+
Op jcast.dev is het centrale concept de podcast als geheel. Dat modelleer je als `PodcastSeries`.
189+
190+
```html
191+
<script type="application/ld+json">
192+
{
193+
"@context": "https://schema.org",
194+
"@type": "PodcastSeries",
195+
"@id": "https://jcast.dev/#podcast",
196+
"name": "JCast",
197+
"url": "https://jcast.dev",
198+
"publisher": {
199+
"@id": "https://jcast.dev/#org"
200+
}
201+
}
202+
</script>
203+
```
204+
205+
Dit object beschrijft wat JCast is, los van afleveringen of seizoenen.
206+
207+
## Seizoenen geven structuur, geen versiering
208+
209+
Je kan afleveringen rechtstreeks aan een serie koppelen, maar zodra seizoenen betekenis hebben, loont het om die expliciet te maken.
210+
211+
```html
212+
<script type="application/ld+json">
213+
{
214+
"@context": "https://schema.org",
215+
"@type": "PodcastSeason",
216+
"@id": "https://jcast.dev/#season-2",
217+
"seasonNumber": 2,
218+
"name": "Season 2",
219+
"partOfSeries": {
220+
"@id": "https://jcast.dev/#podcast"
221+
}
222+
}
223+
</script>
224+
```
225+
226+
Een seizoen bestaat alleen binnen de context van een serie. Dat maak je hier expliciet.
227+
228+
## Afleveringen zijn waar alles samenkomt
229+
230+
Een `PodcastEpisode` is inhoud. Dit is wat mensen beluisteren, delen en terugvinden.
231+
232+
```html
233+
<script type="application/ld+json">
234+
{
235+
"@context": "https://schema.org",
236+
"@type": "PodcastEpisode",
237+
"@id": "https://jcast.dev/episodes/clean-code#episode",
238+
"name": "Clean Code in de praktijk",
239+
"episodeNumber": 3,
240+
"partOfSeason": {
241+
"@id": "https://jcast.dev/#season-2"
242+
},
243+
"partOfSeries": {
244+
"@id": "https://jcast.dev/#podcast"
245+
}
246+
}
247+
</script>
248+
```
249+
250+
De verwijzing naar zowel seizoen als serie lijkt redundant, maar maakt de aflevering zelfstandig begrijpbaar.
251+
252+
## Personen horen bij context, niet bij alles
253+
254+
Pas op het niveau van de aflevering koppel ik hosts of gasten.
255+
256+
```json
257+
"actor": {
258+
"@type": "Role",
259+
"roleName": "Host",
260+
"actor": {
261+
"@type": "Person",
262+
"@id": "https://casteels.dev/#maarten-casteels",
263+
"name": "Maarten Casteels"
264+
}
265+
}
266+
```
267+
268+
Ik ben hier geen publisher en geen eigenaar. Ik ben een stem in deze aflevering. Meer niet.
269+
270+
## Tools helpen, maar ze denken niet voor je
271+
272+
Tijdens dit proces heb ik veel gehad aan validatietools. Niet om het model te ontwerpen, wel om fouten te zien.
273+
274+
De [schema.org validator](https://validator.schema.org "Open de schema.org validator.") laat snel zien wat technisch klopt en wat niet.
275+
Browser add-ons zoals [OpenLink Structured Data Sniffer](https://osds.openlinksw.com/ "Open de OpenLink Structured Data Sniffer.") maken zichtbaar wat een pagina effectief uitzendt. Soms wat rommelig gepresenteerd, maar enorm verhelderend.
276+
277+
Wat deze tools niet doen, is beslissen of je model logisch is. Dat blijft jouw verantwoordelijkheid.
278+
279+
## De master setup is krachtig, maar niet magisch
280+
281+
Een gedeelde instruction file of _"master setup"_ kan veel werk versnellen, zeker wanneer je met AI werkt. Maar na de eerste run is menselijke correctie onmisbaar.
282+
Wie wil, kan mijn eigen instructiebestand bekijken of downloaden: [JSON+LD master instructions (raw)](https://raw.githubusercontent.com/denmette/denmette.github.io/refs/heads/main/ai/instructions/jsonld-master-instructions.md "Open het JSON+LD master-instructiebestand als raw bestand.").
283+
284+
Je person data mag oppervlakkig blijven. Dat is prima.
285+
Wat niet oppervlakkig mag zijn, zijn je identifiers en je relaties.
286+
287+
JSON+LD werkt niet omdat het volledig is.
288+
Het werkt omdat het consistent is.
289+
290+
291+
## Wat ik hieruit heb geleerd
292+
293+
JSON+LD loont pas wanneer je het ernstig neemt. Niet als SEO-hack, maar als expliciet model van je domein.
294+
295+
Je moet accepteren dat:
296+
297+
* niet alles gelinkt moet worden
298+
* minder vaak beter is
299+
* context belangrijker is dan volledigheid
300+
* een beetje herhaling geen fout is
301+
302+
Niet sneller.<br>
303+
Wel correct.
304+
305+
En achteraf bekeken was dat exact de investering die nodig was om dit goed te krijgen.

0 commit comments

Comments
 (0)