# Install Managed Checkout in your Shopify theme

> Add the Bolt scripts and theme asset, replace the native checkout button with Bolt, and add Buy Now to product pages.

Source: https://help.boltapp.com/platforms/shopify-installation

For your first verified sandbox purchase from a checkout link, follow the [Shopify Quickstart](/platforms/shopify). This page installs Managed Checkout in the storefront theme itself.

Bolt Managed Checkout on Shopify uses three scripts: `connect.js`, Bolt's Shopify Managed Checkout loader, and one asset you add to the theme. The Bolt checkout button replaces the native Shopify checkout button in the cart, and a Buy Now button goes on product pages. Complete the steps in order on an unpublished copy of your theme. Use sandbox hosts and keys until every check in [Test your website](#test-your-website) passes, then move the whole configuration to production in one release. Element names below match Shopify's Dawn theme; other themes use different names.

## Prerequisites [#prerequisites]

* Your store is connected to Bolt. See [Connect Shopify to Bolt](/platforms/shopify-checkout-everywhere).
* **Storefront API access.** Install or open Shopify Headless and create the Storefront API configuration. Record the Storefront API token in your approved secure location, and confirm its token type before sharing it with your Bolt implementation contact.
* **A Bolt custom app in Shopify Admin** with Admin API access to draft orders, fulfillments, gift cards, orders, assigned fulfillment orders, third-party fulfillment orders, marketplace fulfillment orders, merchant-managed fulfillment orders, products, and customers, plus unauthenticated Storefront API access to product listings and their subsections. Install the app and record its consumer key and consumer secret securely.
* The generic Shopify Managed Checkout script for the theme asset, supplied by your Bolt implementation contact.
* Shopify admin access that can edit theme code.

Keep the custom app secret and every private access token out of Liquid, JavaScript, HTML, screenshots, logs, and browser storage. Only the publishable key belongs in the theme.

## 1. Prepare for installation [#1-prepare-for-installation]

1. Log in to the [sandbox Merchant Dashboard](https://merchant-sandbox.boltapp.com/), select **Administration > API**, and copy the **Publishable Key**.
2. In your Shopify admin, go to **Online Store > Themes**.
   <img alt="Shopify theme list with the current theme" src="__img0" />
3. Duplicate the published theme and name the copy clearly, for example **Bolt Managed Checkout Staging**. Record the current theme version or Git commit so you can roll back.
4. On the copy, open the **three dots** menu and select **Edit code**.
   <img alt="Theme context menu with Edit code" src="__img1" />
5. Back up `layout/theme.liquid`, the cart drawer or cart footer snippet, and the product page template before editing them.

Do all implementation and testing on the unpublished copy. If your configuration requires Bolt `track.js`, include it once.

**Expected result:** The theme code editor opens on the duplicate theme with the **Layout**, **Snippets**, and **Assets** folders in the sidebar.

## 2. Add code snippets [#2-add-code-snippets]

### Install global scripts [#install-global-scripts]

1. Open `layout/theme.liquid` and find the closing `</head>` tag.
2. Paste the three scripts before it, in this order: `connect.js`, the Managed Checkout loader, then the theme asset.

```html title="theme.liquid"
<script
  defer="defer"
  id="bolt-connect"
  type="text/javascript"
  src="https://connect-sandbox.boltapp.com/connect.js"
  data-publishable-key="PUBLISHABLE_KEY">
</script>

<script
  defer="defer"
  id="managed-checkout"
  type="text/javascript"
  data-dynamic-elements-selector="DYNAMIC_ELEMENT_SELECTOR"
  src="https://c-sandbox.boltapp.com/shopify/managed-checkout.js?v={{ 'now' | date: '%s' }}">
</script>

<script
  defer="defer"
  type="text/javascript"
  src="{{ 'bolt-connect-shopify.js' | asset_url }}">
</script>
```

3. Replace `PUBLISHABLE_KEY` with the sandbox publishable key.
4. Replace `DYNAMIC_ELEMENT_SELECTOR` with a stable parent element that stays in the page when the cart drawer re-renders. [Configure dynamic cart behavior](#4-configure-dynamic-cart-behavior) explains how to choose it.
5. Reload the storefront. Confirm all three scripts load once and the browser console shows no Content Security Policy or JavaScript errors.

<img alt="theme.liquid with the Bolt scripts in the head" src="__img2" />

### Create the Bolt asset [#create-the-bolt-asset]

1. Under **Assets**, select **Add a new asset** and create `bolt-connect-shopify.js`.
2. Paste the generic Shopify Managed Checkout script from Bolt into the asset.
3. Update the configuration block near the top of the file:

```javascript title="bolt-connect-shopify.js"
const BOLT_BUTTON_SELECTOR =
  '[data-tid*="instant-bolt-checkout-button"]';
const DYNAMIC_ELEMENTS_SELECTOR =
  "#shopify-section-cart-drawer";
const CART_TOKEN_COOKIE_NAME = "cart";
const analytics = {
  klaviyo: true,
  northbeam: true,
  google: true,
};
var debug = false;
```

4. Replace the example dynamic selector with the stable selector your theme uses.
5. Set an analytics destination to `false` when the store does not use it.
6. Leave `debug` set to `false` in production. Enable it only temporarily when you need lifecycle logging during QA.
7. If shopper prefill is required, populate only the supported hints fields, and confirm the consent and privacy requirements that apply.

## 3. Add Bolt Checkout buttons [#3-add-bolt-checkout-buttons]

### Cart drawer and cart page [#cart-drawer-and-cart-page]

1. Open the cart drawer, cart footer, or cart page snippet your theme uses.
2. Remove or comment out the native Shopify checkout control, including the element with id `CartDrawer-Checkout` when present.
3. Insert the Bolt V1 checkout button in the same visual location:

```html title="cart-drawer.liquid"
<div data-tid="instant-bolt-checkout-button" class="px-4">
  <object
    aria-label="Bolt checkout button"
    data="https://connect-sandbox.boltapp.com/v1/checkout_button?publishable_key=PUBLISHABLE_KEY">
  </object>
</div>
```

4. Replace `PUBLISHABLE_KEY`, and check that the button URL uses the host for the active environment.
5. Confirm no second native checkout button remains where Bolt is meant to be the only checkout path.
6. Add and remove products, change quantities, and apply a discount. The Bolt button must survive every cart update.

### Product page Buy Now button [#product-page-buy-now-button]

Add the product page button in the theme customizer.

1. Go to **Themes > Customize** on the duplicate theme.
   <img alt="Customize button on the theme card" src="__img3" />
2. In the top navigation dropdown, select **Products > Default product**.
   <img alt="Default product template selection" src="__img4" />
3. In the left navigation, go to **Template > Product information**.
   <img alt="Product information section in the template tree" src="__img5" />
4. In the **Buy buttons** block, turn off **Show dynamic checkout buttons**.
5. Select **Add block**, then **Custom Liquid**, at the intended product page location.
   <img alt="Add block menu with Custom Liquid" src="__img6" />
6. Paste the same Bolt V1 button markup as the cart, with the correct publishable key and environment host, and save.
7. Test the default variant, another variant, a quantity change, an unavailable variant, and the quick-add modal. Confirm `configureProductCheckout` receives the selected variant and quantity.

## 4. Configure dynamic cart behavior [#4-configure-dynamic-cart-behavior]

1. Change the cart while inspecting the theme, and note whether Shopify replaces the drawer's contents or the entire drawer element.
2. If only the contents change, use the cart drawer as the dynamic selector.
3. If the entire drawer is replaced, use a stable Shopify section or a wrapper around the drawer.
4. Keep the document-level `MutationObserver` fallback when a third-party app injects the Bolt button after page load.
5. Confirm every cart re-render produces one working Bolt button and does not repeat configure calls, callbacks, or checkout events.

## 5. Configure callbacks and analytics [#5-configure-callbacks-and-analytics]

1. Confirm the success callback clears the Shopify cart only after a successful checkout and invokes the Bolt completion callback exactly once.
2. Enable the Klaviyo Checkout Start and identify events only when Klaviyo is installed and approved.
3. Enable Northbeam email identification only when Northbeam is installed and approved.
4. Enable the Google `begin_checkout`, `add_payment_info`, and `purchase` events only when GA4 or GTM is installed and approved.
5. Check that the Google ecommerce payload contains currency, value, transaction ID, item ID, item name, price, and quantity.
6. Confirm no other storefront or order-status integration also sends `purchase` for the same order.
7. Keep analytics best-effort: an analytics failure must never stop checkout from opening or completing.

## Test your website [#test-your-website]

Every check must pass in sandbox before you move to production.

* `connect.js`, `managed-checkout.js`, and `bolt-connect-shopify.js` each load once.
* The Bolt checkout button appears on the cart page and, where applicable, the cart drawer.
* Cart changes do not remove or break the Bolt button.
* Checkout receives the correct Shopify cart token, current line items, discounts, shipping, tax, and total.
* Product Buy Now uses the selected variant and quantity, including from quick add.
* Closing and reopening checkout does not create duplicate buttons, callbacks, or events.
* A successful checkout creates one Shopify order and clears the storefront cart once.
* Enabled Klaviyo, Northbeam, GA4, and GTM events fire once with the expected payload.
* Empty cart, unavailable item, expired cart token, slow cart response, declined payment, and callback errors all recover.
* Mobile Safari, mobile Chrome, desktop Safari, and desktop Chrome pass the core flow.
* No private token, consumer secret, or other sensitive value appears in page source, console output, or browser requests.

## Move to production [#move-to-production]

1. Get approval from the merchant, the Bolt implementation owner, the analytics owner, and the QA owner.
2. Schedule the theme publication window and confirm who owns rollback.
3. Replace every sandbox Bolt script host with the production host: `connect-sandbox.boltapp.com` becomes `connect.boltapp.com`, and `c-sandbox.boltapp.com` becomes `c.boltapp.com`.
4. Replace the sandbox publishable key with the production publishable key in `connect.js` and in every Bolt button URL.
5. Check that the production build contains no sandbox hostname or sandbox credential.
6. Publish the validated theme.
7. Immediately run one cart checkout and one product Buy Now smoke test.
8. During the launch window, watch checkout-start rate, JavaScript failures, order creation, payment success, duplicate analytics events, and cart clearing.

## Roll back [#roll-back]

1. If Bolt cannot open or orders cannot complete, republish the previous theme or restore the backed-up files.
2. Restore the prior `theme.liquid` scripts, native checkout controls, and product page configuration as the rollback plan requires.
3. When it does not delay recovery, capture redacted browser errors, timestamps, cart tokens, order references, and request identifiers first.
4. Confirm the restored checkout path completes successfully.
