Back to Blog
Guides16 min read9 September 2026

Migrating Old Microdata and RDFa Markup to Clean JSON-LD

Old sites still carry inline Microdata or RDFa markup. How to inventory it, translate the vocabulary to JSON-LD, and cut over without losing rich results.

By AI Schema Gen Team

If your site was built before about 2019, there is a good chance its structured data is not where you think it is. Instead of one tidy block of code in the page head, it is scattered through the visible HTML: little attributes stuck onto headings, spans, and divs that tell a search engine "this text is the business name," "this is the price," "this is the review count." That style is called Microdata, or in a slightly different form, RDFa. It still works. Google still reads it. Nothing is on fire.

But it is the hard way to maintain structured data in 2026, and it quietly blocks the one thing that matters most for AI systems: a connected description of your business where every part points at every other part. This guide is the migration itself, step by step: how to find every piece of old inline markup on your site, translate it into JSON-LD without losing anything, and cut over to the new format without breaking the rich results you already have.

The three formats, in plain terms

Structured data is extra information you add to a page so that a machine reading it does not have to guess. "This string is a phone number." "This block describes a product." "This person is the author." The schema.org vocabulary is the shared dictionary of terms everyone uses for that. What changes between the three formats is not the vocabulary, it is where the information physically sits in your code.

Microdata puts the information directly onto your visible HTML elements, as attributes. The same tags that display your content also carry the markup:

<div itemscope itemtype="https://schema.org/Organization">
  <h1 itemprop="name">Ridgeline Plumbing</h1>
  <span itemprop="telephone">(503) 555-0142</span>
  <a itemprop="url" href="https://ridgelineplumbing.com">Home</a>
</div>

itemscope says "a described thing starts here." itemtype says what kind of thing it is. itemprop labels each piece. schema.org's own getting-started guide walks through exactly this pattern.

RDFa does the same job with different attribute names, borrowed from a broader web-data standard. The simplified version most sites used is called RDFa Lite, and the W3C spec boils it down to five attributes: vocab, typeof, property, resource, and prefix.

<div vocab="https://schema.org/" typeof="Organization">
  <h1 property="name">Ridgeline Plumbing</h1>
  <span property="telephone">(503) 555-0142</span>
</div>

JSON-LD takes all of that out of the visible HTML and puts it in a single script block, usually in the page head, written as plain structured text:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Ridgeline Plumbing",
  "telephone": "(503) 555-0142",
  "url": "https://ridgelineplumbing.com"
}
</script>

The markup and the visible page are now separate. The <h1> is just an <h1> again.

Why move at all

Google recommends it, in writing. Google's structured data guidance is careful to say all three formats are treated equally: "all 3 formats are equally fine for Google, as long as the markup is valid and properly implemented." So this is not a ranking fix. But the same page then says plainly: "In general, Google recommends using JSON-LD for structured data if your site's setup allows it, as it's the easiest solution for website owners to implement and maintain at scale." Two reasons are given. "The markup is not interleaved with the user-visible text, which makes nested data items easier to express," and "Google can read JSON-LD data when it is dynamically injected into the page's contents, such as by JavaScript code or embedded widgets."

It is far easier to maintain. With inline markup, every change to your page design risks breaking your structured data, because they share the same tags. Someone swaps an <h1> for a styled <div> during a redesign and the itemprop="name" goes with it. With JSON-LD, the design team can rebuild the whole front end and the markup block is untouched.

It lets you build one connected description instead of scattered fragments. This is the real reason, and it is the one that matters for AI. Inline markup tends to produce isolated pieces: an Organization block in the header, a separate Article block in the main content, a Breadcrumb list somewhere else, none of them aware the others exist. Modern JSON-LD instead outputs a single graph where each thing has a stable identifier (an @id) and the others refer to it by that identifier. The article points at its author. The author points at the organization. The organization is the same node the homepage describes. AI systems that are trying to work out who runs your site and whether your content is backed by a real, consistent identity are looking for exactly that web of connections, and it is genuinely awkward to build with attributes sprinkled across your HTML.

The tools moved years ago. When Yoast SEO rewrote its structured data in version 11.0, back in April 2019, it switched from scattered Microdata "blobs" to a single JSON-LD graph "that uses IDs to connect different nodes inside of it," and described the old approach as pages having "many individual pieces, which had no way of talking to each other." Most current documentation, plugins, and validators assume JSON-LD. Staying on inline markup means working against the grain of every tool you touch.

Is anything actually broken if you do nothing?

Mostly no, and it is worth being honest about that before you spend a week on this.

Plain Microdata and RDFa that use the schema.org vocabulary still produce Google rich results today. There is no announced end date for them. If your star ratings, breadcrumbs, and FAQ snippets are showing up in search and you have checked recently, an emergency migration is not required.

The one real deprecation in this area already happened. Before schema.org won, some sites, especially for breadcrumbs, used an older vocabulary called data-vocabulary.org. Google stopped supporting it for rich results on 31 January 2021, after an earlier date was pushed back during the pandemic. Markup still in that format produces nothing today, and Search Console has been flagging it for years. If your inventory (next section) turns up data-vocabulary.org anywhere in an itemtype or vocab attribute, that part is not a "nice to migrate eventually," it is already dead and should go to the top of the list. Our rundown of structured data changes has the fuller history.

Everything else is a maintainability and AI-readiness decision, not a fire drill. Which means you can do it carefully, template by template, instead of rushing.

The migration, step by step

Step 1: Find every piece of markup, and which template puts it there

You cannot migrate what you have not mapped. The goal here is a short list: which formats are on the site, which page types carry them, and what is generating each one.

Open a representative page of each type (homepage, a blog post, a product page, a category or archive page, a contact page) and view the page source, not the browser's element inspector. The inspector shows you the page after scripts have run; view-source shows the raw HTML the server sent, which is what a crawler reads first. In that raw source, search for:

  • itemscope and itemtype (Microdata)
  • typeof= and vocab= (RDFa)
  • application/ld+json (JSON-LD that is already there)
  • data-vocabulary.org (the dead format)

Write down what each page type has. A common and messy finding is that a site has all three at once: JSON-LD from an SEO plugin added a few years ago, Microdata still baked into the theme from before that, and an RDFa breadcrumb from a third source nobody remembers installing.

For each piece, work out who owns it. The usual suspects, in rough order of how often they turn out to be the source:

  • The theme. Older commercial and custom themes hard-coded Microdata into their template files, especially for posts, comments, breadcrumbs, and the site header. This is the most common leftover.
  • An SEO plugin's older output. Some plugins emitted Microdata before switching to JSON-LD; if the plugin was configured long ago, an old setting may still be on.
  • A page builder or a breadcrumb plugin. Breadcrumbs are the single most common piece of orphaned inline markup, because they were often added separately from everything else.
  • Hand-written code in a template file, added once by a developer and never revisited.

Step 2: Decide what the finished JSON-LD should say, per template

Do not translate line by line yet. First decide, for each page type, what the structured data should describe when you are done. This is your chance to fix gaps, not just move them.

A blog post page, for example, usually wants: an Article (or BlogPosting), its author as a Person, the publisher as an Organization, a breadcrumb trail, and ideally all of it connected by @id so the author node is the same node used everywhere else on the site. Your old Microdata might only have covered the Article headline and date. Migration is the moment to add the rest, because you are rebuilding the block anyway.

Step 3: Translate the vocabulary

The good news: because all three formats use the same schema.org dictionary, translation is mechanical. Every term maps one to one.

MicrodataRDFaJSON-LD
itemtype="https://schema.org/Product"typeof="Product""@type": "Product"
itemprop="name"property="name""name": "..."
itemscope on a nested elementtypeof on a nested elementa nested { } object, or an @id reference
the element's text contentthe element's text, or a content attributethe value of the key
<a itemprop="url" href="...">property="url" resource="...""url": "..."

The one part that takes judgment is nesting. Inline markup expresses "the author of this article" by physically putting the author's markup inside the article's markup in the HTML. In JSON-LD you have two choices: nest the author object directly inside the Article, or give the author its own @id and reference it. For anything that appears on more than one page (your organization, recurring authors), use the @id reference so there is one definition and everything points at it. For one-off values, nest them inline. Putting multiple schema types on one page cleanly is its own small skill.

Step 4: Replace per template, and never run both at once

Make the change in the template or the plugin setting, so it fixes every page of that type in one move. Fixing individual pages by hand leaves the generator broken for the next hundred.

The critical rule during cutover: do not leave the old inline markup in place "just in case" while you add the JSON-LD. Two sources describing the same Organization or the same Article on one page is a real problem, not a harmless backup. A search engine may merge them, pick one, or flag the page as confused, and an AI crawler building an entity graph can end up with two of everything. This is the same failure mode you get from two schema plugins running at once. When you switch a template to JSON-LD, strip that template's itemscope, itemtype, itemprop, typeof, vocab, and property attributes in the same change.

Step 5: Watch for styling and scripts hooked to the old attributes

This is the trap that breaks pages. Because Microdata and RDFa attributes live on visible elements, some sites ended up using them as styling or scripting hooks: a CSS rule like [itemprop="name"] { font-size: 2rem }, or a script that reads document.querySelector('[itemprop="price"]'). Remove the attribute and the heading loses its size, or the script silently returns nothing.

Before you strip attributes from a template, search your stylesheets and JavaScript for itemprop, itemtype, itemscope, typeof, and property=. Anything that matches needs a plain class added to the element first, with the CSS or script repointed at that class. Do this before the migration, not after someone reports the page looks wrong.

Step 6: Verify parity before and after

For each template, capture the "before" state so you can prove nothing regressed:

  1. Run a representative URL through the Rich Results Test and note every rich-result type it detects and every property inside.
  2. Run the same URL through the Schema Markup Validator, which checks broader schema.org validity, including types Google does not show a rich result for but AI systems still use.

Make the change on staging. Run both tools again on the new JSON-LD. The detected types and their key properties should match your "before" list, or be a deliberate superset because you added things in Step 2. If something is missing, you dropped it in translation. Common misses: the breadcrumb list, the datePublished value, the author, and image URLs that were relative in the old markup and need to be absolute in JSON-LD. If you hit validator errors you do not recognise, our guide to common schema errors covers the messages you are most likely to see.

Step 7: Ship, then watch Search Console

After the change goes live, use Search Console's Rich Results and Enhancements reports over the following two to four weeks. Google has to recrawl each template's pages to pick up the new format, so the reports will show a transition: old items ageing out, new items appearing. A temporary dip in counted items during the recrawl is normal. A sustained drop, or a spike in errors on the new items, means Step 6 missed something on that template. Because you migrated one template at a time, you will know exactly which one.

Common mistakes

Leaving both formats live at once. Covered above, but it is the most common and most damaging error, so it is worth repeating. A migration where the old attributes are still on the page is not a migration, it is a duplication.

Migrating page by page instead of template by template. You will fix your ten most important pages, lose track, and leave the other few thousand on the old format indefinitely. Change the thing that generates the markup.

Orphaned itemprop attributes. Removing itemscope and itemtype from a container but leaving the itemprop attributes on the children behind. They do nothing without an enclosing scope, but they clutter the HTML and confuse the next person who reads it. Remove the whole set.

Translating the gaps forward. If the old markup was thin, rebuilding it exactly as thin in JSON-LD wastes the effort. You have the block open. Add the author, the publisher, the breadcrumb, the @id connections.

Assuming the JSON-LD is in the page just because a plugin is active. If your front end is built with a JavaScript framework, or the markup is injected by a script, confirm it appears in view-source, not just the inspector. Structured data that only exists after scripts run can be missed by crawlers that read the raw HTML first. This is a whole category of its own, covered in our guide to schema not appearing in rich results.

Forgetting the visual hooks. Step 5. Check your CSS and JS for the old attributes before you remove them.

How to check and fix your site

A short version you can run today:

  1. Inventory. View-source on one page of each type. Search for itemscope, typeof=, vocab=, application/ld+json, and data-vocabulary.org. Note what each page type has and what generates it.
  2. Triage. Anything using data-vocabulary.org is already producing no rich result. Fix that first. Everything else is a maintainability upgrade you can schedule.
  3. Pick one template. Start with the one on the most pages, usually the blog post or product template.
  4. Decide the target. What should the finished JSON-LD describe? Include the connections, not just the fields the old markup had.
  5. Check the hooks. Search your stylesheets and scripts for the old attribute names. Repoint anything that matches onto a class.
  6. Translate and replace. One template. Remove every old attribute in the same change. Never run both formats together.
  7. Verify parity. Rich Results Test and Schema Markup Validator, before and after, on staging.
  8. Ship and watch. Search Console Rich Results and Enhancements reports for two to four weeks. Move to the next template.

If doing this across a large site by hand sounds like a month of work, that is a fair assessment. Tools that generate structured data from your actual page content, rather than from templates you maintain by hand, remove most of the ongoing part of this: the markup is rebuilt from what is genuinely on the page, as a single connected JSON-LD graph, and stays in sync as the page changes. AI Schema Gen works this way. It reads whatever markup you already have on the site, in all three formats, so you can see where the mixed-format pages are, and it outputs one clean JSON-LD block per page with stable @id connections between entities. The migration still needs the old inline attributes removed from your templates, but the "what should the new markup say and how do I keep it current" half stops being your problem.

Frequently Asked Questions


AI Schema Gen reads the structured data already on your site in every format, shows you where old Microdata and RDFa are mixed in with newer JSON-LD, and generates one clean, connected JSON-LD graph per page from your live content. Run a free AI readiness check at aischemagen.com to see what your current markup looks like to a machine.

Is your site ready for AI?

Get a free readiness score in under a minute. No signup, no card.

Run the free check