Saltar al contenido principal

Stencil theme snippet — for non-JS crawlers

Audience: BigCommerce merchants on a Stencil theme who care about a specific class of crawler that does NOT evaluate JavaScript. This is additional to the Schema Injector Script Tag, not a replacement for it.

Why this exists

The Clione Schema Injector (see SCHEMA_INJECTOR_BIGCOMMERCE.md) installs a <script> via BC's Scripts API. That script runs in the browser and injects JSON-LD into <head> before DOMContentLoaded fires. Crawlers that run a real headless browser — Google, Bing modern, GPTBot, ClaudeBot, PerplexityBot, the Common Crawl V2 fleet, all of Anthropic / OpenAI / Google AI training pipelines — see that JSON-LD as if it were in the original HTML.

But a non-trivial set of crawlers does not evaluate JavaScript at all. They fetch HTML with something equivalent to curl and parse what comes back:

  • LinkedIn Post Inspector / debugger — used by anyone sharing a product link on LinkedIn.
  • Facebook Sharing Debugger — same idea, Facebook side. (FB occasionally renders JS now, but the debugger UI itself doesn't.)
  • Slack link unfurler — open-graph and a thin JSON-LD parser, no JS.
  • Older SEO audit tools — Screaming Frog (older configs), Sitebulb (configurable), some commercial enterprise tools.
  • AI scrapers without a V8 runtime — long tail of internal data pipelines, RAG indexers, scraper-as-a-service products that ship without a headless browser to save cost.

For these, the Script Tag is invisible — they never run it. The only way to make JSON-LD visible to them is to put it in the HTML the BC server returns. There is no API-only way to do that on BC. You have to edit the Stencil theme.

What this is and isn't

This doc covers the minimum theme snippet that fetches Clione's JSON-LD server-side at theme-render time and inlines it in the HTML response.

It is not a replacement for the Script Tag. The Script Tag handles 95%+ of crawler traffic and updates dynamically with no theme deploy. The theme snippet is the long-tail belt-and-braces option for stores that care about LinkedIn / Slack / FB previews and want JSON-LD signals visible to non-JS crawlers.

Prerequisites

  • The store is on a Stencil theme (not Catalyst / headless).
  • You have edit access to the active theme via the BC admin (Storefront → Themes → Customize → Advanced → Edit theme files).
  • You have an active Clione API key with products:read scope.
  • The Clione Schema Injector Script Tag is also installed — they are complementary, not alternatives.

The snippet

Add the following to templates/components/common/header.html (or the closest equivalent for your theme), inside <head>, after any existing meta-tag block:

{{!-- Clione SEO — server-side JSON-LD for non-JS crawlers --}}
{{#if pages.contact}}{{/if}}{{!-- placeholder; remove if your theme has no Handlebars helpers --}}

<script type="application/ld+json" data-clione="theme-snippet">
{{!--
Stencil cannot fetch external APIs at render time. The pattern below uses
BC's `inject` helper to surface the entity id (product / category) and lets
a small inline boot script call /api/v1/public/schema.jsonld on first
paint, then write the response into a noscript-equivalent slot.

For TRULY no-JS crawlers (which by definition won't run this), the only
durable option is to back-fill the snippet at deploy time using the
`clione schema dump` CLI (see scripts/dump-schema.ts) and commit the
resulting JSON file into theme assets, then `{{ inject }}` the contents
into <head>. Documented below under "Static fallback".
--}}
</script>

For crawlers that DO evaluate JS but you want to avoid the Script Tag's XMLHttpRequest sync hit, add this to templates/components/common/head.html:

{{#if product}}
{{inject "clioneProductId" product.id}}
{{else if category}}
{{inject "clioneCategoryId" category.id}}
{{/if}}

<script>
(function () {
var data = JSON.parse(document.getElementById('jsContext').innerHTML);
var entityType = data.clioneProductId ? 'product'
: data.clioneCategoryId ? 'category'
: null;
var entityId = data.clioneProductId || data.clioneCategoryId;
if (!entityType) return;

var s = document.createElement('script');
s.type = 'application/ld+json';
s.setAttribute('data-clione', 'stencil-snippet');
fetch('https://api.clione.ai/api/v1/public/schema.jsonld'
+ '?platform=bigcommerce&entityType=' + entityType
+ '&entityId=' + encodeURIComponent(entityId), {
headers: { 'X-API-Key': 'PASTE_YOUR_API_KEY_HERE' },
}).then(function (r) { return r.ok ? r.text() : null; })
.then(function (t) { if (t) { s.text = t; document.head.appendChild(s); }});
})();
</script>

This still requires JS, so it's only a partial answer for non-JS crawlers. Use the static fallback below if you truly need bytes-in-HTML.

Static fallback (for genuine non-JS crawlers)

This is the only approach that actually puts JSON-LD bytes in the HTML BC returns to a curl-equivalent crawler.

  1. Run npm run clione:dump-schema -- --store=YOUR_STORE_HASH --out=assets/clione-schema.json from your local Clione tools checkout. This calls the same /schema.jsonld endpoint for every published product / category and writes a single bundle.
  2. Commit assets/clione-schema.json into the active Stencil theme via the Theme Editor's file uploader (or stencil push if you maintain the theme outside admin).
  3. Add to templates/components/common/header.html, inside <head>:
{{#if product}}
<script type="application/ld+json" data-clione="static">
{{{getAssetFromTheme "clione-schema.json" product.id}}}
</script>
{{/if}}

Caveat: the static bundle is a snapshot. It does not reflect Clione changes until you re-run the dump and re-deploy. For most stores this is fine if the bundle is refreshed weekly via a scheduled CI job — Pulse will tell you when it goes stale (the signal_stale_age metric).

When NOT to bother

If your store's traffic is mostly Google / Bing organic + paid + direct, and you don't publish products on LinkedIn or Slack as link previews, skip this entirely. The Script Tag covers everything that matters and the theme edit is just maintenance cost.

If you DO publish on LinkedIn / Slack / FB regularly, and product previews look thin or wrong there, do the dynamic variant first. Only escalate to the static fallback if a specific named crawler (with logs to prove it) is missing signals.

  • SCHEMA_INJECTOR_BIGCOMMERCE.md — The Script Tag side. Install that first.
  • PROPAGATION.md — How enriched signals flow from Clione → BC metafields → the snippet's data source.
  • PULSE_SCORING.md — Which signals contribute to the Pulse score and how staleness is detected.