Skip to main content
Hydrogen storefronts are custom React applications built on Remix and deployed to Oxygen. A Hydrogen store has no Liquid templates — your storefront is your own code, and the cart is a React component backed by the Storefront API. Order Protection still works on the cart page, but the integration is different from a Liquid theme: instead of the self-driving cart widget (which manages the Shopify AJAX cart for you), Hydrogen uses the API widget, which renders the same UI and pricing but leaves the cart mutation to your app. The result is the same as on any other store: the shopper toggles protection, the Order Protection line is added to the cart, and it carries through to checkout.
Two surfaces, and you can use either or both. The simplest supported option is the checkout UI extension (see the last section), which needs no Hydrogen-specific code. This guide covers the cart-page widget, which is a real integration in your Hydrogen app.
This is a reference implementation. It is built on Order Protection’s documented headless API widget, but the exact wiring depends on your Hydrogen version and cart setup, and it has not been certified against every skeleton. Build it against a preview deployment and test the full add → toggle → checkout flow before shipping to Oxygen. Your Order Protection onboarding contact (onboarding@orderprotection.com) can confirm the store-specific values called out below.

How it works

  • Order Protection ships a per-brand widget bundle at https://cdn.orderprotection.com/cart-widget/<brand-slug>/widget.js. For a Hydrogen store, that URL serves the API widget build (window.OrderProtection.init / setCartTotal / on / setState) rather than the Liquid cart widget. This is an Order Protection deploy-side setting — your onboarding contact enables it for your brand.
  • You load that script, render <order-protection> in your cart, tell the widget your cart subtotal, and listen for the toggle.
  • When protection is toggled on, your app adds the Order Protection variant to the Storefront-API cart (cartLinesAdd); when it’s off, you remove it (cartLinesRemove). Because it’s a normal cart line, it flows to cart.checkoutUrl automatically.
Design the widget first. Configure your cart widget’s appearance, copy, and pricing display in the Order Protection app, then grab its config from Get Code — see Widget Customization. The Hydrogen bundle renders whatever you’ve published there.

Prerequisites

  • A Hydrogen storefront running locally (shopify hydrogen dev).
  • Your store onboarded with Order Protection, and the API widget build deployed to your brand’s cart-widget/<brand-slug>/widget.js path (ask your onboarding contact to confirm, or verify it yourself with the check below).
  • Your brand slug (the CDN path segment, e.g. cool-store-co — the slugified brand name, not your myshopify.com domain) and your Order Protection store identifier passed to init() (typically your .myshopify.com domain — confirm with Order Protection). You can read the brand slug straight from your app URL — it’s the path segment after app.orderprotection.com/, e.g. app.orderprotection.com/order-protection-v2/settings/general means your slug is order-protection-v2.
  • The Order Protection product published to your Hydrogen sales channel so its variant is purchasable through the Storefront API. Order Protection can confirm the product is set up; publishing it to the storefront is done in Shopify admin (see the first step below).
Confirm the bundle resolves before wiring anything up — a published widget config is not the same as a deployed bundle:
200 means it’s live; 404 means the bundle still needs to be deployed — contact onboarding@orderprotection.com. No terminal handy? Open the same URL in your browser — a page of JavaScript means it’s live; a Not Found page means it isn’t deployed yet.

Installation

1

Confirm the Order Protection product is Unlisted

The Order Protection variant is added through the Storefront API, so it must be purchasable there — but you don’t want shoppers finding it and buying it on its own. Shopify’s Unlisted product status is built for exactly this (warranty-style products): unlisted products behave like active ones in the cart, checkout, and orders, but are hidden from storefront search, collections, recommendations, and your sitemap — they stay reachable only by direct link and the Storefront API.Order Protection creates the product and sets it to Unlisted for you; your job is just to confirm it. In your Shopify admin:
  1. Go to Products and open the Order Protection product (vendor: Order Protection).
  2. Its status should read Unlisted — not Active or Draft. If it doesn’t, contact onboarding@orderprotection.com.
  3. Make sure it’s available to the storefront/sales channel your Hydrogen app queries, so the Storefront API can add it. If cartLinesAdd rejects the variant, it isn’t available to your headless channel yet — confirm with Order Protection.
2

Load the widget script in your root layout

Add the script to your document in app/root.tsx, inside <body> before Remix’s <Scripts />:
app/root.tsx
The bundle registers the <order-protection> custom element and attaches window.OrderProtection (including on/off, which are available before init()).
3

Declare the custom element and the API for TypeScript

<order-protection> isn’t a known JSX element, and window.OrderProtection isn’t typed. Add a declaration (e.g. app/order-protection.d.ts):
app/order-protection.d.ts
Depending on your React version the JSX augmentation target differs — React 19 uses declare module 'react' { namespace JSX { ... } } instead of the global JSX namespace. Match whichever your project uses.
4

Add a hook that wires the widget to your Storefront-API cart

This hook does the four jobs: wait for the script, init + feed the cart subtotal, capture the current Order Protection variant, and reconcile the widget’s toggle against the actual cart line. Create app/lib/useOrderProtection.ts:
app/lib/useOrderProtection.ts
5

Render the widget in your cart summary

<order-protection> must wrap your subtotal and checkout button as direct light-DOM children (it hides/adjusts them based on toggle state). In the Hydrogen skeleton this is app/components/CartSummary.tsx:
app/components/CartSummary.tsx
The widget’s own checkout-button interception is built for the Liquid /checkout flow, not Hydrogen’s checkoutUrl anchor. This integration adds Order Protection on toggle (the hook above), so you do not need the widget to intercept your checkout button — leave your normal checkoutUrl navigation as-is.
6

Hide the Order Protection line from the cart display

Order Protection appears as a cart line with the vendor Order Protection. Filter it out of your rendered line items (never remove it from the cart — it must reach checkout). First request vendor in your cart query (e.g. app/lib/fragments.ts):
Then filter where you render lines (e.g. app/components/CartMain.tsx), and base your “cart is empty” check on the filtered list so an Order-Protection-only cart doesn’t render empty:
app/components/CartMain.tsx

Order Protection in checkout

Your checkout is hosted by Shopify even on Hydrogen (you hand off via cart.checkoutUrl), so Order Protection’s checkout-widget UI extension installs identically to any other Shopify store — no Hydrogen-specific work. Use it on its own, or alongside the cart widget above. See Checkout Extension.

Before you go live

  • Test the full flow on a preview deployment: toggle on → Order Protection line is added → it’s hidden from the cart list but present in the cart → it appears in checkout with the right price → toggle off removes it.

Follow-ups

The points most likely to need Order Protection’s involvement as you implement:
  1. API build deployment. Order Protection deploys the API widget build to your brand’s cart-widget/<brand-slug> path — it’s a deploy-side setting on their end. Confirm it’s live for your brand (see the bundle check under Prerequisites).
  2. Product published to the Storefront channel. The Order Protection product must be published to your Hydrogen Storefront sales channel, or cartLinesAdd will reject the variant.
  3. storeUrl vs. brand slug. These are two different values — the identifier passed to init() (likely your .myshopify.com domain) and the brand slug in the CDN path. Confirm both.
  4. Multi-currency / Markets. If you sell across markets, pass your presentment currency to init() and feed setCartTotal() amounts in that currency — the widget applies the exchange rate.

Support

Questions or issues during setup? Contact onboarding@orderprotection.com.