# Website embed > Show your products on any website with two lines of HTML — mockups, color and size pickers, your retail or points price — and hand the customer's pick to your own checkout or points redemption. Source: https://swaglists.com/docs/embed The embed shows your **active products** on your own website: mockups, the options of the enabled variants, and the price your customers pay — your [retail price](https://swaglists.com/docs/pricing.md#retail-prices) or its [points price](https://swaglists.com/docs/pricing.md#points). It never shows our wholesale price and carries no branding of ours. There is no checkout on our side: when a customer picks a variant, your page receives an event and your checkout (or points redemption) takes over. ## 1. Create a publishable key In **Developers → Embed**, create a publishable key and list the websites that will use it — exact origins such as `https://shop.example.com` (add `https://www.shop.example.com` separately; `http://` only for `localhost`). Publishable keys (`pk_live_…`, `pk_test_…`) are safe to put in your HTML: they only read your active products, only from those websites, and the API refuses them for everything else. Orders always use a **secret** key (`sk_…`) on your server. ## 2. Add the embed ```html
``` Load the script once per page; it renders every matching element, including ones added later (single-page apps). `/embed.js` is the current version; pin `/embed/v1.js` if you prefer. In the grid, a click shows the product in place — or set `data-product-url="/products/{id}"` to link to your own product pages instead. ## 3. Receive the customer's pick ```js document.addEventListener("swaglists:select", async (e) => { const { product_variant_id, sku, quantity, retail_price, retail_points } = e.detail; // Add to your cart, or deduct retail_points from the customer's balance, then let your // server create the order with your secret key: POST /v1/orders // { items: [{ product_variant_id, quantity }], recipient: { … } } }); ``` The event bubbles from the embed element. `e.detail` contains `product_id`, `product_variant_id`, `sku`, `title`, `variant_title`, `options`, `quantity`, `retail_price` (cents), `retail_points`, `currency` and `image_url`. Instead of listening, you can name a global function: `data-on-select="addToCart"`. `swaglists:ready` fires when a product rendered, `swaglists:error` when it could not load (the reason is also logged in the browser console). Always re-check the price on your server from [`GET /product_variants`](https://swaglists.com/docs/pricing.md#sync) before charging — anything in a browser can be changed by the customer. ## Styling Set any of these on the embed element (or once on the script tag): | Attribute | Default | | | --- | --- | --- | | `data-price` | `auto` | `auto` (points when your account shows points prices), `money`, `points`, `both` | | `data-points-label` | `points` | e.g. `pts` or your program's name | | `data-button-label` | `Add to cart` | e.g. `Redeem` | | `data-sold-out-label`, `data-from-label`, `data-back-label`, `data-more-label` | | other labels | | `data-accent`, `data-accent-text` | `#111827`, `#ffffff` | button and selection colors | | `data-text-color`, `data-muted-color`, `data-background`, `data-surface`, `data-border-color` | | colors | | `data-font` | `inherit` | your site's font by default | | `data-radius` | `10px` | corner radius | | `data-card-width` | `220px` | grid card width | | `data-quantity` | `true` | `false` hides the quantity field; `data-max-quantity` (default 10) | | `data-description` | `true` | `false` hides the description | The embed renders in a shadow root, so your page's CSS doesn't change it and its CSS doesn't leak into your page. `window.SwaglistsEmbed.refresh()` re-renders every embed (for example after a [`product.prices_changed`](https://swaglists.com/docs/events.md#product.prices_changed) webhook told your site that prices moved). ## Content Security Policy If your site sends a CSP, allow `https://swaglists.com` in `script-src`, `connect-src` and `img-src`. ## Errors The embed endpoints answer `{ "error": { "code", "message" } }`: `invalid_key` (401, unknown or revoked key), `origin_not_allowed` (403, add the website under Developers → Embed), `account_inactive` (403), `not_found` (404, the product is a draft, archived or not yours) and `rate_limited` (429).