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.
isLive: true and the surfaces you expect. This is the fastest go/no-go in the whole list.// 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.
| Message | Level | What it means |
|---|---|---|
Config fetched — isLive: … | active surfaces: … | debug | Your 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 card | warn | Same 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. | warn | The block is enabled but has no selector on either surface. Set one in the theme editor under App embeds |
Injection target not found: … | warn | Your selector matched nothing on this page. The most common real placement bug — check it against the live DOM for that surface |
Injection target found: … | debug | The selector resolved and the block was injected |
Failed to initialize pay card: / pay link: | error | Croissant 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: | error | Same cause, from the info modal block. The button may still render while the modal does not |
Failed to resolve Croissant Pay state: | error | Croissant 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: | error | The 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: | error | Remove 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.
| Host | Purpose | If it fails |
|---|---|---|
cdn.croissant.com | Your store's Croissant settings and assets | Nothing renders. If this request fails, start by confirming the domain is registered with Croissant |
api.retailer.croissant.com | Croissant Pay API | The block falls back to showing the plain button. Not every response here is an error — Croissant uses these to decide what to display |
croissant.com | The hosted Croissant Pay session the shopper is sent to | The shopper cannot authorize |
api.event.croissant.com | Button impression and click analytics | Nothing user-facing. Analytics never block the button or checkout |
Symptoms and Causes
| Symptom | Likely cause |
|---|---|
| Nothing renders anywhere, no console warnings | The app embed is not enabled on this theme — check App embeds, and remember a duplicated theme starts with them off |
Console says Config not live | Croissant has not switched the integration live yet |
Console says Injection target not found | Selector does not match this surface's DOM |
| Renders in the drawer but not on the cart page | The cart page injection target is empty, or needs a different selector from the drawer |
| Info icon does nothing | The Croissant Info Modal app embed is not enabled |
| Button renders but disappears when the drawer reopens | Expected 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 store | The checkout block is not placed. On Plus, that block applies the discounts |
| Authorization works, no discounts at checkout, non-Plus store | Cart 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 working | Your discount is not set to combine. See stacking rules |
Shopper returns to a .myshopify.com URL | Croissant does not have your custom domain on file |
| The cart page reloads itself once after authorizing | Expected on non-Plus — it is how discounted totals get rendered |
| Button never reappears after testing | You still have an active authorized session. Use Remove Croissant to void it |
| Orders missing from Croissant | Order 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 theme | Set 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 →