Testing & Troubleshooting

The Croissant blocks log exactly why they did or did not render. Once you know how to read those logs, almost every integration problem resolves in a minute — so start here rather than guessing at selectors.

Getting a Test Store

Read this before you plan the work, because two of these will otherwise block you on day one.

  • Every store domain must be registered with Croissant. A dev store, a staging store, or a clone is a separate domain, and Croissant enables the integration per domain. On an unregistered domain nothing renders. Send your Croissant contact the exact domains you intend to test on, early.
  • Authorizations in testing are real. They place a real hold on a real card. Ask your Croissant contact to set you up with a test account before you start; do not test with a personal card.
  • Password-protected and unpublished stores work. The shopper leaves for the Croissant session and returns in the same browser session, so store password protection is not a problem.
  • Reset between runs with Remove Croissant on the cart block. If you leave an authorization in place, starting again picks it back up instead of giving you a fresh run.

Verification Checklist

Work through it in order. The first step that fails localizes the problem.

1App settings — the Croissant app in your admin reads Connected, with all five discounts and the pixel Active.
2Discounts — the five Croissant discounts exist in Discounts in the Shopify admin, original titles, no duplicates. The admin list is the source of truth, not the app page.
3Console — load the cart with the console open and confirm the configuration line reports isLive: true and the surfaces you expect. This is the fastest go/no-go in the whole list.
4Storefront — the CTA appears at every configured injection target, in the drawer and on the cart page, and matches your theme's button style. Click the info icon and confirm the modal opens.
5Session — click through, authorize with your test account, and return. On non-Plus you land back on the cart, which reloads once and shows the authorized state; on Plus you land in checkout.
6Cart state — on Basic, Grow, and Advanced, confirm the Croissant cart attributes are present (snippet below). Skip this step on Plus, where the checkout block handles it and no cart attributes are added.
7Checkout — the expected Croissant discount lines appear and sum to the authorized total, and shipping shows as free.
8Order — place it, confirm the Croissant attributes are on the order, then check it appears in Reporting within a few minutes.
9Edge cases — change the cart after authorizing and confirm the reauthorize prompt, apply a gift card and confirm the notice, and switch to a non-USD currency and confirm the block hides.
js
// Step 6 — run on the storefront after returning from the session
fetch("/cart.js")
  .then((r) => r.json())
  .then(({ attributes, items_subtotal_price }) =>
    console.log({ attributes, items_subtotal_price })
  );

Console Diagnostics

Every message from the theme blocks is prefixed [Croissant]. Filter the console on that string and you get a decision trace for the current page.

Tip
The informational lines are logged at debug level, which Chrome hides by default. Set the console log level to include Verbose, or you will see only warnings and errors and conclude nothing is running.
MessageLevelWhat it means
Config fetched — isLive: … | active surfaces: …debugYour store's settings loaded. isLive: false means Croissant has not switched the integration live yet, and nothing will render until it does. If a surface you configured is missing from the list, its injection target is empty
Config not live, hiding cardwarnSame cause, and the single most common reason for “I set everything up and see nothing”. Ask Croissant to switch you live
No injection target configured for any surface.warnThe block is enabled but has no selector on either surface. Set one in the theme editor under App embeds
Injection target not found: …warnYour selector matched nothing on this page. The most common real placement bug — check it against the live DOM for that surface
Injection target found: …debugThe selector resolved and the block was injected
Failed to initialize pay card: / pay link:errorCroissant could not load your store's settings. Confirm this domain is registered with Croissant, then check the network tab for a blocked or failing request
Failed to fetch config for modal:errorSame cause, from the info modal block. The button may still render while the modal does not
Failed to resolve Croissant Pay state:errorCroissant could not determine the current state of this cart, so it fell back to showing the plain button. Usually transient — retry before investigating
Failed to initiate pay session:errorThe click could not read or update the cart. Suspect custom cart code intercepting Shopify's AJAX cart
Failed to void session: / Failed to void before reauthorizing:errorRemove Croissant or Reauthorize could not reach Croissant. The shopper is not left stuck, but report it if it repeats

Network Requests

Four hosts are involved. Filter the network tab on croissant.com to see all of them.

HostPurposeIf it fails
cdn.croissant.comYour store's Croissant settings and assetsNothing renders. If this request fails, start by confirming the domain is registered with Croissant
api.retailer.croissant.comCroissant Pay APIThe block falls back to showing the plain button. Not every response here is an error — Croissant uses these to decide what to display
croissant.comThe hosted Croissant Pay session the shopper is sent toThe shopper cannot authorize
api.event.croissant.comButton impression and click analyticsNothing user-facing. Analytics never block the button or checkout
Info
Privacy extensions and ad blockers sometimes block the analytics host. That is harmless. If a blocker also blocks the CDN or retailer API, the button will not render — worth ruling out before you debug a selector, and worth remembering if your consent tooling gates third-party requests.

Symptoms and Causes

SymptomLikely cause
Nothing renders anywhere, no console warningsThe app embed is not enabled on this theme — check App embeds, and remember a duplicated theme starts with them off
Console says Config not liveCroissant has not switched the integration live yet
Console says Injection target not foundSelector does not match this surface's DOM
Renders in the drawer but not on the cart pageThe cart page injection target is empty, or needs a different selector from the drawer
Info icon does nothingThe Croissant Info Modal app embed is not enabled
Button renders but disappears when the drawer reopensExpected briefly — re-injection restores it. If it stays gone, your theme is replacing the container the selector points at
Authorization works, no discounts at checkout, Plus storeThe checkout block is not placed. On Plus, that block applies the discounts
Authorization works, no discounts at checkout, non-Plus storeCart attributes are missing or being cleared — inspect /cart.js, then audit cart-editing apps and custom AJAX cart code
Croissant discount applies, but your own promotion stops workingYour discount is not set to combine. See stacking rules
Shopper returns to a .myshopify.com URLCroissant does not have your custom domain on file
The cart page reloads itself once after authorizingExpected on non-Plus — it is how discounted totals get rendered
Button never reappears after testingYou still have an active authorized session. Use Remove Croissant to void it
Orders missing from CroissantOrder attributes stripped by another system, Reporting lag, or the app was uninstalled when the order was placed
Button style looks unlike the rest of the themeSet a style source instead of hand-tuning; reset overrides to inherit and re-tune from there

Getting Help

Contact your Croissant integration contact or support@croissant.com. Include the store domain, the Shopify order name, the session id from the order's _croissant_pay_session_id attribute, and any [Croissant] console output. That set is enough to trace any order or failed render end to end.


Back to Shopify Integration overview →