Rich Text Editor Removes JSON-LD Script After Saving – Any Workaround?

Rich Text Editor Removes JSON-LD Script After Saving – Any Workaround?

Hi everyone,

I’m facing an issue with the Shopify Rich Text Editor and couldn’t find a reliable solution.

I’m working on an industrial products website:

For SEO purposes, each product category requires a different JSON-LD schema (FAQ, Collection, Breadcrumb, etc.). Because every category has unique structured data, I can’t place a single common schema in the theme’s <head>.

My idea was to add the category-specific JSON-LD inside the page content using the Shopify Rich Text Editor. However, whenever I paste something like:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "CollectionPage"
}
</script>

the editor accepts it initially, but after clicking Save, the entire <script> block is automatically removed.

I’ve tested this with multiple pages, and the same thing happens every time. It appears Shopify is sanitizing or stripping <script> tags from the Rich Text Editor.

My questions:

  • Is this expected behavior in Shopify?
  • Is there any supported way to output page-specific JSON-LD without hardcoding every schema into the theme?
  • Has anyone used metafields, metaobjects, or a custom Liquid section to inject different schema for different collection pages?
  • Are there any SEO-safe alternatives that don’t require editing the theme every time a new category is added?

I’d really appreciate hearing how others are managing unique structured data for large catalogs.

Thanks in advance!

  1. You’ve chosen the right word – sanitizing. There are good reasons for this.
    People tend to copy/paste stuff from other sites and I remember that on several occasions some malicious code has been copied.

  2. Usually, this is taken care by theme code, which renders different json for different templates and pages.

  3. If this is not enough for you, an option is to use “Custom liquid” type section/block – this does minimal checks on content (if at all), so you should be able to paste your custom JSON-LD and dynamically reference page object properties to output different data for different pages.

    Be sure to run your pages through one of the the Schema Markup Testing Tool | Google Search Central  |  Google for Developers to avoid duplicates etc.

    Existing structured data can be extended rather than output a duplicate. Example here – Liquid/Schema Help: Mapping Custom Shipping/Return Metafields to Google's Structured Data - #3 by tim_tairli

    Using “Custom liquid” is a nice way to do it without editing theme code. (Which is beneficial for keeping your theme updatable

    Of course, you should also be able to output metafield content there – see this post: Metafields code adding a gallery - #5 by ajaycodewiz

  4. There are Apps which will inject JSON-LD data into your pages, but frankly, if you’re thinking about code edits, then “Custom lqiuid” should cover your needs.

@Indo_Power ,
Yes this is expected Shopify strips <script> tags from the Rich Text Editor for security reasons.

For a large catalog I’d avoid storing the JSON-LD itself in the editor. Instead create a metafield (or metaobject) that stores only the structured data values (FAQs, category type, etc.) then use a single Liquid snippet to generate the JSON-LD dynamically based on the current collection or page. That way you only maintain one template and adding new categories is just a matter of filling in metafields rather than editing theme code.

Its much easier to maintain and reduces the risk of invalid or duplicate schema.

  1. Online Store > Themes > Customize.
  2. Top-left dropdown > Collections > Default collection
  3. Under Template, click Add section > Custom Liquid.

  1. Paste this into the Liquid code box, then Save.

For example:

{%- if collection -%}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "CollectionPage",
  "name": {{ collection.title | json }},
  "description": {{ collection.description | strip_html | truncate: 300 | json }},
  "url": {{ request.origin | append: collection.url | json }},
  "hasPart": {
    "@type": "ItemList",
    "numberOfItems": {{ collection.products_count }},
    "itemListElement": [
      {%- for product in collection.products limit: 25 -%}
      {
        "@type": "ListItem",
        "position": {{ forloop.index }},
        "name": {{ product.title | json }},
        "url": {{ request.origin | append: product.url | json }}
      }{%- unless forloop.last -%},{%- endunless -%}
      {%- endfor -%}
    ]
  }
}
</script>
{%- endif -%}

SECOND METHOD: for different schema per category, use metafield:

  1. Settings > Custom data > Collections > Add definition. Name it JSON-LD, type Multi-line text. This gives you custom.json_ld.
  2. On each collection, paste that category’s raw JSON-LD into the field (no <script> tag - just the { ... } part).
  3. Use this in the same Custom Liquid section:
{%- assign ld = collection.metafields.custom.json_ld -%}
{%- if ld != blank -%}
<script type="application/ld+json">
{{ ld }}
</script>
{%- endif -%}

Shopify strips <script> tags from the Rich Text Editor for security reasons. A better approach is to store the JSON-LD in metafields and render it with Liquid in your theme. It’s much more scalable for large catalogs and easier to maintain than hardcoding schema for every collection.

You can try to add code to main-collection-product-grid.liquid file