Schema markup

How to Add BlogPosting Schema to a Shopify Blog Article

Shopify's docs cover Product schema. Here's the missing piece: BlogPosting JSON-LD for your Shopify blog posts — with a copy-paste article.liquid snippet.

Published May 23, 20266 min readBy RankCrab Team

Shopify's official documentation for structured data is almost entirely focused on Product schema — price, availability, reviews. That makes sense for commerce. It doesn't help the many Shopify stores that run blogs to drive organic traffic, where BlogPosting schema is what matters.

Out of the box, Shopify doesn't add BlogPosting JSON-LD to article pages. Most themes don't either. The fix is a short Liquid snippet added to article.liquid — the template that renders every blog post. This guide walks through the full implementation.

Why Shopify ignores blog schema by default

Shopify was built around products, not content. The blog feature exists and works well, but it's not where Shopify's SEO investment has historically gone. Their structured data documentation covers Product, BreadcrumbList, and Organization. BlogPosting doesn't appear in their official guides.

Most Shopify themes ship with meta tags for blog posts (title, description, Open Graph), but no <script type="application/ld+json"> block. A few premium themes include article schema as a feature — check your theme's documentation before implementing manually, since running duplicate schema blocks can cause validation warnings.

Where to find article.liquid

The article.liquid template lives in your theme's templates directory. To edit it:

  1. In your Shopify admin, go to Online Store → Themes.
  2. Click Actions → Edit code on your active theme.
  3. In the left sidebar, expand Templates and click article.liquid.

If you're using a 2.0 theme with JSON templates, you may see article.json instead of article.liquid. In that case, open the Sections folder and find your article section file — often named main-article.liquid or article-template.liquid.

The article.liquid snippet

Paste this block near the top of your article.liquid file, inside the <article> tag or immediately before it. Liquid will interpolate the Shopify variables at render time.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": {{ article.title | json }},
  "description": {{ article.excerpt_or_content | strip_html | truncate: 200 | json }},
  "image": {% if article.image %}{{ article.image | img_url: 'master' | prepend: 'https:' | json }}{% else %}{{ shop.url | append: '/path/to/default-image.jpg' | json }}{% endif %},
  "datePublished": "{{ article.published_at | date: '%Y-%m-%dT%H:%M:%S%z' }}",
  "dateModified": "{{ article.updated_at | date: '%Y-%m-%dT%H:%M:%S%z' }}",
  "author": {
    "@type": "Person",
    "name": {{ article.author | json }}
  },
  "publisher": {
    "@type": "Organization",
    "name": {{ shop.name | json }},
    "logo": {
      "@type": "ImageObject",
      "url": {{ shop.url | append: '/path/to/logo.png' | json }}
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": {{ shop.url | append: article.url | json }}
  }
}
</script>

Variable-by-variable breakdown

article.title | json — Outputs the article title as a properly escaped JSON string. The | json filter handles quote escaping for you, which is why you don't see explicit " wrapping it — the filter adds the quotes.

article.excerpt_or_content | strip_html | truncate: 200 | json — Uses the excerpt if set, falls back to the article body. Strips HTML tags and truncates to 200 characters. This produces a clean description string without markup noise.

article.image | img_url: 'master' — Outputs the full-size article image URL. The 'master' parameter requests the original resolution. The | prepend: 'https:' fixes a Shopify quirk where img_url sometimes returns a protocol-relative URL (//cdn.shopify.com/...) that schema validators reject.

article.published_at | date: '%Y-%m-%dT%H:%M:%S%z' — ISO 8601 datetime format. Google accepts both date-only (YYYY-MM-DD) and full datetime. Using the full datetime is more precise.

article.author — Shopify's article author is a string (the author's name as entered in the Shopify admin). There's no Author object with a URL or bio unless you build it separately.

shop.name and shop.url — Global Liquid variables available on every template.

Handling article tags for articleSection

If you use Shopify blog tags to categorize your posts, you can include the first tag as articleSection. Add this inside the JSON-LD block:

{% if article.tags.size > 0 %}
"articleSection": {{ article.tags.first | json }},
{% endif %}

Note the trailing comma placement — articleSection should appear before the next property in the JSON object. Liquid conditionals inside JSON-LD are valid but require care with comma placement to keep the JSON well-formed.

The logo URL problem

Shopify doesn't have a built-in Liquid variable for your logo URL. The snippet above uses a placeholder (/path/to/logo.png). Replace this with your actual logo URL — either the Shopify CDN URL for your logo image, or an absolute URL to your logo hosted elsewhere.

To find your logo's CDN URL, upload the logo as a theme asset, then reference it with:

"url": {{ 'logo.png' | asset_url | prepend: 'https:' | json }}

This assumes your logo is named logo.png in your theme's Assets folder.

One note on Shopify's auto-generated meta tags

Shopify automatically adds og:title, og:description, and og:image meta tags to article pages. These are not schema markup — they're Open Graph tags for social sharing — and they don't conflict with your JSON-LD. You can safely add BlogPosting schema alongside them.

Where you might see a conflict: some Shopify apps (particularly all-in-one SEO apps) inject their own structured data onto article pages. If you're running one of those apps, check what schema it's outputting before adding your own snippet. Duplicate schema blocks for the same type can confuse validators.

If you find a conflict, either disable the app's schema output for articles or remove the manual snippet — pick one source of truth.

Generating and validating your schema

Use RankCrab's schema generator to build a reference BlogPosting block with your actual values before touching article.liquid. This gives you a validated baseline to compare against your Shopify output.

Free tool
Schema markup generator
Generate valid JSON-LD in 60 seconds — no signup.
Try it

After saving your theme changes, open a published blog post, view the page source, and confirm the <script type="application/ld+json"> block appears with real values (not Liquid placeholders). Then run the URL through the Google Rich Results Test.

Common things to check:

  • image resolves to an absolute HTTPS URL (not protocol-relative)
  • datePublished is in ISO 8601 format
  • headline doesn't contain raw HTML
  • No trailing commas in the JSON object

For a full overview of schema types and validation, see the schema markup guide. Running into errors? The validation errors guide covers the most common Rich Results Test failures including image URL issues and date format problems.

The same BlogPosting schema structure applies on other platforms — see how to add schema markup to Webflow CMS collection pages and how to add schema markup to a Next.js App Router site for platform-specific implementations.

Schema generated, validated, deployed.

Skip the JSON-LD copy-paste loop. RankCrab generates schema and audits every page for errors.