Most Shopify blogs have zero structured data on their article pages. No Article schema, no BlogPosting markup, nothing that tells Google “this is a blog post by this author, published on this date, about this topic.”
The result: Google treats your blog content as generic web pages instead of recognized articles. You miss out on article-specific rich results, author attribution in search, and better visibility in Google Discover and AI Overviews.
I recently audited a Shopify store where the blog drove 50,000+ clicks across 230+ URLs with zero Article schema on any of them. The blog was their strongest content type, outperforming collection pages on CTR, and Google had no structured data to work with.
This guide gives you the exact Liquid code to add BlogPosting schema to every Shopify blog post. One snippet, one render call, and every article page gets valid structured data that passes Google’s Rich Results Test.
Why Your Shopify Blog Needs Article Schema
Shopify themes handle Product schema reasonably well through the default structured-data.liquid snippet. But blog content gets nothing. No Article, no BlogPosting, no datePublished, no author. Google has to guess what your content is.
Here is what Article schema specifically enables:
Article rich results. Google can display your blog posts with headline styling, author name, published date, and thumbnail image directly in search results. These enriched listings have measurably higher click-through rates than plain blue links.
Author attribution. The author field connects your blog content to a named person, which feeds into Google’s E-E-A-T (Experience, Expertise, Authoritativeness, Trustworthiness) evaluation. For freelancers and consultants, this builds personal brand authority in search.
Date signals. datePublished and dateModified tell Google exactly when content was created and last updated. This matters for queries where freshness is a ranking factor, and it helps Google decide whether to show your content in “Top stories” or time-sensitive results.
AI Overview citations. Structured content with clear schema markup is more likely to be cited by Google’s AI Overviews and other generative search engines. The schema gives these systems confidence in the content’s source, date, and authorship.
Google Discover eligibility. Article schema is a prerequisite for Google Discover, which can drive significant traffic to blog content on mobile devices.
The Complete Liquid Snippet
Create a new file at snippets/article-schema-jsonld.liquid in your Shopify theme:
{% comment %}
BlogPosting schema for article pages.
Renders JSON-LD structured data for Google rich results.
Include this snippet in sections/article-template.liquid
or templates/article.liquid.
{% endcomment %}
{% if request.page_type == 'article' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": {{ article.title | json }},
"description": {{ article.excerpt_or_content | strip_html | truncate: 160 | json }},
"url": "{{ shop.url }}{{ article.url }}",
"datePublished": "{{ article.published_at | date: '%Y-%m-%dT%H:%M:%S%z' }}",
"dateModified": "{{ article.updated_at | date: '%Y-%m-%dT%H:%M:%S%z' }}",
"wordCount": {{ article.content | strip_html | split: ' ' | size }},
"inLanguage": "{{ request.locale.iso_code }}",
"author": {
"@type": "Person",
"name": {{ article.author | json }}
},
"publisher": {
"@type": "Organization",
"name": {{ shop.name | json }},
"url": "{{ shop.url }}"{% if article.image %},
"logo": {
"@type": "ImageObject",
"url": "https:{{ article.image | image_url: width: 600 }}"
}{% endif %}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "{{ shop.url }}{{ article.url }}"
}{% if article.image %},
"image": {
"@type": "ImageObject",
"url": "https:{{ article.image | image_url: width: 1200 }}",
"width": 1200
}{% endif %}{% if article.tags.size > 0 %},
"keywords": {{ article.tags | join: ', ' | json }}{% endif %},
"articleSection": {{ blog.title | json }}
}
</script>
{% endif %}
Then add one line to your article template to render it. Open sections/article-template.liquid (or templates/article.liquid depending on your theme) and add:
{% include 'article-schema-jsonld' %}
Place it anywhere inside the template. The JSON-LD renders in the page source regardless of where you include it, because Google reads structured data from anywhere in the HTML document.
Field-by-Field Breakdown
Here is what each field does and why it matters:
@type: “BlogPosting”
Use BlogPosting for blog content. It is a more specific subtype of Article in Schema.org’s hierarchy. Google accepts both, but BlogPosting gives a clearer signal about what the content is.
For non-blog content like case studies or documentation, use Article instead.
headline
Maps to article.title. Google uses this as the primary title in article rich results.
The | json filter is critical here. It wraps the value in quotes and escapes any special characters (quotes, backslashes, unicode) that would break the JSON-LD. Never output Liquid values in JSON-LD without the | json filter. A single unescaped quote in an article title will silently break the entire schema block.
description
Uses article.excerpt_or_content with strip_html and truncate: 160. This pulls the article excerpt if one exists, otherwise falls back to the first 160 characters of the article body.
datePublished and dateModified
article.published_at is when the post was first published. article.updated_at is the last time any edit was saved.
The date format %Y-%m-%dT%H:%M:%S%z outputs ISO 8601 format, which is what Schema.org requires. Example output: 2026-03-15T09:30:00-0400.
wordCount
Calculated dynamically: article.content | strip_html | split: ' ' | size. Strips HTML tags, splits on spaces, and counts the resulting array. It is approximate but sufficient for schema purposes.
author
Maps to article.author, which is the author name set in Shopify’s blog editor. If you want to link the author to a Person entity with a URL (for stronger E-E-A-T signals), expand it:
"author": {
"@type": "Person",
"name": {{ article.author | json }},
"url": "{{ shop.url }}/pages/about"
}
publisher
For single-person brands, you can use "@type": "Person" instead of "Organization". For stores with a company identity, keep it as Organization and reference your logo.
If you already have an Organization schema elsewhere on the site (many themes include one in layout/theme.liquid), you can reference it by @id instead of duplicating the full block:
"publisher": {
"@id": "{{ shop.url }}#organization"
}
This assumes your existing Organization schema has a matching "@id": "{{ shop.url }}#organization" field. Using @id references keeps your schema DRY and prevents Google from seeing duplicate Organization entities.
image
Conditionally included only when the article has a featured image. The image_url filter with width: 1200 serves a properly sized image for schema. Google recommends images be at least 1200px wide for article rich results.
If the article has no image, the field is omitted entirely. Do not output an empty string or placeholder. Empty image fields cause schema validation warnings.
keywords
Pulls from article.tags and joins them with commas. Only included if the article has tags.
articleSection
Maps to blog.title, which is the name of the Shopify blog the article belongs to (e.g., “News”, “Guides”, “CRO Tips”).
Handling Edge Cases
Articles Without Images
The snippet already handles this with the {% if article.image %} conditional. When no featured image exists, the image field is cleanly omitted.
Articles Without Excerpts
excerpt_or_content automatically falls back to article body content when no excerpt is set. The truncate: 160 ensures the description stays within a reasonable length.
Special Characters in Titles
The | json filter handles this. A title like "How to Fix 'Broken' Liquid Loops" gets properly escaped to "How to Fix 'Broken' Liquid Loops" in the JSON output. Without this filter, the nested quotes would break the JSON-LD and Google would silently ignore the entire schema block.
Multi-Author Blogs
If your blog has multiple authors, article.author already returns the correct author per article. No additional logic needed.
Existing Schema Conflicts
Check if your theme already outputs any article-related schema. Search your theme code for "BlogPosting" or "Article" in the layout/theme.liquid, templates/article.liquid, and snippets/ directory. If you find existing schema, either replace it with this snippet or remove this snippet to avoid duplicate structured data.
Also check for SEO apps (JSON-LD for SEO, Smart SEO, Schema Plus) that may already inject Article schema. Running two sources of the same schema type creates duplicate markup that Google flags as a warning.
Validating Your Schema
After deploying the snippet, test it immediately.
Step 1: Open Google Rich Results Test.
Step 2: Enter the URL of a published blog post. Use the live URL, not a preview link.
Step 3: Check for:
- Zero errors (red). Any error means the schema is invalid and Google will ignore it.
- Zero warnings (yellow). Warnings do not prevent rich results but indicate missing recommended fields.
- The “Article” or “BlogPosting” result type should appear in the detected items.
Step 4: Test at least 3 different articles. Test one with an image, one without, and one with special characters in the title to make sure edge cases are handled.
If you see a “Missing field” warning for image, that means the specific article has no featured image. Add one in Shopify admin, or accept the warning since the field is intentionally omitted for imageless articles.
What This Looks Like to Google
After deploying, here is an example of the structured data Google sees on a blog post:
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "How to Optimize Shopify Checkout for Higher Conversions",
"description": "12 proven tactics to reduce Shopify checkout abandonment...",
"url": "https://yourstore.com/blogs/guides/checkout-optimization",
"datePublished": "2026-03-15T09:30:00-0400",
"dateModified": "2026-03-20T14:15:00-0400",
"wordCount": 2847,
"inLanguage": "en",
"author": {
"@type": "Person",
"name": "Your Name"
},
"publisher": {
"@type": "Organization",
"name": "Your Store",
"url": "https://yourstore.com"
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://yourstore.com/blogs/guides/checkout-optimization"
},
"image": {
"@type": "ImageObject",
"url": "https://cdn.shopify.com/s/files/1/..../checkout-guide.jpg",
"width": 1200
},
"keywords": "Shopify checkout, CRO, conversion optimization",
"articleSection": "Guides"
}
Google can now unambiguously identify this as a blog post, attribute it to a specific author, understand when it was published and updated, and evaluate it for article rich results.
Going Further: Connecting to Your Person or Organization Entity
For maximum E-E-A-T impact, connect your Article schema to a sitewide Person or Organization entity using @id references.
If your theme already outputs a Person schema on every page (common for personal brands and consultants), add an @id to it:
{
"@type": "Person",
"@id": "https://yourstore.com/#person",
"name": "Your Name",
"url": "https://yourstore.com/pages/about"
}
Then reference it in your Article schema:
"author": {
"@id": "{{ shop.url }}/#person"
}
This tells Google that every blog post on your site is authored by the same verified entity, building cumulative authority across all your content.
Common Mistakes to Avoid
Hardcoding values instead of using Liquid objects. If you hardcode the author name or blog title, they will not update when you change them in Shopify admin. Always pull from article.author, article.title, blog.title, etc.
Forgetting the | json filter. This is the most common cause of silently broken schema. The JSON-LD looks correct in your code editor but outputs invalid JSON because a product title contained a quote or ampersand.
Duplicating publisher entities. If your theme already has Organization schema in theme.liquid, use @id references instead of outputting a full Organization block inside every article. Two identical Organization blocks on the same page is wasteful and can trigger duplicate entity warnings.
Adding schema to draft or password-protected pages. The request.page_type == 'article' check ensures the schema only renders on published article pages. But if you are testing on a password-protected staging theme, Google cannot validate the URL through Rich Results Test. Test on a live, publicly accessible URL.
Wrapping Up
Adding BlogPosting schema to your Shopify blog is a one-time, 15-minute implementation that benefits every article you publish from now on. The Liquid snippet handles edge cases automatically, the | json filter prevents data breakage, and the conditional image logic keeps the output clean.
If your blog drives any meaningful organic traffic, this is one of the highest-ROI technical SEO improvements you can make. For the broader context on Shopify structured data including Product, Collection, FAQ, and BreadcrumbList schema, see my Shopify Liquid development guide. For more Liquid snippets that replace apps, check 15 Liquid Snippets That Replace Expensive Apps.