> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shoppex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed Security & Troubleshooting

> CSP, origin safety, and production checklist for Checkout Embed SDK

This guide covers secure production setup and common embed issues.

## Security Model

<Note>
  The SDK protects modal message handling by validating iframe origin before processing events.
  Only messages from trusted origins are accepted — forged `postMessage` events from random origins are ignored.
</Note>

Trusted origins:

* `https://checkout.shoppex.io`
* local development origin for checkout app

Because of this, forged `postMessage` events from random origins are ignored.

***

## CSP Setup

<Warning>
  If you enforce a Content Security Policy and omit the required `frame-src` and `script-src` rules, the checkout iframe will be blocked entirely. Customers will see a blank modal or a browser console error instead of the payment form. Always test your CSP in production, not only locally.
</Warning>

If you run strict CSP, allow checkout iframe + script and pass a nonce to `Shoppex.init`.

Example policy:

```http theme={"system"}
Content-Security-Policy:
  frame-src https://checkout.shoppex.io;
  script-src 'self' 'nonce-YOUR_NONCE' https://checkout.shoppex.io;
  style-src 'self' 'nonce-YOUR_NONCE';
```

SDK init with nonce:

```javascript theme={"system"}
Shoppex.init({ nonce: 'YOUR_NONCE' });
```

Why this matters:

* The SDK injects styles into its shadow root.
* The `nonce` allows those injected styles under strict CSP.

***

## Return URL Safety

<Warning>
  Never pass unvalidated user input as `returnUrl`. An attacker could exploit this as an open redirect, sending customers to a phishing page after checkout completes. Always use a hardcoded or server-validated URL.
</Warning>

Use a trusted application URL for `returnUrl`.

```javascript theme={"system"}
Shoppex.open({
  items: [{ productId: 'PRODUCT_ID' }],
  returnUrl: 'https://app.example.com/checkout/success'
});
```

Avoid sending unvalidated user input directly as `returnUrl`.

***

## Production Checklist

<Steps>
  <Step title="Use HTTPS everywhere">
    The embed modal runs inside a cross-origin iframe. Most browsers block mixed content, so your host page must be served over HTTPS.
  </Step>

  <Step title="Load the embed script from the correct origin">
    Always load from `https://checkout.shoppex.io/embed/embed.iife.js` — never self-host or proxy the script, as it needs to match the iframe origin.
  </Step>

  <Step title="Bind event handlers">
    Listen for `shoppex:success` and `shoppex:error` events so your app knows when a payment completed or failed. Without these, your UI has no feedback loop.
  </Step>

  <Step title="Track conversions">
    Fire your analytics conversion event inside the `shoppex:success` handler. This is the only reliable moment to attribute a sale to your funnel.
  </Step>

  <Step title="Validate product and variant IDs">
    Double-check that `data-shoppex-product-id` and `data-shoppex-variant-id` values match real products. Invalid IDs silently fail to open the modal.
  </Step>

  <Step title="Test dark mode and mobile viewports">
    The modal adapts to `prefers-color-scheme` and small screens. Test both to catch layout issues before your customers do.
  </Step>

  <Step title="Validate CSP in production">
    Your local dev server likely has no CSP. Test your Content Security Policy on the real production domain — CSP violations only surface there.
  </Step>
</Steps>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Modal does not open">
    **Checklist:**

    * Script is loaded.
    * Element has valid `data-shoppex-product-id`, `data-shoppex-group-id`, or `data-shoppex-items`.
    * `items` contains at least one non-empty `productId`, unless you pass a valid `groupId`.
    * No JavaScript error before click handler runs.
  </Accordion>

  <Accordion title="Wrong product opens">
    **Cause:**
    Multiple `items` currently resolve to first valid item in modal flow.

    **Fix:**
    Pass one item per checkout open until multi-item modal support lands.
  </Accordion>

  <Accordion title="Event listeners do not fire">
    **Checklist:**

    * Listen on `document`, not only on button element.
    * Ensure checkout completed successfully for `shoppex:success`.
    * Verify browser extensions/policies are not blocking cross-origin frames.
  </Accordion>

  <Accordion title="Modal appears behind custom UI">
    **Use low-risk defaults:**

    * Avoid custom overlays with extreme z-index values.
    * Test with your cookie/privacy banners and support widgets.
  </Accordion>

  <Accordion title="Dynamic content buttons do not open checkout">
    The SDK auto-observes DOM changes, but make sure:

    * New nodes actually include `data-shoppex-product-id`, `data-shoppex-group-id`, or `data-shoppex-checkout`.
    * Your frontend does not stop propagation on click before SDK handler runs.
  </Accordion>
</AccordionGroup>

***

## Debug Helpers

Simple runtime checks:

```javascript theme={"system"}
console.log('Shoppex available:', typeof window.Shoppex !== 'undefined');
```

```javascript theme={"system"}
document.addEventListener('shoppex:error', (event) => {
  console.error('Embed error:', event.detail.error);
});
```

***

## Related Docs

<CardGroup cols={2}>
  <Card title="Embed SDK Overview" icon="window-maximize" href="/guides/embeds">
    Start here for integration patterns.
  </Card>

  <Card title="Embed SDK Reference" icon="book" href="/guides/embeds-reference">
    Full API, attributes, and event details.
  </Card>

  <Card title="Embed Snippets" icon="code" href="/guides/embeds-snippets">
    Copy-paste code snippets for common embed scenarios.
  </Card>
</CardGroup>
