# From widget to live product page on BigCommerce, step by step

> How data reaches a live BigCommerce product page: Stencil template, Page Builder widget, Script Manager or Catalyst, and the HTML that proves it.

URL: https://clione.ai/guides/bigcommerce-widget-to-published-page/
Lang: en

You've filled in a product's [custom fields](/glossary/bigcommerce-custom-fields/), dragged a widget in Page Builder or pasted a script into Script Manager, and you want to know whether any of it made it onto your live [product page](/glossary/product-page/). On BigCommerce, looking at the admin isn't enough: between the admin and the page sit a theme that decides what gets rendered, a placement that may be inactive, and a publish button. This guide follows each road to the page's source code, with what BigCommerce's documentation says about each step, and it ends on something you can see: the HTML.

## Where the data travels, and where it gets lost

On a store with a [Stencil](/glossary/bigcommerce-stencil/) theme, the theme builds the product page. Its templates use Handlebars, and **in production those instructions run on the server and generate the HTML the browser receives**.[^bc-stencil-stack] That's [server-side rendering](/glossary/server-side-rendering/): whatever the theme renders is in the source code before any JavaScript runs. Three roads lead to that HTML, and [Catalyst](/glossary/bigcommerce-catalyst/), BigCommerce's headless frontend, changes the rules for all three:

| Road               | Where you set it up                                                                                        | What puts it on the page                                                                       | It gets lost if…                                                                                                              |
| ------------------ | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| The theme template | The product, in the admin or through the [Catalog API](/glossary/catalog-api/); the template, in the theme | Handlebars, on the server[^bc-stencil-stack]                                                   | The template doesn't render it                                                                                                |
| A widget           | Page Builder, or the [Widgets API](/glossary/bigcommerce-widget/) from an app                              | The store's HTML, inside a theme region[^bc-widgets]                                           | There's no region, the placement is inactive, or the change wasn't published[^bc-placement][^bc-page-builder-help]            |
| A script           | Script Manager, or the Scripts API from an app                                                             | The theme's script slots in the header and the footer[^bc-scripts]                             | The theme doesn't have those slots, or the shopper rejects its category in the cookie banner[^bc-scripts][^bc-script-manager] |
| Catalyst           | The frontend code                                                                                          | The Next.js application, which requests the data from the GraphQL Storefront API[^bc-catalyst] | The code doesn't render it                                                                                                    |

The five steps below walk the table in order: the data, the template, the widget, the script and the published page.

## Step 1: check that the data is on the product

Before looking for data on the page, confirm it exists where the theme will look for it. For a product page, that's the product:

- **The SEO fields.** Each product's [page title](/glossary/meta-title/) and [meta description](/glossary/meta-description/) are edited on the product itself, in its SEO section.[^bc-seo-fields] If they're empty, whatever the theme renders in their place is up to the theme.
- **The custom fields.** They are name and value pairs; both fields are required, each pair has to be unique within the product, and the limit is **200 per product and 250 characters per field**.[^bc-api-custom-field]
- **The identifiers.** [SKU](/glossary/sku/), [MPN](/glossary/mpn/) and [GTIN](/glossary/gtin/). In Cornerstone, the [structured data](/glossary/structured-data/) block writes each one only if the product has it, as you'll see in step 2.[^cornerstone-622]

If the data isn't on the product, no theme is going to render it. If it is, the next suspect is the template.

## Step 2: read what your theme's template renders

A Stencil template can only render the data it has at hand. The product page template, `product.html`, gets the product object by default; extra data (reviews, related products, videos) is requested with a YAML front matter block at the top of the files in `templates/pages`, and it can't be requested from `templates/components` or `templates/layout`.[^bc-frontmatter]

In Cornerstone 6.22.0, the default theme, the product page is put together like this:[^cornerstone-622]

- `templates/pages/product.html` calls the product view, declares the `product_below_content` region and, at the end, includes `components/products/schema`, which is the [JSON-LD](/glossary/json-ld/) block.
- The product view renders the name in the `<h1>`, declares the `product_below_price` region, and renders the custom fields in the details list, unless the `show_custom_fields_tabs` theme setting is on, which moves them into a tab.
- The custom fields template loops over the product's list and writes each pair as a term and its definition:


```handlebars
{{#each product.custom_fields}}
  <dt class="productView-info-name">{{name}}:</dt>
  <dd class="productView-info-value">{{{value}}}</dd>
{{/each}}
```


The structured data block is a [Product](/glossary/product-schema/) with the name, the SKU, the MPN and the GTIN if they exist, the URL, the [brand](/glossary/brand-schema/), the description cut to 4,000 characters, the main image, the ratings and reviews if the store displays them, and an [offer](/glossary/offer-schema/) with the currency, the price (or the minimum and maximum if there's a range), the condition, the availability, and a price valid-until date that the template calculates as one year after the day the page is generated.[^cornerstone-622] And two things missing: **the node has no [`@id`](/glossary/id-json-ld/) and includes no custom field**. A shirt's fabric shows up on the product page for whoever reads it, and doesn't show up in its markup.

That's Cornerstone. A theme from the marketplace or from an agency is Stencil too, but it brings its own templates, so the only way to know what yours does is to read its files or the HTML it generates. If you're going to touch them, BigCommerce says so in its own exercises: **make a copy of the theme first and test the changes on the copy**.[^bc-lab-custom-field]

## Step 3: follow the widget to its region

A widget reaches a BigCommerce product page through one of two doors, and both end up in the same place.

**Page Builder**, for people who don't code. You open it at `Storefront › Themes › Edit in Page Builder`, and only on stores with a Stencil theme. You drag widgets from the menu on the left into one of the regions the theme comes with, and there's an HTML widget that accepts any HTML. The rule people forget most: **saving doesn't publish**. According to the Help Center, saved changes don't show on the storefront until you click **Publish**.[^bc-page-builder-help] Under the hood, Page Builder places widgets with the Widgets API, the same mechanism the platform's own widgets use.[^bc-page-builder-dev]

**The Widgets API**, for an app or an agency. A widget is a Handlebars template plus a configuration, a JSON of up to 64 KB that carries the content the template renders. For it to appear on the storefront it needs a placement, which decides which region it goes into and in what order.[^bc-widgets] When you create one, four fields decide whether you'll see it:[^bc-placement]

- `template_file`: the page template, `pages/product` for product pages.
- `entity_id`: the product ID, if the widget is for that product page only. Without it, it shows up on all of them.
- `channel_id`: the channel; if you leave it out, the first one created in the store.
- `status`: `active` or `inactive`, and **the default is `inactive`**.

The region has to exist in the active theme. The endpoint `GET /v3/content/regions?template_file=pages/product` returns the regions the theme declares in that template,[^bc-regions] and in Cornerstone 6.22.0 the product page has two, `product_below_price` and `product_below_content`.[^cornerstone-622] The limit a large catalog hits early: **75 placements per page template**.[^bc-widgets]

What a widget publishes lives in its configuration, not in the catalog: BigCommerce defines the configuration as the JSON holding the content the template can render.[^bc-widgets] If a widget carries a product page's markup, the price it shows is the one written into its configuration, and when the product's price changes, someone has to update the widget. One more for anyone who installs apps: the content an app's widget creates stays in the store even after you uninstall the app.[^bc-third-party-widgets]

In the HTML, the region and the widget can be recognized by two attributes; the placement leaves no trace.[^bc-widgets] This is what you look for on the product page (fictitious, simplified example):


```html
<div data-content-region="product_below_content">
  <div data-widget-id="00000000-0000-4000-8000-000000000001">
    <script type="application/ld+json">
      { "@context": "https://schema.org", "@type": "Product", ... }
    </script>
  </div>
</div>
```


Markup that ends up in the `<body>` isn't a problem for Google: JSON-LD goes in a `<script>` tag inside the `<head>` or the `<body>`, and Google also reads it when a content management system's widgets inject it. Google uses it to understand the page and to show [rich results](/glossary/rich-results/).[^google-structured-data]

## Step 4: check Script Manager and the theme's slots

Script Manager lives at `Storefront › Script Manager` and, according to the Help Center, it's a feature of stores with a Stencil theme.[^bc-script-manager] (Catalyst reads its scripts its own way, as you'll see at the end.) Each script is configured with:[^bc-script-manager]

- the placement, in the header or the footer;
- the pages where it loads: storefront pages, checkout, order confirmation, or all pages;
- the category for the cookie banner: essential, analytics, functional, or targeting/advertising;
- the type: a URL or the pasted code, up to 64 KB.

Look at the second line: **Script Manager works by page type, not by product**. A script for product pages comes out on every product page, so it's no use for one specific product's markup. That's what a widget's `entity_id` is for.

The script reaches the page through two slots in the theme. On Stencil, it goes into the header object or the footer object, and **if the template doesn't have those expressions, the scripts for that location aren't rendered**.[^bc-scripts] Cornerstone 6.22.0 has them in `templates/layout/base.html`, the first before the closing `</head>` and the second at the end of the `<body>`:[^cornerstone-622]


```handlebars
    {{{head.scripts}}}
  </head>
  ...
    {{{footer.scripts}}}
  </body>
```


A modified theme that has lost one of the two silently fails to render everything Script Manager sends to that location. Three more warnings from BigCommerce:

- **Changes take a few seconds.** Scripts have a 20-second cache, so one you've just created, changed or deleted may not show on the storefront right away.[^bc-script-manager]
- **You won't see them locally.** If you develop the theme with Stencil CLI, scripts created with the Scripts API aren't rendered.[^bc-scripts]
- **The cookie banner decides.** With the banner on, the shopper can reject script categories; essential scripts can't be opted out of.[^bc-script-manager] When you check the product page, do it without accepting anything as well.

If what you're sending through Script Manager is structured data, tell two cases apart. An `application/ld+json` block pasted as is, is text the theme writes into the HTML like any other script. A script that builds the markup with JavaScript after the page loads is something else: Google warns that **product markup generated that way can make Shopping crawls less frequent and less reliable**, a problem for data that changes fast, such as [price and availability](/glossary/price-and-availability/).[^google-js-sd]

## Step 5: check it in the published HTML

Open the product page and ask for its source code: **View page source** in the right-click menu, or `view-source:` in front of the URL. Don't use the inspector in the developer tools, which shows the page after JavaScript has run. Look for:

- **The exact value of the data**: a custom field's text, the page title, the meta description.
- **`data-content-region`**, to see the regions your theme declares, and **`data-widget-id`**, to see the widgets that have landed in them.[^bc-widgets]
- **`application/ld+json`**: how many blocks there are and which `@type` each one declares. On a product page with the theme's block and a widget's, there will be two Products, and it's worth knowing where each one comes from.
- **The Script Manager scripts**, in the header or just before the closing `</body>`, depending on the placement you chose.

What you find in the source code arrives with any download. What you see on the page and isn't there was put there by JavaScript, and only a [web crawler](/glossary/web-crawler/) that renders will read it; the guide on [what an AI crawler sees](/guides/what-an-ai-crawler-sees/) explains who does and who doesn't.

Then look at what Google sees:

- **The [Rich Results Test](/glossary/rich-results-test/)** with the URL, not by pasting the code, because pasted code comes with JavaScript limits.[^google-js-sd] It tests as a smartphone unless you choose otherwise and tells you which rich result types it finds, with their errors and suggestions.[^google-rrt]
- **The URL Inspection tool in [Search Console](/glossary/google-search-console/).** **View crawled page** shows the HTML your server returned, the headers, the JavaScript console and the resources loaded, and the live test examines the URL at that moment, so it may not match the indexed version.[^gsc-url-inspection]


If what you want is to audit the markup itself, there's the guide to [auditing a product page's structured data](/guides/audit-product-page-structured-data/). And keep the two verbs apart: [validating the markup is not the same as verifying it gets published](/comparisons/validate-vs-verify/). The second one, checking on the live page that every signal is there, is [publication verification](/glossary/publication-verification/).


**Saving is not publishing, and creating is not placing.** In Page Builder, a saved change doesn't show until it's published.[^bc-page-builder-help] Through the API, a widget with no placement doesn't come out on any page, and a placement created without a `status` starts out `inactive`.[^bc-widgets][^bc-placement] In Script Manager, the change takes a few seconds to clear the cache.[^bc-script-manager] Before you look for the fault in the widget's or the script's code, open the live product page and search for `data-widget-id` or the script: if they aren't there, the problem is in the publishing, not in the content.


## If your store runs on Catalyst

Catalyst is BigCommerce's headless frontend: a Next.js application with React Server Components that requests its data from the GraphQL Storefront API and is hosted on Vercel, on another provider that supports Next.js or, in closed beta, on BigCommerce itself.[^bc-catalyst] It doesn't load Stencil templates, and that changes all three roads:

- **Widgets.** Without Stencil templates there are no regions, which is where widgets land.[^bc-widgets] The equivalent of Page Builder is Makeswift, the visual editor built into one version of Catalyst, and apps that modify the storefront, according to BigCommerce itself, generally don't work with Catalyst.[^bc-catalyst-features]
- **Scripts.** Catalyst reads the Script Manager scripts set for all pages or for storefront pages, ignores the rest, and **loads them in the browser** with a consent library; if the store has the banner on, the non-essential ones wait until the shopper accepts their category.[^bc-catalyst-scripts] Scripts with Handlebars expressions made for Stencil don't work on Catalyst,[^bc-catalyst-features] and versions before 1.1 don't render the ones from the Scripts API.[^bc-scripts]
- **The template.** The product page is rendered by the application's code. On the Catalyst development branch we read on October 7, 2026, the product page takes its title from the product's SEO page title or, if there isn't one, from its name; and its description from the meta description or, if there isn't one, from the first 150 characters of the description. It renders a Product block with the name, the URL, the description, the brand, the ratings, the image, the SKU, the GTIN, the MPN and an offer, and **the custom fields come out in the page's specifications, not in the block**.[^gh-catalyst-pdp]

The check is the same as in step 5, with more reason: on Catalyst, what the code doesn't render doesn't exist, and the version your agency deploys may not be the one we read.

## What we tested

### What we checked from outside, on October 7, 2026

From one of our own computers, with no access to any admin, we read the code of Cornerstone 6.22.0 and of Catalyst on GitHub, and we requested a product page from BigCommerce's demo store, `cornerstone-light-demo.mybigcommerce.com`, which belongs to the platform itself.

- **Two blocks, one Product.** The product page answered with a 200 and two `application/ld+json` blocks: a BreadcrumbList and a Product. The Product has no `@id`, and its offer had October 7, 2027 as its price valid-until date, one year after our request, just as the template calculates it.
- **Seven regions, no widgets.** The HTML declared seven regions with `data-content-region`, among them the product page's two, `product_below_price` and `product_below_content`, and no `data-widget-id`: the slots were there, empty.
- **A date that isn't ISO.** The [review](/glossary/review-schema/) inside the Product block carries "2015 Dec 15th" as its publication date. [Schema.org](/glossary/schema-org/) defines the Date type as a date in ISO 8601 format,[^schema-date] and that string isn't one. It's the demo store, not yours, but it's a good reason to read your markup rather than take it for granted.
- **No meta description.** That product page's HTML had no `<meta name="description">` tag.

### The test on a Stencil store

- **Setup.** A fictitious product, labeled as such, with SKU, GTIN, page title, meta description and two custom fields, one with text and one with HTML in the value. Save the source code of its product page before you start, as a baseline.
- **Five roads.** (1) The custom field: does it show on the product page? And in the JSON-LD? (2) An HTML widget in Page Builder with an `application/ld+json` block, saved without publishing and then published. (3) A widget through the Widgets API with the product's `entity_id`, first without `status` and then `active`, with the API request and response. (4) A Script Manager script with an `application/ld+json` block pasted into the footer, in the essential category and then in analytics, with the cookie banner on and nothing accepted. (5) If the reviewer wants it, the same product on a Catalyst channel.
- **For each road.** Whether it appears in the source code (with the literal fragment), how long it took to appear, what the Rich Results Test detects with the URL and, if the store is verified in Search Console, **View crawled page**.
- **Screenshots.** The product page's source code with the region, the `data-widget-id` and the structured data blocks (the one for the image block in step 5), and the Rich Results Test, each with its date.

Tested on: store, theme and version, variant, channel, date.

| Road                           | Variant                         | In the page source | Time to appear | Rich Results Test |
| ------------------------------ | ------------------------------- | ------------------ | -------------- | ----------------- |
| Custom field                   | On the product page             |                    |                |                   |
| Custom field                   | In the JSON-LD                  |                    |                |                   |
| HTML widget in Page Builder    | Saved, not published            |                    |                |                   |
| HTML widget in Page Builder    | Published                       |                    |                |                   |
| Widget through the Widgets API | Placement without `status`      |                    |                |                   |
| Widget through the Widgets API | Placement `active`              |                    |                |                   |
| Script Manager, footer         | Essential, cookies not accepted |                    |                |                   |
| Script Manager, footer         | Analytics, cookies not accepted |                    |                |                   |

The limits, as they are: one store, one theme, one version, one channel and one date. The platform's and the themes' behavior changes with every version.

## When Clione publishes it

Clione publishes on BigCommerce by the road in step 3: its structured data graph is published with the Widgets API and rendered on the server, with a Product node with a stable `@id` next to the one the theme already renders, instead of duplicating it. Nothing reaches the store until you click Push, and then Clione requests the live product page and tells you, signal by signal, what was rendered and what wasn't.
