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

# Embed checkout pages and storefronts

> Add Nautilus purchase experiences to your website and preselect a location or product

Use a Nautilus checkout page or storefront as a hosted link, button destination, or auto-resizing inline embed. Both surfaces support preselecting a location and product.

## Choose a surface

| Surface       | Use it when                                                                | URL format                                                    |
| ------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------- |
| Checkout page | You want a curated campaign, offer, or subset of locations and products.   | `https://www.nautilus-app.com/c/checkout/CHECKOUT_LINK_ID`    |
| Storefront    | You want the organization's complete public catalog, filtered by location. | `https://www.nautilus-app.com/c/storefront/ORGANIZATION_SLUG` |

A checkout page exposes only the locations and products configured on that page. If the page is deactivated or deleted, its direct links and embeds stop working.

A storefront reads the organization's public catalog. Only storefront-visible locations and published products appear.

## Get the base URL

In Nautilus, open **Checkout Pages**.

For a checkout page:

1. Open the checkout page you want to integrate.
2. Click **Copy link** to copy its hosted URL.
3. Click **Embed code**, select **Inline embed**, and click **Copy code**.
4. Click **View live page** to test the customer experience.

For the full storefront:

1. Click **Preview** to open the organization's storefront.
2. Or open **Edit Storefront**, select a location, and click **Live Checkout**.

Use the exact URL Nautilus generates. The examples below use placeholders that you must replace.

## Preselect a location and product

Nautilus reads these case-sensitive query parameters:

| Parameter     | Value               | Behavior                                                                           |
| ------------- | ------------------- | ---------------------------------------------------------------------------------- |
| `locationId`  | Nautilus site ID    | Selects a location available on the checkout page or storefront.                   |
| `productId`   | Nautilus product ID | Selects a product available at the selected location and on the selected surface.  |
| `embedded`    | `true`              | Enables iframe-friendly presentation. The Nautilus loader adds this automatically. |
| `transparent` | `true`              | Makes the storefront's outer background transparent. Storefront only.              |

### Select a location

Checkout page:

```text theme={null}
https://www.nautilus-app.com/c/checkout/CHECKOUT_LINK_ID?locationId=SITE_ID
```

Storefront:

```text theme={null}
https://www.nautilus-app.com/c/storefront/ORGANIZATION_SLUG?locationId=SITE_ID
```

The customer lands on the selected location and chooses from that location's available products.

### Select a location and product

Checkout page:

```text theme={null}
https://www.nautilus-app.com/c/checkout/CHECKOUT_LINK_ID?locationId=SITE_ID&productId=PRODUCT_ID
```

Storefront:

```text theme={null}
https://www.nautilus-app.com/c/storefront/ORGANIZATION_SLUG?locationId=SITE_ID&productId=PRODUCT_ID
```

Always include `locationId` when you include `productId`. Products are location-specific. The product must belong to the selected location and be available on the chosen surface.

Do not substitute a POS item ID, Stripe price ID, product name, location name, or organization slug for a Nautilus site or product ID.

### Get the correct IDs

The safest method is to copy them from a working customer flow:

1. Open the live checkout page or storefront from Nautilus.
2. Select the intended location.
3. Select the intended product.
4. Copy the resulting browser URL. Nautilus adds `locationId` and `productId` as the selection changes.
5. Open the copied URL in a clean browser session.
6. Confirm the visible location, product name, price, and purchase terms.

You can also retrieve sites, products, and checkout links through the [Nautilus API](/api-reference/introduction).

<Warning>
  Invalid, hidden, or mismatched IDs can return a valid page that falls back to the location or product selection screen. An HTTP `200` response does not prove that preselection worked.
</Warning>

## Add a link or button

Use the preselected URL as a normal link:

```html theme={null}
<a
  href="https://www.nautilus-app.com/c/checkout/CHECKOUT_LINK_ID?locationId=SITE_ID&productId=PRODUCT_ID"
  target="_blank"
  rel="noopener noreferrer"
>
  Buy now
</a>
```

For a storefront, change the `href` to the storefront URL:

```html theme={null}
<a
  href="https://www.nautilus-app.com/c/storefront/ORGANIZATION_SLUG?locationId=SITE_ID&productId=PRODUCT_ID"
  target="_blank"
  rel="noopener noreferrer"
>
  Buy now
</a>
```

## Embed a checkout page

The Nautilus loader creates the iframe, enables payment and geolocation permissions, adds `embedded=true`, and automatically resizes the iframe as its content changes.

```html theme={null}
<div
  data-nautilus-embed="checkout"
  data-src="/c/checkout/CHECKOUT_LINK_ID?locationId=SITE_ID&productId=PRODUCT_ID"
  data-height="800px"
></div>

<script>
  window.NautilusEmbedConfig = {
    baseUrl: "https://www.nautilus-app.com",
  };
</script>
<script src="https://www.nautilus-app.com/embed/loader.js"></script>
```

Paste the `<div>` where the checkout should appear. Define `window.NautilusEmbedConfig` before you load `loader.js`. Load `loader.js` only once per page.

`data-height` sets the initial minimum height while automatic resizing starts.

## Embed a storefront

Use the same loader with `data-nautilus-embed="storefront"`:

```html theme={null}
<div
  data-nautilus-embed="storefront"
  data-src="/c/storefront/ORGANIZATION_SLUG?locationId=SITE_ID&productId=PRODUCT_ID"
  data-height="800px"
></div>

<script>
  window.NautilusEmbedConfig = {
    baseUrl: "https://www.nautilus-app.com",
  };
</script>
<script src="https://www.nautilus-app.com/embed/loader.js"></script>
```

To show the host website's background behind the storefront, add `transparent=true` to `data-src`:

```html theme={null}
<div
  data-nautilus-embed="storefront"
  data-src="/c/storefront/ORGANIZATION_SLUG?locationId=SITE_ID&productId=PRODUCT_ID&transparent=true"
  data-height="800px"
></div>
```

## Handle a completed purchase

Set `onSuccess` before loading the Nautilus script. It can redirect the host page:

```html theme={null}
<script>
  window.NautilusEmbedConfig = {
    baseUrl: "https://www.nautilus-app.com",
    onSuccess: "https://example.com/thank-you",
  };
</script>
```

Or it can run a callback:

```html theme={null}
<script>
  window.NautilusEmbedConfig = {
    baseUrl: "https://www.nautilus-app.com",
    onSuccess(event) {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({ event: "nautilus_purchase_completed" });
    },
  };
</script>
```

Treat the callback as a conversion signal, not as the source of payment truth. Use Nautilus purchase records or a server-side integration for reconciliation.

## Use the loader on a dynamic site

If your application adds an embed container after `loader.js` has loaded, initialize new containers after rendering:

```js theme={null}
window.NautilusEmbed.init();
```

You can also create an embed directly:

```html theme={null}
<div id="checkout-container"></div>
<script>
  window.NautilusEmbed.create({
    target: "#checkout-container",
    src: "/c/checkout/CHECKOUT_LINK_ID?locationId=SITE_ID&productId=PRODUCT_ID",
    height: "800px",
  });
</script>
```

## Use a plain iframe

Use the Nautilus loader whenever possible. If a CMS blocks custom JavaScript, use a fixed-height iframe:

```html theme={null}
<iframe
  title="Purchase a car wash"
  src="https://www.nautilus-app.com/c/checkout/CHECKOUT_LINK_ID?locationId=SITE_ID&productId=PRODUCT_ID&embedded=true"
  style="width: 100%; height: 900px; border: 0; display: block"
  loading="lazy"
  allow="geolocation; payment"
></iframe>
```

This fallback does not resize automatically. Replace its `src` with the storefront URL when embedding a storefront.

The `payment` permission is required for browser wallets such as Apple Pay or Google Pay when the browser and payment configuration support them.

## Configure Content Security Policy

If your website uses a restrictive Content Security Policy, allow the Nautilus frame and scripts. Merge these origins into your existing policy:

```text theme={null}
script-src https://www.nautilus-app.com https://cdn.jsdelivr.net;
frame-src https://www.nautilus-app.com;
```

If your policy requires a nonce or hash for inline scripts, apply your normal CSP mechanism to the `NautilusEmbedConfig` block.

The loader fetches `@iframe-resizer/parent` from jsDelivr. Contact Nautilus if you must self-host that dependency.

## Preserve campaign attribution

The loader preserves parameters already present in `data-src`. It also forwards non-empty query parameters from the host page, supporting attribution parameters such as UTMs and click IDs.

Do not place customer personal information, credentials, access tokens, or other secrets in the host page URL.

## Verify the integration

Test every location and product combination your website exposes:

1. Click the website's source link or button.
2. Confirm the destination URL contains the expected `locationId` and `productId`.
3. Reload that exact URL in a clean browser session.
4. Confirm the visible location, product name, price, recurrence or trial terms, and organization branding.
5. For an inline embed, test desktop and mobile widths, automatic height changes, scrolling, and browser-wallet availability.
6. Keep a normal direct-link fallback available if the host site's scripts or CSP prevent the embed from loading.

Only complete a test purchase when the environment, payment method, and customer scope are explicitly authorized.

## Troubleshoot the integration

### The wrong product is selected

* Confirm the parameter names are exactly `locationId` and `productId`.
* Confirm both values came from the same working location and product selection.
* Confirm the product belongs to the selected location and remains available on the checkout page or storefront.
* Test from a clean URL instead of relying on browser history.

### The embed is blank

* Open the direct checkout page or storefront URL and confirm it works.
* For a checkout page, confirm the page is active.
* Confirm the host site allows custom scripts and iframes.
* Check the browser console for blocked requests to `www.nautilus-app.com` or `cdn.jsdelivr.net`.
* Confirm `loader.js` loads after `window.NautilusEmbedConfig` is defined.

### The embed does not resize

* Confirm the host can load `https://cdn.jsdelivr.net/npm/@iframe-resizer/parent@5`.
* Confirm the iframe URL includes `embedded=true`. The loader adds it automatically.
* Keep a reasonable `data-height` so the checkout remains usable if the resize script is blocked.

### Apple Pay or Google Pay is missing

* Use the Nautilus loader, which grants the iframe payment permission.
* For a manual iframe, include `allow="geolocation; payment"`.
* Wallet display still depends on browser, device, domain, and payment-provider eligibility.
