For the complete documentation index, see llms.txt. This page is also available as Markdown.

Integrate Captain Shipping Protection with a Shopify Headless Storefront

This guide explains how to add Captain Shipping Protection to a custom Shopify storefront.

It covers two integration options:

  • React storefronts: use Captain's standard widget and controller hook.

  • Other storefronts: use the framework-independent SDK and render your own UI.

Both options use the same Shopify cart and checkout flow.

Before you start

Make sure:

  • Captain Shipping Protection is configured for your Shopify store.

  • The Captain Shipping Protection product is published to the Shopify Headless sales channel used by your storefront.

  • Your storefront can read and update a Shopify cart.

  • You can install npm packages.

  • Your production storefront uses HTTPS.

  • You know the active shopper country, locale, and currency.

Important: Captain calculates which protection variant should be used, but your storefront is responsible for adding or removing Shopify cart lines.

Publish Shipping Protection to your Headless sales channel

This step is required. If the Captain Shipping Protection product is not available on the same Headless sales channel as your Storefront API token, Shopify cannot add the protection variant to the cart.

In Shopify Admin:

  1. Go to Products.

  2. Open the Captain Shipping Protection product.

  3. Find Publishing, Sales channels, or Sales channels and apps.

  4. Click Manage.

  5. Enable the Headless sales channel used by your storefront.

  6. Click Done, then save the product if Shopify asks you to save.

The channel name depends on your Shopify setup. Select the channel associated with the Storefront API token used by this headless storefront.

If you have multiple Headless channels, publishing the product to a different channel is not sufficient. The protection product must be available to the exact channel making the cart request.

You can verify the setup by querying the protection product or variant through the same Storefront API token. Shopify must return the product and allow its variant to be used as merchandiseId in cartLinesAdd.

Choose an integration

Use the React package when

  • Your storefront uses React 18 or later.

  • You want Captain's standard widget.

  • You want checked, loading, error, and cleanup state managed for you.

Install:

Use the Core SDK when

  • Your storefront uses Vue, Svelte, Angular, Solid, or Vanilla JavaScript.

  • You already have a shipping protection UI.

  • You want full control over state and presentation.

Install:

How the integration works

Captain recommends adding protection only when checkout begins:

  1. Read the current Shopify cart.

  2. Convert it to Captain's cart format.

  3. Ask Captain for the current price, variant, and eligibility.

  4. Show the protection option when the cart is eligible.

  5. Store the shopper's checked choice in your storefront.

  6. If the cart already contains protection, remove that line and keep the shopper checked.

  7. When checkout begins, request the latest protection information.

  8. Add one unit of the latest variant when the shopper is checked.

  9. Redirect immediately to the checkout URL returned by Shopify.

This approach avoids repeatedly changing the Shopify cart while the shopper edits products or quantities.

Important: Toggling the widget records shopper intent only. It should not immediately add or remove a Shopify cart line.

Prepare your Shopify cart data

Both packages require the same SdkCartData structure.

Shopify Storefront GraphQL returns GIDs and decimal money strings. Captain expects numeric Shopify IDs and integer minor-unit prices.

For USD:

  • "12.99" from Shopify becomes 1299.

  • "100.00" from Shopify becomes 10000.

Use a cart mapper like this:

Create a new mapped cart whenever products, quantities, discounts, currency, or line prices change.

Option A: React integration

The recommended React integration combines:

  • ShippingProtectionWidget for the standard UI.

  • useShippingProtectionController for Captain state and requests.

Add the controller

Replace the adapter props with your Storefront API or Hydrogen cart implementation.

React state behavior

The controller handles these rules:

  • Uses the merchant's default checked setting on the first eligible cart.

  • Keeps the shopper's checked choice when the cart changes.

  • Sets the widget to checked when an existing protection line is found.

  • Calls removeProtection() to clean up that existing line.

  • Prevents duplicate cleanup requests.

  • Hides the widget when the cart is excluded.

  • Recalculates the latest price and variant in prepareCheckout().

React checkout behavior

prepareCheckout() returns:

  • ShippingProtectionInfo when protection should be added.

  • null when the shopper is unchecked or the cart is excluded.

  • null when an existing protection line could not be safely cleaned up.

After receiving protection info:

  1. Convert variantsId to a Shopify ProductVariant GID.

  2. Add exactly one unit to the cart.

  3. Use the checkout URL returned by that mutation.

  4. Redirect immediately.

Do not remain on the cart page after adding protection. The cart-page controller removes existing protection so the next checkout attempt can calculate a fresh variant.

Option B: Core SDK integration

The Core SDK returns plain data and works with any browser framework.

Initialize the SDK

Call init() again if the active shop, country, locale, or currency changes.

Request protection information

The response includes:

Manage your UI state

The Core SDK does not store checked state. Use your framework's normal state management.

Implement removeProtectionLinesByProductId, refreshHostCart, and renderProtection in your application.

Prepare checkout with the Core SDK

Connect the Shopify Storefront Cart API

Both integration options require the host storefront to add and remove cart lines.

Add protection at checkout

Use Shopify's cartLinesAdd mutation:

Variables:

Remove existing protection

Find cart lines whose Shopify product ID matches info.productId, then remove their cart line IDs with cartLinesRemove:

Match by product ID, not only by variant ID. Captain may choose a different variant when the eligible cart total changes.

Always check Shopify userErrors before updating your local cart or redirecting.

SSR storefronts

Run Captain SDK operations in the browser.

Next.js App Router

Place the integration in a Client Component:

Pass serializable cart data from your Server Component to the Client Component.

Hydrogen, Remix, Nuxt, and SvelteKit

You can load the Shopify cart on the server, but initialize Captain after the component mounts or from browser-only cart code.

Do not call init(), getInfo(), or prepareCheckout() during the server render.

Content Security Policy

Captain sends configuration and eligibility requests to:

If your storefront has a Content Security Policy, add this origin to connect-src:

The React widget may display a merchant-configured external icon. If your CSP restricts images, add the icon's exact origin to img-src.

Captain does not require an external script, iframe, or font origin. Do not add broad permissions such as * or 'unsafe-inline' solely for this integration.

Understand common states

The widget is visible and checked

The shopper wants protection. Do not add it yet. Add the latest variant when checkout begins.

The widget is visible and unchecked

Continue checkout without adding protection.

includedProtection is true

The Shopify cart already contains Captain's protection product:

  1. Keep the widget checked.

  2. Remove all matching protection lines.

  3. Refresh your host cart.

  4. Keep checked enabled after the cart refresh.

isExcluded is true

Hide the widget and continue checkout without protection.

Common exclusion reasons include:

  • empty_cart

  • invalid_cart

  • only_shipping_protection

  • excluded_variant

  • check_display_hidden

Treat exclusion reasons as extensible.

Captain requests fail

Hide or disable the protection UI and allow checkout without protection unless your business requirements say otherwise.

Test your integration

Before deployment, test:

  • An eligible cart with the widget checked.

  • An eligible cart with the widget unchecked.

  • An empty cart.

  • A cart containing only protection.

  • A cart containing an excluded variant.

  • Quantity changes that select a different protection price.

  • A cart loaded with an existing protection line.

  • Failure while removing an existing protection line.

  • Failure while adding protection.

  • A stale response from an older cart request.

  • A storefront with CSP enabled.

  • Checkout redirect with and without protection.

Troubleshooting

The widget does not appear

Check:

  • The store has an active Captain configuration.

  • SDK initialization completed.

  • info.isExcluded and info.excludedReason.

  • Cart product and variant IDs are valid numeric IDs.

  • Browser requests are not blocked by CSP or CORS.

Toggling does not add a Shopify cart line

This is expected. The toggle stores intent only. Add the variant returned by the latest Captain request when checkout begins.

The protection price is incorrect

Verify:

  • total_price uses integer minor units.

  • Every final_line_price uses integer minor units.

  • The latest cart is passed after products, quantities, or discounts change.

  • Existing protection is included in mapped cart data so Captain can subtract it from the eligible total.

Shopify cannot add the returned variant

Convert a numeric variant ID to:

Then confirm the Captain Shipping Protection product is published to the exact Headless sales channel associated with your Storefront API token.

When the product is not published to that channel, Shopify commonly returns an error similar to:

The variant may exist in Shopify Admin and still be unavailable to your headless storefront. Open the protection product's publishing settings, enable the correct Headless channel, save, and retry with the same Storefront token.

Duplicate protection lines appear

Before adding protection:

  • Remove lines matching info.productId.

  • Refresh the cart.

  • Request Captain info again.

  • Add exactly one unit of the returned variant.

Protection is removed immediately after checkout starts

Add protection and redirect immediately using the checkout URL returned by the same mutation. Do not publish the updated cart back to the visible cart page and remain there.

Go-live checklist

  • Captain Shipping Protection is configured for the store.

  • The Shipping Protection product is published to the exact Headless sales channel used by the Storefront API token.

  • The correct npm package or packages are installed.

  • Shopify GIDs and money values are mapped correctly.

  • The active country, locale, and currency are passed to Captain.

  • The UI updates after every relevant cart change.

  • Shopper toggle behavior changes intent only.

  • Existing protection lines are removed by product ID.

  • Checkout waits for protection cleanup to finish.

  • The latest variant is requested immediately before checkout.

  • Exactly one protection line is added.

  • Shopify userErrors are handled.

  • Checkout redirects using the updated cart URL.

  • CSP allows https://insurance.captaintop.com.

  • Error paths allow the shopper to continue checkout safely.

Package reference

For complete API and type details:

  • React package: captain-shipping-protection-react

  • Framework-independent SDK: captain-shipping-protection-sdk

Last updated