How to implement RDFa for Schema.org Markup

Published: July 17, 2026 | Author: Aubrey Yung

Follow aubreyyung.com as a preferred source on Google

RDFa (Resource Description Framework in Attributes) is one of three formats search engines support for adding structured data to your website — the other two being JSON-LD and Microdata. Unlike JSON-LD, which lives in a separate script block, RDFa is written directly into your existing HTML tags using attributes like property and typeof.

In this article, we'll go over what RDFa is, how it's structured, and how to implement it on your website using Schema.org's vocabulary.

What is RDFa?

RDFa is a W3C Recommendation that extends plain HTML with a set of attributes for embedding structured data. It was originally designed to support the semantic web — the idea that web pages should carry machine-readable meaning, not just human-readable text — and it predates both Microdata and JSON-LD.

Where JSON-LD describes your page's entities in a standalone script, and Microdata uses itemscope and itemprop attributes, RDFa attaches its own attribute vocabulary (typeof, property, resource, about, and a few others) to the HTML elements that are already on your page.

RDFa schema anatomy

In practice, this means RDFa markup is woven into your visible content rather than sitting separately from it. With JSON-LD, it's possible to update the visible text without updating the script, so the two disagree. With RDFa, the property attribute sits directly on the element with the text, which reduces that risk (though a template change can still strip the attribute if you're not careful).

Google, Bing, and other major search engines all support RDFa, and it works with the same Schema.org vocabulary as JSON-LD and Microdata — the format changes how the data is expressed, not which schema types and properties are available to you.

RDFa is also worth knowing if you work on projects outside pure SEO, such as linked data or semantic web applications, where RDFa has a longer track record than the other two formats.

What are RDFa Attributes for Schema.org

To mark up content with RDFa, you'll mainly work with the following attributes:

  1. vocab: Declares the vocabulary you're using — for Schema.org markup, this is https://schema.org/. It's usually set once on a container element and inherited by everything inside it.
  2. typeof: Declares the Schema.org type for an element, such as Person, Article, or Organization.
  3. property: Maps an HTML element's content to a specific Schema.org property, such as name, headline, or datePublished.
  4. resource: Assigns a unique identifier (a URI) to an entity, similar to how @id works in JSON-LD.
  5. about: Specifies which entity the surrounding properties describe, useful when an element isn't the natural subject of its own content.
  6. content: Provides a machine-readable value for a property when the visible text on the page isn't in the right format. For example, showing "March 2026" to users while marking up the ISO date underneath.

You'll typically combine typeof to declare an entity, property to attach its attributes, and content when the visible text needs a cleaner, machine-readable equivalent alongside it.

RDFa Example

Here's an example of a Person entity marked up with RDFa, nested inside an Article — a common pattern for blog posts that need both Article and Author schema on the same page:

RDFa schema example
<article vocab="https://schema.org/" typeof="Article">
  <h1 property="headline">How to Implement RDFa for Schema.org</h1>
  <p>
    Published:
    <time property="datePublished" datetime="2026-07-17" content="2026-07-17">
      July 17, 2026
    </time>
  </p>
  <div property="author" typeof="Person" resource="https://aubreyyung.com/about/">
    <span property="name">Aubrey Yung</span>
    <a property="url" href="https://aubreyyung.com/about/">View profile</a>
    <span property="jobTitle">SEO Manager and Schema Markup Consultant</span>
  </div>
  <div property="articleBody">
    <p>RDFa is one of three structured data formats supported by search engines for describing page content to machines.</p>
  </div>
</article>

A few things to note in this example:

  • vocab is declared once, on the outer <article> tag, and applies to everything nested inside it.
  • The outer typeof="Article" and the inner typeof="Person" create two connected entities — the Person is understood as the value of the Article's author property.
  • The content attribute on the <time> element lets you display a human-friendly date while still giving search engines a clean, machine-readable one.

How to implement RDFa on your website

1. Identify the entities on the page

Before writing any markup, work out what the page is actually about. A blog post is usually an Article with a nested Person (the author). A product page is usually a Product with nested Offer and AggregateRating entities. Map these out first so you know which HTML elements you'll be annotating.

2. Choose your vocabulary

For Schema.org markup, set vocab="https://schema.org/" on a container element that wraps all the content you want to describe — this is usually the outermost element of the entity, such as <article> or <div>.

3. Add typeof and property attributes to existing HTML

This is the step that makes RDFa different from JSON-LD: instead of writing a separate data block, you add attributes directly to the tags that already display your content.

A heading becomes <h1 property="headline">, an author name becomes <span property="name">, and so on.

Pro Tip

Don't duplicate the same entity in multiple formats on one page. If you already have JSON-LD for an entity, don't also mark it up in RDFa on the same page — pick one format per entity to avoid conflicting or redundant data.

Many things you're describing aren't a single, standalone entity — they're made up of other entities. An Article has an Author. A Product has a Brand. A Recipe has a nested list of Ingredients.

When that's the case, don't just describe each entity separately on the page — nest the child entity's markup inside the parent's, so search engines understand how they relate to each other, not just that they both happen to exist on the same page.

The mechanism is simple: the element that holds the child entity gets two attributes at once — property, naming which field on the parent this child fills, and typeof, declaring what kind of entity the child itself is. You saw this already in the Article/Person example:

html
<div property="author" typeof="Person">
  <span property="name">Aubrey Yung</span>
</div>

property="author" tells search engines "this is the value of the Article's author field." typeof="Person" tells them "and this value is itself a Person entity, with its own properties." Nesting like this is what turns two disconnected facts — "this page mentions an Article" and "this page mentions a Person" — into one connected fact: "this Article's author is this specific Person."

A couple of things worth keeping in mind as you nest:

  • Nesting can go more than one level deep. A parent entity can contain a child, and that child's markup can itself contain further nested properties, as long as each level's typeof correctly labels what's inside it.
  • Every nested entity still inherits the outer vocab. You only need to declare vocab="https://schema.org/" once, at the outermost element — every typeof and property nested inside it, no matter how deep, resolves against that same vocabulary automatically.
  • Always pair the child's typeof with property on the same element. If you find yourself writing typeof without a property alongside it, double-check whether that entity is actually supposed to connect to something else on the page.

A common trap: DOM nesting isn't the same as RDFa nesting.

Nesting the markup is just the natural, conventional way to write that connection, but it doesn't create the connection by itself.

It's entirely possible to place a typeof="Person" element physically inside the Article's HTML and still end up with two disconnected entities, if that element is missing property:

DOM nesting without RDFa nesting
<div vocab="https://schema.org/" typeof="Article">
  <h1 property="headline">
    How to Implement RDFa...
  </h1>

  <div typeof="Person">
    <span property="name">
      Aubrey Yung
    </span>
  </div>

  <div property="articleBody">
    ...
  </div>
</div>

This Person <div> is a child element in the DOM tree, but as far as RDFa parsing goes, it's unrelated to the Article — there's no property attribute creating the link, so the parser sees two separate entities that happen to share a common ancestor. typeof on its own only says "a new entity starts here." The connection to the parent is created exclusively by property, regardless of where the element physically sits in the markup.

5. Use content for data that isn't visible in the right format

Most of the time, the text a visitor sees on the page is already fine for search engines to read as-is. For example, <span property="name">Aubrey Yung</span> is a plain string that a machine can read "Aubrey Yung" exactly as written.

But some values are written for humans in a format a machine can't reliably parse:

  • Dates: a page might show "July 17, 2026" — easy for a person to read, but ambiguous or hard to parse programmatically. Schema.org expects dates in ISO 8601 format, like 2026-07-17.
  • Prices: a page might show "$1,000.00" — the currency symbol and comma are for human readability, but a machine needs a clean number like 1000.00 plus a separate currency code.
  • Ratings: a page might show "4.5 out of 5 stars" — a machine wants just the number 4.5.

Whenever the visible text isn't machine-readable on its own, pair it with a content attribute holding the correctly formatted value. You keep the human-friendly text visible on the page, but attach content to the same element to hold the clean, machine-readable version alongside it — the visitor sees one, the search engine reads the other. This is exactly what's happening in the <time> element from the example above:

RDFa content example
<time property="datePublished" datetime="2026-07-17" content="2026-07-17">
  July 17, 2026
</time>

A visitor reads "July 17, 2026." A search engine reads content="2026-07-17" instead — content, when present, overrides the element's own visible text as the property's value.

Pro Tip:

You need to match visible content to marked-up content. Don't use property and content to describe something that isn't actually shown or true on the page — search engines can penalize markup that misrepresents the page's content.

6. Add resource for entities you'll reuse

typeof and property are usually enough to describe an entity once. But if the same Person, Organization, or Brand shows up in more than one place — an author appearing on every article, a company appearing on every product page — each mention is otherwise treated as its own separate, anonymous entity that just happens to share a name.

resource fixes that by giving the entity a stable identifier, similar to how @id works in JSON-LD.

The value is typically a URL you control — often the entity's own page:

code
<div property="author" typeof="Person" resource="https://aubreyyung.com/about/">
  <span property="name">Aubrey Yung</span>
</div>

Reuse that exact same resource value on every page where this Person appears — every article's author block, the team page, the about page itself. That consistency is what lets search engines merge all those mentions into one recognized entity, rather than reading them as coincidentally similar but separate people. A URL fragment (resource="https://aubreyyung.com/#person-aubrey") works too if you don't have a dedicated page to point to, but linking to a real page is usually better — it doubles as a useful link for readers and gives you a canonical place to add more detail about that entity later.

You don't need resource for entities that only ever appear once. It earns its place specifically when an entity recurs and you want search engines to recognize the repetition.

6. Test Your Markup

Once your RDFa is in place, run the page through Google's Rich Results Test or the Schema Markup Validator to confirm the markup parses the way you intended and that every entity and property you added is actually being picked up.

Because RDFa lives inside your HTML, a redesign or template update can strip or shift attributes in a way a separate JSON-LD script wouldn't be affected by. Re-run your validator after any redesign, template change, or CMS migration, and not just the first time you add the markup.

When should you use RDFa instead of JSON-LD?

Google's own documentation is clear that all three formats are equally valid, as long as the markup is implemented correctly. That said, Google explicitly recommends JSON-LD, specifically because it's the easiest format for site owners to implement and maintain at scale, and it's the least prone to the kind of accidental breakage that comes from editing HTML templates directly.

Beyond Google's stated preference, there's also a structural limit worth knowing about: RDFa doesn't handle multiple, interlinked entities as cleanly as JSON-LD does.

Here is a simple example. Say you have one Organization that needs to be referenced as the manufacturer on two different Product entities. In JSON-LD, you can define the Organization once with an @id and reference it from both products:

jsonld
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Example Co."
    },
    {
      "@type": "Product",
      "name": "Trail Runner Shoe",
      "manufacturer": { "@id": "https://example.com/#organization"" }
    },
    {
      "@type": "Product",
      "name": "Trail Runner Backpack",
      "manufacturer": { "@id": "https://example.com/#organization"" }
    }
  ]
}

In RDFa, there's no @graph-style container to hold that shared reference. Each Product typically has to nest its own copy of the Organization markup, or you resort to resource or about attributes to reconnect them — which quickly gets harder to read and easier to break as the number of shared entities grows:

html
<div vocab="https://schema.org/" typeof="Product">
  <span property="name">Trail Runner Shoe</span>
  <div property="manufacturer" typeof="Organization">
    <span property="name">Example Co.</span>
  </div>
</div>

<div vocab="https://schema.org/" typeof="Product">
  <span property="name">Trail Runner Backpack</span>
  <div property="manufacturer" typeof="Organization">
    <span property="name">Example Co.</span>
  </div>
</div>

Two entities are somehow manageable. But once you're describing something with several shared, cross-referenced entities, RDFa's HTML-nesting approach stops scaling gracefully, while JSON-LD stays flat and readable.

RDFa is still worth considering in a few specific situations:

  • You're working within a CMS or templating system that doesn't easily support injecting a JSON-LD script, but does give you control over HTML attributes.
  • You're maintaining a legacy site that already uses RDFa, and a full migration to JSON-LD isn't a priority right now.
  • You're working on a semantic web or linked data project outside of pure search visibility, where RDFa's broader W3C support matters more.
  • Your markup describes a small number of simple, self-contained entities with little or no need to reference shared entities across the page.

If none of those apply to you, JSON-LD is usually the more practical choice.

What you get from RDFa if it’s done right

RDFa attaches structured data straight to the HTML you already have. You don't need to create a separate script, and there's no risk of your markup and content drifting out of sync.

It works well for a handful of connected entities, but it gets harder to manage once you're linking many together, which is why JSON-LD stays the more practical default for most sites.

RDFa fits best when your CMS won't let you inject a script, you're maintaining an existing RDFa implementation, or you're building for the wider semantic web rather than search alone.

Otherwise, the checklist is the same regardless of schema markup format: identify your entities, nest what's actually connected, and validate after every redesign.

Related Post

Schema Markup

What is Schema Markup

In this beginner’s guide, let’s take a look at what schema markup is, how it works, and how it can benefit your website.