Install

The @planetary/co-mment package ships one React component. React 18+ is a peer dependency; everything renders inside a Shadow DOM root, so your styles cannot leak into the widget and its styles cannot leak into your page.

terminal
npm install @planetary/co-mment
# or: pnpm add co-mment / yarn add co-mment

1. Add the component

Mount <Comment /> once, near your app root, with the publishable key from your project settings. The key is safe to ship in client code: access is enforced by the origin allowlist, not by key secrecy.

Next.js (App Router)

app/layout.tsx
// app/layout.tsx
import { Comment } from "@planetary/co-mment";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        {process.env.NEXT_PUBLIC_VERCEL_ENV !== "production" && (
          <Comment projectKey="cmt_pk_..." />
        )}
      </body>
    </html>
  );
}

The component is client-side; Next.js handles that automatically because the package marks it "use client"-compatible. The NEXT_PUBLIC_VERCEL_ENV variable is "production" only on production deployments, so the widget appears on previews and local dev but never in production.

Vite / plain React

src/App.tsx
// src/App.tsx
import { Comment } from "@planetary/co-mment";

export default function App() {
  return (
    <>
      <main>{/* your app */}</main>
      {!import.meta.env.PROD && <Comment projectKey="cmt_pk_..." />}
    </>
  );
}

Vite exposes import.meta.env.PROD; any equivalent build-time flag works. The important part is that the check happens, not how you write it.

2. Keep it out of production

The widget is meant for staging, preview, and development environments, not your production site. Two reasons:

Check your environment as shown above, or pass disabled to switch off the component (it renders nothing and makes no network calls).

3. Allowlist your origins

The widget API rejects requests from origins that are not on the project’s allowlist. In the dashboard project settings (or during onboarding), add every deployed origin where the widget should run. Give the scheme, host, and port with no path, for example https://staging.example.com.

localhost needs no entry: loopback origins are always allowed, on any port, because only software on your own machine can present one. Local dev works the moment the component mounts.

Preview deployments get a new hostname on every build, so an entry may put * inside a single host label: https://myapp-*.preview.example.com matches https://myapp-a1b2c3d4.preview.example.com. The wildcard stands for one or more letters, digits, or hyphens and never crosses a dot, so it can only widen the label you put it in.

A whole label cannot be just a wildcard (https://*.preview.example.com is refused). On a preview apex shared with other tenants that would let any of them use your publishable key, so keep a literal prefix that is yours.

Props

all props
<Comment
  projectKey="cmt_pk_..."          // required: your publishable key
  user={{ name, email }}           // optional: pre-fill commenter identity
  disabled={false}                 // hard off switch (renders nothing)
  position="bottom-right"          // "bottom-right" | "bottom-left" | "top-right" | "top-left"
  apiUrl="http://localhost:3000"   // API origin override (defaults to the hosted API)
/>
PropTypeDefaultDescription
projectKeystringrequiredPublishable project key (cmt_pk_...).
user{ name: string; email: string }nonePre-fill commenter identity, e.g. from your app’s session.
disabledbooleanfalseHard off switch: renders nothing and makes no network calls.
position"bottom-right" | "bottom-left" | "top-right" | "top-left""bottom-right"Floating toolbar placement.
apiUrlstringautoAPI origin override. Defaults to the hosted API (or http://localhost:3000 when the host page runs on localhost).

Verify it works

  1. Start your dev server and open the app.
  2. A floating toolbar appears in the corner you configured.
  3. Click +, click anywhere on the page, enter a name and email, and post a comment. A pin appears at the click point.The widget toolbar with the plus button marked 1, and a dropped pin with its composer open marked 2
  4. If the toolbar renders but posting fails, the page’s origin is not on the allowlist (step 3 above). It looks like this:The composer showing the error: this site is not authorised to post comments, ask the site owner to allowlist this origin