Schema.org: Describing Your Page to Google with Data, Not Words
A search engine reads the text on your page, but it has to guess at the question “is this a service, a post, or a person?” JSON-LD removes that guesswork entirely. Here is which types I use and why, how I validate the markup, and the traps I fall into most often.
After delivering a client site I opened Search Console, and the “Enhancements” tab was completely empty. The page had services on it, an address, opening hours — all written out properly. But to Google they were just text. There is a world of difference between “Monday–Friday 09:00–18:00” sitting inside a <p> tag and the machine-readable version of that same sentence.
Structured data closes that gap. Without changing anything the visitor sees, you add a separate layer that tells the page “I am an entity of this type, and I have these properties.” I do this with JSON-LD, and the site you are reading right now has exactly the same thing.
Why JSON-LD and not Microdata
There are three ways to embed Schema.org in a page: Microdata (sprinkling itemprop attributes across your HTML tags), RDFa, and JSON-LD (a separate <script> block). I tried all three, and after the second project I never used anything but JSON-LD. The reasons are simple:
- Markup and content stay separate. When you change the design or remove a
div, the schema does not break. In Microdata, deleting a wrapper silently drops every property inside it. - You can read it in one place. Reviewing the schema does not mean scanning the whole page; it is a single block.
- It is easy to generate on the server. My pages come out of a generator script, and I print the schema from the same data, so I never have to update two places by hand.
- It is the format Google recommends. It reads the others too, but the documentation gives its examples in JSON-LD.
Let me say this up front, because it gets misunderstood constantly: adding schema does not push you up the results. What it does is let you take up more space in the search result and make sure what your content actually is gets understood correctly. Star ratings, an expandable FAQ list, a recipe card, a job posting box — those change your click-through rate. Ranking is decided by content and technical health.
The types that actually pay off in practice
Schema.org has more than eight hundred types. The ones I really use barely go past the fingers on one hand. Across the sites I have delivered, this is the split that settled in:
| Type | Where I use it | What it buys you |
|---|---|---|
LocalBusiness | Business sites with a physical address | Address, phone and opening hours in maps and the knowledge panel |
Organization / Person | Corporate sites / personal portfolio | Recognition as a brand or a person, account matching through sameAs |
BlogPosting | Every blog post | Author, date, category; news and article presentation |
BreadcrumbList | All subpages | A readable path in the result instead of a bare URL |
FAQPage | Pages that genuinely have an FAQ section | An expandable question list under the result |
SoftwareApplication | App landing pages | Platform, category, store link |
Service | Service pages | The name and scope of the service offered |
How a post page gets marked up
The <head> section of the page you are reading right now holds a block like this:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Schema.org: Google'a Sayfanı Kelimelerle Değil Veriyle Anlatmak",
"description": "JSON-LD ile yapısal veri nasıl yazılır...",
"datePublished": "2026-05-14",
"dateModified": "2026-05-14",
"inLanguage": "en-US",
"articleSection": "SEO & Pazarlama",
"keywords": ["Schema.org", "JSON-LD", "yapısal veri"],
"author": {
"@type": "Person",
"name": "Demir Taşdemir",
"url": "https://demirtasdemir.com"
},
"publisher": {
"@type": "Person",
"name": "Demir Taşdemir",
"url": "https://demirtasdemir.com"
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://demirtasdemir.com/en/blog/schema-org-yapisal-veri.html"
}
}
</script>
Three things are worth watching here. headline has to match the <h1> on the page — if they differ, Google counts that as an inconsistency. mainEntityOfPage has to match the canonical address exactly. And datePublished has to be the real publication date; printing today's date on every build gives you a page that claims “published today” while the content never changes, and that costs you trust.
Where the details make the difference for a local business
For a business with an address, LocalBusiness is the markup with the highest return. But this is where most sites stop halfway: they write the name and the phone number and move on. The fields that actually do the work are these:
{
"@context": "https://schema.org",
"@type": "HealthAndBeautyBusiness",
"name": "Örnek Klinik",
"url": "https://ornek.com",
"telephone": "+90 555 000 00 00",
"address": {
"@type": "PostalAddress",
"streetAddress": "Örnek Mah. Örnek Cad. No: 1",
"addressLocality": "Kadıköy",
"addressRegion": "İstanbul",
"postalCode": "34000",
"addressCountry": "TR"
},
"geo": { "@type": "GeoCoordinates", "latitude": 40.99, "longitude": 29.02 },
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "09:00",
"closes": "18:00"
}],
"sameAs": [
"https://www.instagram.com/ornek",
"https://www.google.com/maps/place/..."
]
}
In the @type field it pays to pick a more specific subtype instead of LocalBusiness: HealthAndBeautyBusiness, Restaurant, SecurityService and so on. The sameAs field matters more than it looks — it explicitly establishes the link between the business's Google Maps listing, its Instagram account and its website.
This is the most common mistake by far. Adding a rating as aggregateRating when it appears nowhere on the page, printing FAQPage for an FAQ section that does not exist, listing a service that is not offered. Google treats this as a “structured data policy violation” and can shut down every rich result on the site with a manual action. The schema should be the machine-readable copy of the page — not an ad for it.
Validation: two separate tools, two separate questions
Once the markup is written I run it through two places, because each one looks at something different:
- Schema Markup Validator (validator.schema.org) — “Is this JSON valid according to the Schema.org vocabulary?” This is where I catch syntax errors and undefined properties.
- Rich Results Test (Google) — “Will Google show this as a rich result?” If you wrote a type that is valid but not supported by Google, the first tool sees no problem at all while the second one tells you no eligible items were found.
Shipping it is not the end of the job. The “Enhancements” section in Search Console shows the errors that surface in real crawls, and the warnings there can catch things the testing tools never show — particularly cases where a field in the page template ends up empty for some records.
The traps I keep falling into
I learned all of these from my own mistakes:
- Injecting the content later with JavaScript. Google does render it, but there is no guarantee and it is delayed. I keep the JSON-LD inside the HTML, in the form that comes off the server.
- Two conflicting blocks on the same page. If two different plugins or two different template fragments print different data for the same type, which one applies becomes anyone's guess. One source, one block.
- Turkish characters getting mangled. Rather than trying to escape them inside the JSON, the cleanest route is to keep the page in UTF-8 and write the characters as they are.
- Forgetting to escape a quote. If the title contains a double quote, the JSON breaks and the whole block gets ignored — silently. In the generator script I escape the quotes before printing the title.
- Date format. Write anything other than ISO 8601 and the field drops entirely.
2026-05-14is right,14.05.2026is not.
Where to start
If I had to add schema to a site from scratch, my order would be this: BreadcrumbList on every page first, then a single Organization or Person for the site as a whole, then the markup specific to each page type (BlogPosting for a post, Service for a service, a LocalBusiness subtype for a business). If there really is an FAQ section, FAQPage comes last.
The logic behind that order: the first two cover the entire site in one move and are the cheapest to maintain. Page-type-specific markup takes more effort, but it also returns more. Once you place the schema into the template correctly, every page after that gets it for free — on my own blog I write nothing extra for each new post, the generator script handles it.
- SEO
- Schema.org
- JSON-LD
- Structured Data
- Web Development
Demir Taşdemir
Mobile App & Web Developer
I have been building software since 2018. I have published 11 apps on the App Store and Google Play; right now I am working on 6 mobile apps, 1 e-commerce platform and 1 desktop game.
Does your site have structured data, and is it correct?
I can go through the schema markup on your current site and work out which types are missing and which ones are wrong. If you are building a new site, I plan the structured data in from the start. Just write to me from the contact page.