> For the complete documentation index, see [llms.txt](https://docs.klink.cloud/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.klink.cloud/getting-started/setup-channels/live-chat/chat-widget-custom-buttons-and-programmatic-control.md).

# Chat Widget - Custom Buttons & Programmatic Control

#### Installation

Add the script inside the `<head>` tag of your HTML. It uses `async` and `defer`, so it won't block page rendering.

html

```html
<head>
  <script>
    (function (d, t) {
      var timestamp = new Date().getTime();
      var SCRIPT_PATH = "https://webchat.klink.cloud/widget/klink-chat-widget.umd.js";
      var g = d.createElement(t),
          s = d.getElementsByTagName(t)[0];
      g.src = SCRIPT_PATH + '?v=' + timestamp;
      g.defer = true;
      g.async = true;
      s.parentNode.insertBefore(g, s);
      g.onload = function () {
        window.klinkChatSDK.run({
          serverUrl: "https://apigw.klink.cloud",
          scId: "YOUR_SC_ID_HERE",
        });
      };
    })(document, 'script');
  </script>
</head>
```

**Framework notes:** In Next.js, use `<Script strategy="afterInteractive">` in your root layout. In Vite or CRA, paste the snippet into `public/index.html`. In WordPress, use a headers plugin or edit `header.php`.

***

#### Configuration Options

| Option             | Type    | Required | Description                                        |
| ------------------ | ------- | -------- | -------------------------------------------------- |
| `serverUrl`        | string  | Yes      | Always `https://apigw.klink.cloud`                 |
| `scId`             | string  | Yes      | Your Social Channel ID from klink.cloud settings   |
| `showLaunchButton` | boolean | No       | Set to `false` to hide the default floating button |
| `authUser`         | object  | No       | Pre-fills visitor identity (`email`, `name`)       |

***

#### Hide the Default Button & Open Programmatically

To integrate chat into your own UI — a nav link, hero CTA, or custom icon — hide the default launcher and call `openWidget()` when you need it.

javascript

```javascript
window.klinkChatSDK.run({
  serverUrl: "https://apigw.klink.cloud",
  scId: "YOUR_SC_ID_HERE",
  showLaunchButton: false,
});
```

Then trigger it from any click:

html

```html
<button onclick="window.klinkChatSDK.openWidget()">
  Chat with Support
</button>
```

**React / Next.js**

jsx

```jsx
<button onClick={() => window.klinkChatSDK.openWidget()}>
  Talk to us
</button>
```

**Link**

html

```html
<a href="#" onclick="window.klinkChatSDK.openWidget(); return false;">
  Need help? Chat now
</a>
```

***

#### Passing Authenticated Users

For logged-in visitors, pass their identity so conversations attribute to a known contact instead of an anonymous session.

javascript

```javascript
window.klinkChatSDK.run({
  serverUrl: "https://apigw.klink.cloud",
  scId: "YOUR_SC_ID_HERE",
  showLaunchButton: false,
  authUser: {
    email: session?.user?.email,
    name: session?.user?.name,
  },
});
```

In React, wait for the session to hydrate before initializing:

jsx

```jsx
useEffect(() => {
  if (session?.user && window.klinkChatSDK) {
    window.klinkChatSDK.run({
      serverUrl: "https://apigw.klink.cloud",
      scId: "YOUR_SC_ID_HERE",
      showLaunchButton: false,
      authUser: {
        email: session.user.email,
        name: session.user.name,
      },
    });
  }
}, [session]);
```

***

#### Notes

* Initialize once per page — calling `run()` multiple times creates duplicate instances.
* Only pass `authUser` when you have real values; omit the field otherwise.
* If `window.klinkChatSDK` is undefined, the script hasn't finished loading yet.
