Back to Blog

How Do You Add Schema to a HubSpot Website (the Right Way)?

April 30, 2026 4 min read
How Do You Add Schema to a HubSpot Website (the Right Way)?

If you’ve ever tried to “just add schema” to a HubSpot site, you’ve probably realized pretty quickly… it’s not that simple.

You’re not just dropping in JSON.

You’re trying to:

  • map dynamic CMS data
  • normalize inconsistent outputs
  • connect entities across pages
  • and do it in a way that scales

Most implementations stop at “valid.”

But valid schema isn’t the goal anymore.

Structured, connected, reusable schema is.

This guide walks through exactly how to do that on HubSpot… in a way that both search engines and LLMs can actually understand.

 

What Is Schema Markup and Why Does It Matter for SEO and LLMs?

Schema markup is structured data written in JSON-LD that helps machines interpret your content.

But that definition undersells it.

Schema is not just metadata. It’s a data model of your website.

It defines:

  • who you are (Organization)
  • what your site is (WebSite)
  • what each page represents (WebPage)
  • how everything connects

Search engines use it to enhance results.

LLMs use it to understand relationships.

That second part is where things are shifting.

Because LLMs don’t just read your content…

They reconstruct meaning from structure.

If your schema is:

  • duplicated
  • inconsistent
  • disconnected

Then your site becomes harder to interpret… even if the content itself is strong.

 

 

What Does a Complete Schema Implementation Look Like on HubSpot?

Below is a production-ready, fully dynamic schema implementation designed for HubSpot.

This includes:

  • base configuration
  • language normalization
  • breadcrumb generation
  • organization, brand, logo, founders
  • website + webpage
  • clean referencing structure

All placeholders are intentionally generic so this can be adapted to any site.

{% set base = request.scheme ~ "://" ~ request.domain %}

{% set lang_parts = content.language.languageTag|split('-') %}
{% set schema_lang = (lang_parts|length > 1)
? (lang_parts[0]|lower ~ "-" ~ lang_parts[1]|upper)
: content.language.languageTag
%}

{% set breadcrumb_items = [] %}
{% do breadcrumb_items.append({
"position": 1,
"name": "Home",
"item": base
}) %}

{% set url_parts = request.path|split("/") %}
{% set current_url = base %}
{% set position = 1 %}

{% for part in url_parts %}
{% if part and not part is match('^[a-z]{2}-[a-z]{2}$') %}
{% set position = position + 1 %}
{% set current_url = current_url ~ "/" ~ part %}

{% do breadcrumb_items.append({
"position": position,
"name": part|replace('-', ' ')|title,
"item": current_url
}) %}
{% endif %}
{% endfor %}

<script type="application/ld+json">
[
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": {{ (base ~ "/#organization")|tojson }},
"name": "Your Company Name",
"url": {{ base|tojson }},
"description": "Short description of what your company does.",
"foundingDate": "YYYY-MM-DD",
"email": "support@yourdomain.com",
"sameAs": [
"https://www.linkedin.com/company/yourcompany",
"https://twitter.com/yourcompany",
"https://www.youtube.com/@yourcompany"
],
"logo": { "@id": {{ (base ~ "/#logo")|tojson }} },
"brand": { "@id": {{ (base ~ "/#brand")|tojson }} },
"founder": [
{ "@id": {{ (base ~ "/#founder-1")|tojson }} },
{ "@id": {{ (base ~ "/#founder-2")|tojson }} }
]
},

{
"@type": "Person",
"@id": {{ (base ~ "/#founder-1")|tojson }},
"name": "Founder Name",
"jobTitle": "CEO",
"worksFor": { "@id": {{ (base ~ "/#organization")|tojson }} }
},

{
"@type": "Person",
"@id": {{ (base ~ "/#founder-2")|tojson }},
"name": "Founder Name",
"jobTitle": "Co-Founder",
"worksFor": { "@id": {{ (base ~ "/#organization")|tojson }} }
},

{
"@type": "Brand",
"@id": {{ (base ~ "/#brand")|tojson }},
"name": "Your Brand Name",
"logo": { "@id": {{ (base ~ "/#logo")|tojson }} }
},

{
"@type": "ImageObject",
"@id": {{ (base ~ "/#logo")|tojson }},
"contentUrl": {{ brand_settings.logo.src|tojson }},
"encodingFormat": "image/svg+xml"
},

{
"@type": "WebSite",
"@id": {{ (base ~ "/#website")|tojson }},
"url": {{ base|tojson }},
"name": "Website Name",
"inLanguage": {{ schema_lang|tojson }},
"publisher": { "@id": {{ (base ~ "/#organization")|tojson }} }
},

{
"@type": "WebPage",
"@id": {{ (content.absolute_url ~ "#webpage")|tojson }},
"url": {{ content.absolute_url|tojson }},
"name": {{ page_meta.name|tojson }},
"description": {{ content.meta_description|tojson }},
"inLanguage": {{ schema_lang|tojson }},
"isPartOf": { "@id": {{ (base ~ "/#website")|tojson }} },
"about": { "@id": {{ (base ~ "/#organization")|tojson }} },
"breadcrumb": { "@id": {{ (content.absolute_url ~ "#breadcrumb")|tojson }} }

{% if content.publish_date %}
, "datePublished": {{ content.publish_date|datetimeformat('%Y-%m-%d')|tojson }}
{% endif %}

{% if content.updated %}
, "dateModified": {{ content.updated|datetimeformat('%Y-%m-%d')|tojson }}
{% endif %}
},

{
"@type": "BreadcrumbList",
"@id": {{ (content.absolute_url ~ "#breadcrumb")|tojson }},
"itemListElement": [
{% for crumb in breadcrumb_items %}
{
"@type": "ListItem",
"position": {{ crumb.position }},
"name": {{ crumb.name|tojson }},
"item": {{ crumb.item|tojson }}
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}
]
</script>

 

How Does the Base Configuration Work in HubSpot Schema?

The base configuration is what keeps everything consistent across your entire schema graph.

Without it, you end up with:

  • mixed domains (http vs https)
  • broken IDs
  • disconnected entities

By defining:

{% set base = request.scheme ~ "://" ~ request.domain %}

You ensure that every reference is:

  • absolute
  • consistent
  • reusable

This becomes the foundation for every @id used throughout your schema.

 

 

Why Do You Need to Normalize Language Codes in Schema?

HubSpot outputs language codes like:

en-us

Schema expects:

en-US

That difference looks small… but it matters.

Language codes are used by search engines and LLMs to:

  • group content
  • determine localization
  • map translations

If they’re inconsistent, your multilingual structure weakens.

That’s why we normalize it at the start and reuse it everywhere.

 

 

How Should Breadcrumb Schema Be Built on HubSpot?

HubSpot does not reliably expose breadcrumb data in a structured way.

So instead of relying on CMS fields…

We rebuild breadcrumbs from the URL.

This ensures:

  • consistent hierarchy
  • proper position indexing
  • no dependency on editors

It also avoids one of the most common issues:

Breadcrumbs that look correct visually… but are broken in schema.

 

 

What Are the Core Schema Entities Every Site Needs?

Before adding anything advanced, every site should have:

  • Organization
  • WebSite
  • WebPage
  • Brand
  • Logo
  • BreadcrumbList
  • Founders (if applicable)

These form your core graph.

Everything else builds on top of this.

 

 

Why Is Referencing More Important Than Adding More Schema?

Most teams try to “add more schema.”

That’s the wrong approach.

The real goal is to connect what you already have.

This:

"publisher": { "@id": "https://example.com/#organization" }

is far more valuable than redefining the same object 10 times.

Referencing creates:

  • consistency
  • clarity
  • trust

And that’s what machines rely on.

 

 

Where Should Schema Live in a HubSpot Theme?

The safest place is inside your theme files.

Typically:

  • /partials/schema.html
  • included in base.html

This prevents:

  • accidental deletion
  • inconsistent implementations
  • editor-level changes

Schema should be treated like infrastructure… not content.

 

 

How Do You Add Product Schema on HubSpot?

Product schema often requires DOM parsing because pricing isn’t always stored cleanly.

The key challenges are:

  • extracting prices
  • normalizing currency
  • structuring offers

Currency must always be ISO:

  • USD
  • EUR
  • GBP

Never symbols like $.

That’s why the mapping layer exists.

Without it, your schema may validate… but still fail to qualify for enhancements.

 

 

How Should FAQ Schema Be Implemented on HubSpot?

FAQ schema should reflect what’s actually on the page.

Not hardcoded content.

By extracting questions and answers from the DOM, you ensure:

  • accuracy
  • compliance
  • scalability

This also prevents drift between visible content and structured data.

 

 

What Are the Most Common Schema Issues on HubSpot Websites?

Most issues fall into a few categories:

  • semantic IDs that don’t match across pages
  • language codes not normalized
  • duplicated entities instead of referenced ones
  • breadcrumbs with incorrect position values
  • currency symbols instead of ISO codes
  • inconsistent image structures

None of these is major individually.

But together… they break the system.

 

 

How Do You Validate and Monitor Schema Performance?

Start with validation tools:

Then monitor inside Google Search Console.

Important to understand:

Not all schema appears immediately.

Google only surfaces what it detects and chooses to show.

So validation + monitoring both matter.

google search console schema validation

 

What’s the Right Way to Think About Schema Moving Forward?

Schema is not a plugin.

It’s not a checklist.

And it’s not something you add at the end of a build.

It’s a data layer that defines your site.

When structured correctly, it becomes:

  • reusable across pages
  • scalable across systems
  • interpretable by machines

And that’s the shift happening right now.

The sites that win are not the ones with the most schema…

They’re the ones with the best structured schema.


If you need help adding or fixing schema on your HubSpot website, contact us, and we can ensure you are ready for the new era of search. At Smuves we specialize in content engineering for HubSpot websites.