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

# Vue

> Integrate Commerce Engine Checkout into Vue 3 apps with the useCheckout composable. Returns reactive refs with automatic cleanup.

Hosted Checkout provides reactive Vue refs through `useCheckout()`. No plugin injection or provider component is required.

## Installation

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @commercengine/checkout
```

Choose the session owner:

| Application architecture | Mode |
| - | - |
| Hosted Checkout is the only Commerce Engine integration | `managed` |
| App also uses `@commercengine/storefront` or direct session APIs | `provided` with two-way token sync |

## Checkout-only Vue app

When the app does not use the Storefront SDK, initialize checkout before mounting the application. Checkout owns authentication and session refresh.

```typescript src/main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { createApp } from "vue";
import { initCheckout } from "@commercengine/checkout/vue";
import App from "./App.vue";

initCheckout({
  storeId: import.meta.env.VITE_STORE_ID,
  apiKey: import.meta.env.VITE_API_KEY,
  environment:
    import.meta.env.VITE_CE_ENV === "production"
      ? "production"
      : "staging",
  onComplete: ({ orderNumber }) => {
    window.location.assign(`/thank-you?order=${orderNumber}`);
  },
});

createApp(App).mount("#app");
```

For development hot-module replacement, clean up the singleton:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
if (import.meta.hot) {
  import.meta.hot.dispose(async () => {
    const { destroyCheckout } = await import("@commercengine/checkout/vue");
    destroyCheckout();
  });
}
```

## Vue app with Storefront SDK

When `@commercengine/storefront` is present, use provided mode. First send SDK token changes to checkout:

```typescript src/lib/storefront.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { getCheckout } from "@commercengine/checkout";
import {
  BrowserTokenStorage,
  Environment,
  createStorefront,
} from "@commercengine/storefront";

export const tokenStorage = new BrowserTokenStorage("brand_");

export const storefront = createStorefront({
  storeId: import.meta.env.VITE_STORE_ID,
  apiKey: import.meta.env.VITE_API_KEY,
  environment:
    import.meta.env.VITE_CE_ENV === "production"
      ? Environment.Production
      : Environment.Staging,
  session: {
    tokenStorage,
    onTokensUpdated: (accessToken, refreshToken) => {
      getCheckout().updateTokens(accessToken, refreshToken);
    },
  },
});

export const sdk = storefront.session();
```

Bootstrap before mounting Vue and send checkout token changes back to the SDK:

```typescript src/main.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { createApp } from "vue";
import { initCheckout } from "@commercengine/checkout/vue";
import App from "./App.vue";
import { sdk, tokenStorage } from "./lib/storefront";

async function start() {
  const accessToken = await sdk.ensureAccessToken();
  const refreshToken = await tokenStorage.getRefreshToken();

  initCheckout({
    storeId: import.meta.env.VITE_STORE_ID,
    apiKey: import.meta.env.VITE_API_KEY,
    environment:
      import.meta.env.VITE_CE_ENV === "production"
        ? "production"
        : "staging",
    authMode: "provided",
    accessToken: accessToken ?? undefined,
    refreshToken: refreshToken ?? undefined,
    onTokensUpdated: ({ accessToken, refreshToken }) => {
      void sdk.setTokens(accessToken, refreshToken);
    },
  });
  createApp(App).mount("#app");
}

start().catch((error) => {
  console.error("Commerce Engine startup failed", error);
});
```

## Use the composable

```vue src/components/CartButton.vue theme={"theme":{"light":"github-light","dark":"github-dark"}}
<script setup lang="ts">
import { useCheckout } from "@commercengine/checkout/vue";

const { cartCount, isReady, openCart } = useCheckout();
</script>

<template>
  <button type="button" :disabled="!isReady" @click="openCart">
    Cart ({{ cartCount }})
  </button>
</template>
```

All state values are readonly Vue refs and are automatically unwrapped in templates.

```vue src/components/AddToCartButton.vue theme={"theme":{"light":"github-light","dark":"github-dark"}}
<script setup lang="ts">
import { useCheckout } from "@commercengine/checkout/vue";

const props = defineProps<{
  productId: string;
  variantId: string | null;
  hasVariants: boolean;
}>();

const { addToCart, isReady } = useCheckout();
</script>

<template>
  <button
    type="button"
    :disabled="!isReady || (props.hasVariants && !props.variantId)"
    @click="addToCart(props.productId, props.variantId, 1)"
  >
    Add to cart
  </button>
</template>
```

Pass `null` for a product without variants. For variant products, wait until the selection resolves to a purchasable variant ID.

## Nuxt 3

Initialize Hosted Checkout in a client-only plugin. If Nuxt also uses Commerce Engine session APIs, use `@commercengine/ssr-utils` for request-bound server storage and provided mode for checkout.

```typescript plugins/checkout.client.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
export default defineNuxtPlugin(async () => {
  const { initCheckout } = await import("@commercengine/checkout/vue");

  initCheckout({
    storeId: useRuntimeConfig().public.ceStoreId,
    apiKey: useRuntimeConfig().public.ceApiKey,
    environment: useRuntimeConfig().public.ceEnvironment,
    // Add provided-mode tokens and onTokensUpdated when Storefront SDK is present.
  });
});
```

The `.client.ts` suffix prevents browser-only checkout code from entering the server bundle.

## Composable API

| Property | Type | Description |
| - | - | - |
| `isReady` | `Readonly<Ref<boolean>>` | iframe ready state |
| `isOpen` | `Readonly<Ref<boolean>>` | overlay visibility |
| `cartCount` | `Readonly<Ref<number>>` | item count |
| `cartTotal` | `Readonly<Ref<number>>` | reported cart total |
| `cartCurrency` | `Readonly<Ref<string>>` | currency code |
| `isLoggedIn` | `Readonly<Ref<boolean>>` | login state |
| `user` | `Readonly<Ref<UserInfo \| null>>` | current user |
| `openCart()` | function | open cart drawer |
| `openCheckout()` | function | open checkout directly |
| `close()` | function | close overlay |
| `addToCart(productId, variantId, quantity?)` | function | add item |
| `updateTokens(accessToken, refreshToken?)` | function | synchronize provided-mode tokens |

## Production checklist

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[ ] correct session owner selected
[ ] initialized once before app use
[ ] HMR/unmount cleanup where applicable
[ ] cart actions disabled until ready
[ ] two-way token sync when Storefront SDK is present
[ ] Nuxt checkout code remains client-only
[ ] onComplete, onError, and session recovery handled
```

<Card title="Vue and framework starters" icon="github" href="https://github.com/tark-ai/ce-starter-projects">
  Use the production starters to compare SPA behaviour with SSR framework boundaries and deployment configuration.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.