Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions apps/web/content/docs/quickstart/api-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,36 @@ NEXT_PUBLIC_COSSISTANT_API_KEY=pk_live_xxxxxxxxxxxx
</TabsContent>
<TabsContent value="other">

For frameworks without a public env variable convention (CRA, Remix, etc.),
pass the key directly via the `publicKey` prop:

```tsx
<SupportProvider publicKey="pk_live_xxxxxxxxxxxx">
```

The generic env variable only works when your bundler or server inlines
`process.env.COSSISTANT_API_KEY` into browser code (for example a custom
webpack `DefinePlugin`, or SSR that renders the provider with the key):

```bash title=".env"
COSSISTANT_API_KEY=pk_live_xxxxxxxxxxxx
```

CRA only exposes `REACT_APP_*` variables and Remix does not expose
`process.env` to the client at all, so on those frameworks prefer the
`publicKey` prop.

</TabsContent>
</Tabs>

<Alert variant="info" className="mt-6">
<Icon name="help" className="size-4" />
<AlertTitle>Auto-detection</AlertTitle>
<AlertDescription>
The SDK automatically detects your framework and checks
`VITE_COSSISTANT_API_KEY` (Vite), `NEXT_PUBLIC_COSSISTANT_API_KEY`
(Next.js), or `COSSISTANT_API_KEY` (other). You can also pass the key
explicitly through `publicKey`.
The SDK automatically reads `VITE_COSSISTANT_API_KEY` (Vite),
`NEXT_PUBLIC_COSSISTANT_API_KEY` (Next.js), or `COSSISTANT_API_KEY`
(only when your bundler or server inlines `process.env` into client code).
You can also pass the key explicitly through `publicKey`.
</AlertDescription>
</Alert>

Expand Down
163 changes: 163 additions & 0 deletions apps/web/content/docs/quickstart/browser.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
title: Script Tag
description: Embed the Cossistant support widget on any website with a single script tag.
---

Use the CDN embed when your site is not built with React — plain HTML,
WordPress, Webflow, Rails, PHP, or any other stack. The loader downloads the
widget bundle, mounts it into a shadow root, and keeps your page styles
untouched.

## 1. Add the script tag

Paste one tag anywhere in `<head>` or `<body>` with your public key:

```html
<script
async
src="https://cdn.cossistant.com/widget/latest/loader.js"
data-public-key="pk_live_..."
></script>
```

That is the whole install. The loader reads `data-public-key` from its own
script tag and initializes the widget automatically once the bundle loads. The
widget waits for the DOM to be ready before mounting, so placement does not
matter.

Get your public key from the dashboard under **Settings → Developers** — see
[API Keys](/docs/quickstart/api-keys). Only use public keys (`pk_live_*`,
`pk_test_*`) in browser code.

## 2. Pin a version (optional)

`latest/` always serves the newest release. To pin an exact version, put it in
the URL — the loader derives `widget.js` and `widget.css` from its own URL, so
both forms work the same way:

```html
<script
async
src="https://cdn.cossistant.com/widget/0.2.0/loader.js"
data-public-key="pk_live_..."
></script>
```

Self-hosted deployments can also point the widget at their own API:

```html
<script
async
src="https://cdn.your-domain.com/widget/latest/loader.js"
data-public-key="pk_live_..."
data-api-url="https://api.your-domain.com"
data-ws-url="wss://api.your-domain.com/ws"
></script>
```

## The `window.Cossistant` API

Once the widget runtime has loaded, `window.Cossistant` exposes:

| Method | Description |
| ----------------------- | ------------------------------------------------------------------------------ |
| `init(options?)` | Mount the widget. Not needed when `data-public-key` is set on the script tag. |
| `show()` | Open the widget window. |
| `hide()` | Close the widget window. |
| `toggle()` | Toggle the widget window. |
| `identify(params)` | Link the visitor to a contact (`externalId`, `email`, `name`, `image`, `metadata`). |
| `updateConfig(options)` | Update config at runtime (`open`, `defaultMessages`, `quickOptions`, `size`, `theme`, `widget`). |
| `on(type, handler)` | Subscribe to an event. Returns an unsubscribe function. |
| `off(type, handler)` | Remove an event handler. |
| `destroy()` | Unmount the widget and remove it from the page. |

Events for `on`/`off`: `conversationStart`, `conversationEnd`, `messageSent`,
`messageReceived`, and `error`.

`init()` accepts: `publicKey`, `apiUrl`, `wsUrl`, `autoConnect`, `container`,
`defaultMessages`, `defaultOpen`, `quickOptions`, `size` (`"normal"` or
`"larger"`), `theme`, `host`, and `widget`.

```js
window.Cossistant.identify({
externalId: "user_123",
email: "jane@acme.com",
name: "Jane Doe",
});

window.Cossistant.on("messageReceived", function (event) {
console.log("New message in", event.conversationId);
});
```

The loader tag is `async`, so inline scripts usually run before
`window.Cossistant` exists — install the queue stub below before calling any
of these methods from inline code.

## Calling the API before the widget loads

`window.Cossistant` only exists once `loader.js` executes, and the script tag
is `async`. Inline scripts that call widget methods earlier must install a
small command queue first; every queued call is replayed in order (after any
`data-public-key` auto-init) once the widget runtime loads:

```html
<script>
(function (w) {
var c = (w.Cossistant = w.Cossistant || { __queue: [] });
var methods =
"init show hide toggle identify updateConfig destroy on off".split(" ");
for (var i = 0; i < methods.length; i++) {
(function (m) {
c[m] =
c[m] ||
function () {
c.__queue.push({ method: m, args: [].slice.call(arguments) });
};
})(methods[i]);
}
})(window);
</script>
<script async src="https://cdn.cossistant.com/widget/latest/loader.js"></script>
<script>
window.Cossistant.init({
publicKey: "pk_live_...",
quickOptions: ["How do I get started?"],
});
window.Cossistant.show();
</script>
```

With `data-public-key` on the loader tag you never need to call `init()`
yourself — the queue stub is only required when calling widget methods before
the bundle has loaded.

## Theming

The widget renders inside a shadow root, so your page CSS cannot leak in.
Set `--co-theme-*` variables through `init()` or `updateConfig()` instead:

```js
window.Cossistant.updateConfig({
theme: {
mode: "auto", // "auto" | "light" | "dark"
variables: {
"--co-theme-primary": "#111827",
"--co-theme-background": "#ffffff",
"--co-theme-radius": "8px",
},
},
});
```

With `mode: "auto"` (the default) the widget follows your page's color scheme:
it checks the `dark` class, `data-color-scheme`, and `data-theme` attributes on
`<html>`, the computed `color-scheme`, and the OS `prefers-color-scheme`, and
reacts to changes live. The full variable list is in
[Match Your Brand](/docs/support-component/theme).

## Next steps

1. [API Keys](/docs/quickstart/api-keys) to allowlist your production domains.
2. [Match Your Brand](/docs/support-component/theme) for the full theming reference.
3. Using React? Prefer the [React quickstart](/docs/quickstart/react) or [Next.js quickstart](/docs/quickstart) for the native SDK.
2 changes: 1 addition & 1 deletion apps/web/content/docs/quickstart/meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"pages": ["index", "react", "api-keys"],
"pages": ["index", "react", "browser", "api-keys"],
"title": "Quickstart"
}
23 changes: 13 additions & 10 deletions apps/web/content/docs/quickstart/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,28 +86,31 @@ NEXT_PUBLIC_COSSISTANT_API_KEY=pk_test_xxxx
</TabsContent>
<TabsContent value="other">

For other frameworks (CRA, Remix, etc.), either set the env variable:

```bash title=".env"
COSSISTANT_API_KEY=pk_test_xxxx
```

Or pass the key directly via the `publicKey` prop:
For other frameworks (CRA, Remix, etc.), pass the key directly via the
`publicKey` prop:

```tsx
<SupportProvider publicKey="pk_test_xxxx">
```

The generic `COSSISTANT_API_KEY` env variable only works when your bundler or
server inlines `process.env.COSSISTANT_API_KEY` into browser code (for example
a custom webpack `DefinePlugin`, or SSR that renders the provider with the key).
CRA only exposes `REACT_APP_*` variables and Remix does not expose `process.env`
to the client at all, so on those frameworks the env variable never reaches the
widget — use the `publicKey` prop instead.

</TabsContent>
</Tabs>

<Alert variant="info" className="mt-6">
<Icon name="help" className="size-4" />
<AlertTitle>Auto-detection</AlertTitle>
<AlertDescription>
The SDK automatically detects your framework and reads the right
environment variable (`VITE_COSSISTANT_API_KEY`, `NEXT_PUBLIC_COSSISTANT_API_KEY`,
or `COSSISTANT_API_KEY`). You can also pass the key explicitly through `publicKey`.
The SDK automatically reads `VITE_COSSISTANT_API_KEY` (Vite),
`NEXT_PUBLIC_COSSISTANT_API_KEY` (Next.js), or `COSSISTANT_API_KEY`
(only when your bundler or server inlines `process.env` into client code).
You can also pass the key explicitly through `publicKey`.
</AlertDescription>
</Alert>

Expand Down
6 changes: 5 additions & 1 deletion apps/web/content/docs/support-component/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,11 @@ app.
import { CossistantClient } from "@cossistant/core";
import { useFileUpload } from "@cossistant/react/hooks/use-file-upload";

const client = new CossistantClient({ publicKey: "pk_test_xxxx" });
const client = new CossistantClient({
publicKey: "pk_test_xxxx",
apiUrl: "https://api.cossistant.com/v1",
wsUrl: "wss://api.cossistant.com/ws",
});

export function FileUploader() {
const upload = useFileUpload({ client });
Expand Down
12 changes: 10 additions & 2 deletions apps/web/content/docs/user-feedback/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ The most common options are:
import { CossistantClient } from "@cossistant/core";
import { useFeedbackForm } from "@cossistant/react/hooks/use-feedback-form";

const client = new CossistantClient({ publicKey: "pk_test_xxxx" });
const client = new CossistantClient({
publicKey: "pk_test_xxxx",
apiUrl: "https://api.cossistant.com/v1",
wsUrl: "wss://api.cossistant.com/ws",
});

export function ProviderFreeFeedback({ visitorId }: { visitorId: string }) {
const feedback = useFeedbackForm({
Expand Down Expand Up @@ -282,7 +286,11 @@ For provider-free forms, pass a client and visitor explicitly:
import { CossistantClient } from "@cossistant/core";
import { useSubmitFeedback } from "@cossistant/react/hooks/use-submit-feedback";

const client = new CossistantClient({ publicKey: "pk_test_xxxx" });
const client = new CossistantClient({
publicKey: "pk_test_xxxx",
apiUrl: "https://api.cossistant.com/v1",
wsUrl: "wss://api.cossistant.com/ws",
});

export function HeadlessFeedbackSubmit({ visitorId }: { visitorId: string }) {
const feedback = useSubmitFeedback({ client });
Expand Down
15 changes: 11 additions & 4 deletions apps/web/src/lib/support-integration-guide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export default function RootLayout({
framework: "react",
frameworkLabel: "React",
packageName: "@cossistant/react",
envVarName: "COSSISTANT_API_KEY",
envVarName: "VITE_COSSISTANT_API_KEY",
envFileName: ".env",
docsQuickstartPath: "/docs/quickstart/react",
providerFileName: "src/main.tsx",
Expand All @@ -220,7 +220,7 @@ import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<SupportProvider publicKey={process.env.COSSISTANT_API_KEY}>
<SupportProvider publicKey={import.meta.env.VITE_COSSISTANT_API_KEY}>
<App />
</SupportProvider>
</React.StrictMode>
Expand Down Expand Up @@ -306,7 +306,7 @@ import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<SupportProvider publicKey={process.env.COSSISTANT_API_KEY}>
<SupportProvider publicKey={import.meta.env.VITE_COSSISTANT_API_KEY}>
<App />
</SupportProvider>
</React.StrictMode>
Expand Down Expand Up @@ -405,6 +405,13 @@ export function buildSupportAiSetupPrompt({
? `Use this exact public key value: ${publicApiKey}`
: "If the public key is missing, fetch it from Cossistant dashboard > Settings > Developers and replace the placeholder value.";

// The react guide assumes a Vite app; other bundlers need their own
// public-env mechanism or an explicit publicKey prop.
const envVarNote =
guide.framework === "react"
? `\n "${guide.envVarName}" assumes Vite. If the project uses another bundler (CRA, Remix, etc.), use that bundler's public env variable mechanism or pass the key directly via <SupportProvider publicKey="...">.`
: "";

return `You are a senior ${guide.frameworkLabel} engineer. Integrate Cossistant into an existing ${guide.frameworkLabel} project.

Project context:
Expand All @@ -424,7 +431,7 @@ Required implementation:
1. Install dependency:
${installCommand}
2. Add/update ${guide.envFileName} with:
${guide.envVarName}=${keyValue}
${guide.envVarName}=${keyValue}${envVarNote}
3. ${keyInstruction}
4. Mount <SupportProvider> at the app root.
5. Import widget CSS:
Expand Down
Loading
Loading