---
title: Overview
description: Embed cart and other storefront functionality into any page — a custom HTML site, an SPA, a landing page — without building a full Liquid theme.
---

Bolder Headless lets you embed cart and other storefront functionality into any page — a custom HTML site, a framework-based SPA, a landing page — without building a full Liquid theme.

There are two integration paths:

| Path | Use when… |
|------|-----------|
| **Script tag** (`storefront.umd.cjs`) | No build tooling; drop a `<script>` into any HTML page |
| **npm package** (`bolder-storefront`) | Using Vite, Webpack, or another bundler; want tree-shaking |

Both paths expose the same JavaScript API. The script-tag path auto-initialises `window.Bolder`; the npm path exports ES modules you compose yourself.

## Quick start

**Script tag**

Copy this loader snippet into your site's `<head>` or before `</body>`. It loads
`storefront.umd.cjs` asynchronously and exposes `Bolder.ready()` so your code can
queue up before the script has finished loading — no separate `data-*` tag or
queue-shim tag needed, it's one block.

Pass your shop subdomain and (optionally) a 6th argument to override `apiBase` —
omit it in production, where the SDK derives the API URL from `shop` itself:

```html
<script>
(function(b,o,l,d,e,r){
b.Bolder=b.Bolder||{};b.Bolder.ready=b.Bolder.ready||function(n){
(b.Bolder.q=b.Bolder.q||[]).push(n)};var s=o.createElement(l);
s.src=e;s.async=1;s.dataset.shop=d;r&&(s.dataset.apiBase=r);
o.head.appendChild(s)})(window,document,'script','acme',
'https://assets.bolder.run/storefront.umd.cjs?17');

Bolder.ready(function(storefront) {
  storefront.cart.on('updated', function() {
    document.querySelector('#cart-count').textContent = storefront.cart.units
  })
})
</script>
```

The loader's positional arguments (after `window`/`document`/`'script'`) are `shop`,
`src` (the SDK URL), and an optional 6th `apiBase` override. They end up as
`data-shop`/`data-api-base` on the dynamically-created script tag, which is what
`createStorefront()` reads internally to auto-init. You never write those attributes
by hand.

If you need to initialise manually with options the loader doesn't expose, skip the
loader and call `createStorefront()` yourself once the script has loaded — see
[createStorefront(options)](/frontend/sdk/core#createstorefrontoptions).

**npm package**

```bash
npm install bolder-storefront
```

```js
import { createStorefront } from 'bolder-storefront'

createStorefront({ shop: 'acme' }).then(function(storefront) {
  storefront.cart.on('updated', function() {
    document.querySelector('#cart-count').textContent = storefront.cart.units
  })
})
```

## Pre-load queue pattern

The loader snippet above already implements this: `Bolder.ready(fn)` pushes `fn` onto
`window.Bolder.q` if the SDK hasn't finished loading yet, and calls `fn` immediately once
it has. You can call `Bolder.ready()` as many times as you like, from as many separate
`<script>` blocks as you like (e.g. splitting embed setup from page-specific logic) —
every callback queues or fires the same way, in call order.

```html
<script>Bolder.ready(function(storefront) { /* runs once ready, queued or not */ })</script>
```

There's no manual queue array to manage — don't push onto `window.Bolder.q` directly,
always go through `Bolder.ready()`.

**[Core API](/frontend/sdk/core)**

createStorefront(options), Emitter, and the full config reference.

**[Cart](/frontend/sdk/cart)**

Adding items, cross-origin cart identity.
