---
title: "Polar"
description: "The Vue port of @convex-dev/polar/react — the CheckoutLink and CustomerPortalLink billing components, auto-registered and resolved from api.billing."
canonical_url: "https://nuxt-convex-module.dev/components/polar"
---
# Polar

> The Vue port of @convex-dev/polar/react — the CheckoutLink and CustomerPortalLink billing components, auto-registered and resolved from api.billing.

A Vue port of `@convex-dev/polar/react`'s two billing components. [Polar](https://polar.sh) handles the checkout and the customer portal; this package ports only the framework-side links that open them.

<upstream-baseline source="polar">

Matches upstream @convex-dev/polar@0.9.2 (react components).

</upstream-baseline>

## Install

<pm-install packages="@convex-dev/polar@~0.9.0 @polar-sh/checkout">

```bash [pnpm]
pnpm add @convex-dev/polar@~0.9.0 @polar-sh/checkout
```

```bash [npm]
npm i @convex-dev/polar@~0.9.0 @polar-sh/checkout
```

```bash [yarn]
yarn add @convex-dev/polar@~0.9.0 @polar-sh/checkout
```

```bash [bun]
bun add @convex-dev/polar@~0.9.0 @polar-sh/checkout
```

</pm-install>

The components register globally on the next dev run. Auto-registration is a Nuxt convenience — in a [plain Vue](https://nuxt-convex-module.dev/guide/plain-vue) app, import them from `nuxt-convex-module/polar/vue` and register them yourself.

## Configure

Convex-side setup (`convex.config.ts`, the `Polar` instance and its exported actions) is unchanged from [`@convex-dev/polar`'s guide](https://www.convex.dev/components/polar). Nothing is needed in `nuxt.config.ts` beyond `convex.polar: false` if you want to force the components off.

Both components read the Polar action references (`generateCheckoutLink`, `generateCustomerPortalUrl`) from the auto-provided `api.billing` namespace — so unlike upstream's required `polarApi` prop, passing it is optional here. Use `:polar-api` to override.

## Use

<playground-billing>



</playground-billing>

```vue
<template>
  <!-- Auto-registered, no imports. Actions resolve from `api.billing`. -->
  <CheckoutLink :product-ids="['demo-product']" :embed="false" target="_blank">
    Buy demo product
  </CheckoutLink>

  <CustomerPortalLink return-url="/components/polar">
    Manage subscription
  </CustomerPortalLink>
</template>
```

The components above are the **real published ones**, but this site has no Polar account behind it: the Convex actions are **demo stand-ins** that implement `@convex-dev/polar`'s exact action contract and return `sandbox.polar.sh` URLs. That is also why the demo passes `:embed="false"` — the sandbox URL is not a real Polar checkout, so it must open as a plain link instead of the embedded overlay. With a real Polar setup you keep the default `embed`, and every prop below works as upstream documents.

### `<CheckoutLink>`

Renders a Polar checkout link — embedded modal (default) or redirect — with optional lazy generation and trial configuration:

```vue
<template>
  <CheckoutLink :product-ids="[productId]" :trial-interval-count="7" trial-interval="day">
    Start free trial
  </CheckoutLink>
</template>
```

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Purpose
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        product-ids
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      Products offered at checkout
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        polar-api
      </code>
    </td>
    
    <td>
      <code>
        PolarComponentApi
      </code>
    </td>
    
    <td>
      <code>
        api.billing
      </code>
    </td>
    
    <td>
      Override the action references
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        embed
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Embedded modal; set <code>
        :embed="false"
      </code>
      
       to open the Polar checkout page instead
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lazy
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Generate the checkout URL on click instead of on mount
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        theme
      </code>
    </td>
    
    <td>
      <code>
        'dark' | 'light'
      </code>
    </td>
    
    <td>
      <code>
        'dark'
      </code>
    </td>
    
    <td>
      Embedded checkout theme
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        subscription-id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Upgrade/change an existing subscription
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metadata
      </code>
    </td>
    
    <td>
      <code>
        Record<string, string>
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Extra checkout metadata
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        trial-interval
      </code>
    </td>
    
    <td>
      <code>
        'day' | 'week' | 'month' | 'year' | null
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Free-trial unit
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        trial-interval-count
      </code>
    </td>
    
    <td>
      <code>
        number | null
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Free-trial length
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        locale
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Checkout locale
    </td>
  </tr>
</tbody>
</table>

The rendered `<a>` merges your attributes, so a `@click` of your own fires alongside the lazy handler instead of replacing it.

### `<CustomerPortalLink>`

A link to the Polar customer portal (subscription management) — renders nothing until the portal URL resolves:

```vue
<template>
  <CustomerPortalLink>Manage subscription</CustomerPortalLink>
</template>
```

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Purpose
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        polar-api
      </code>
    </td>
    
    <td>
      <code>
        PolarComponentApi
      </code>
    </td>
    
    <td>
      <code>
        api.billing
      </code>
    </td>
    
    <td>
      Override the action references
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        return-url
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Forwarded to <code>
        generateCustomerPortalUrl
      </code>
      
      ; the portal URL re-fetches when it changes
    </td>
  </tr>
</tbody>
</table>

The rendered anchor opens in a new tab (`target="_blank"`).

## Reference

Full signatures: [`polar/client`](https://nuxt-convex-module.dev/api-reference/reference/polar/client). Types via `nuxt-convex-module/polar/client` (alias `nuxt-convex-module/polar/vue`). Upstream: [`@convex-dev/polar`](https://github.com/get-convex/polar).

---

- [@convex-dev/polar](https://github.com/get-convex/polar)
- [Polar component docs](https://www.convex.dev/components/polar)


## Sitemap

See the full [sitemap](https://nuxt-convex-module.dev/sitemap.md) for all pages.
