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

# Add a Chat Widget

> Install Intercom, Crisp, Drift, or another live chat tool on your site

Install a live chat widget for support, sales qualification, or customer engagement. The pattern is the same for every major tool — paste a JavaScript snippet into your site's layout.

<Info>
  Supported widgets: anything with a JavaScript snippet. Intercom, Crisp, Drift, Tidio, Tawk.to, Chatwoot, HubSpot Chat, Olark, LiveChat, Front — all work the same way.
</Info>

## Three Paths

<Tabs>
  <Tab title="AI Chat (Fastest)">
    Ask the project AI:

    ```
    Add a Crisp chat widget to my site with website ID abc123.
    Load it only in production, not in dev.
    ```

    The AI finds your root layout, pastes the snippet in the right place, and adds a guard so the widget doesn't load during development. Review and deploy.
  </Tab>

  <Tab title="Manual Code Editor">
    Paste the snippet yourself. Best if you want to understand what's happening or customize the integration (user identification, event tracking).
  </Tab>

  <Tab title="Env Var (Next.js)">
    Use `NEXT_PUBLIC_CHAT_WIDGET_ID` and conditionally render a `<ChatWidget>` component. Best for multi-environment setups where staging and production use different accounts.
  </Tab>
</Tabs>

## The Generic Pattern

<Steps>
  <Step title="Sign up for the chat tool">
    Create an account with your chosen provider. Intercom, Crisp, Drift, etc. all have free or trial tiers.
  </Step>

  <Step title="Get your widget ID or script URL">
    Look in the provider's dashboard under **Settings > Install** or **Widget Code**. They give you either a full `<script>` snippet or an ID you drop into a provided template.
  </Step>

  <Step title="Open your site's root layout">
    Depending on your stack:

    * **Next.js App Router:** `app/layout.tsx`
    * **Next.js Pages Router:** `pages/_document.tsx`
    * **Static HTML:** `index.html`
    * **Other:** whatever file wraps every page
  </Step>

  <Step title="Paste the snippet">
    Put it in the `<head>` or just before `</body>`. Most providers recommend before `</body>` because it doesn't block initial render.
  </Step>

  <Step title="Deploy">
    Save and deploy. Visit your live site and confirm the widget bubble appears in the corner.
  </Step>
</Steps>

## Example: Crisp

Paste this into your layout before `</body>`:

```html theme={null}
<script type="text/javascript">
  window.$crisp=[];
  window.CRISP_WEBSITE_ID="YOUR_CRISP_WEBSITE_ID";
  (function(){var d=document;var s=d.createElement("script");
  s.src="https://client.crisp.chat/l.js";s.async=1;
  d.getElementsByTagName("head")[0].appendChild(s);})();
</script>
```

Replace `YOUR_CRISP_WEBSITE_ID` with the ID from Crisp Dashboard > Website Settings > Setup Instructions.

## Example: Intercom (React / Next.js)

Install the SDK:

```bash theme={null}
npm install @intercom/messenger-js-sdk
```

Initialize it in your root layout:

```typescript theme={null}
'use client';
import { useEffect } from 'react';
import Intercom from '@intercom/messenger-js-sdk';

export function IntercomBoot({ user }: { user?: { id: string; email: string } }) {
  useEffect(() => {
    Intercom({
      app_id: process.env.NEXT_PUBLIC_INTERCOM_APP_ID!,
      user_id: user?.id,
      email: user?.email,
    });
  }, [user]);

  return null;
}
```

Mount `<IntercomBoot user={currentUser} />` once in your layout. If the user is logged out, leave `user` undefined and Intercom runs in anonymous mode.

## Example: Tawk.to (Free, Simple)

Before `</body>`:

```html theme={null}
<script type="text/javascript">
  var Tawk_API=Tawk_API||{}, Tawk_LoadStart=new Date();
  (function(){
    var s1=document.createElement("script"),s0=document.getElementsByTagName("script")[0];
    s1.async=true;
    s1.src='https://embed.tawk.to/YOUR_TAWK_ID/default';
    s1.charset='UTF-8';
    s1.setAttribute('crossorigin','*');
    s0.parentNode.insertBefore(s1,s0);
  })();
</script>
```

## Cookie Consent

<Warning>
  Most chat widgets drop tracking cookies and fall under GDPR/ePrivacy. If you've enabled cookie consent (see [Site Enhancements](/how-tos/site-enhancements)), gate the widget script until the user consents to functional or analytics cookies.
</Warning>

Basic gating pattern:

```typescript theme={null}
if (cookieConsent.functional) {
  loadChatWidget();
}
```

Or wrap the `<script>` tag and only inject after consent. Your consent library (OneTrust, Cookiebot, or built-in) will have an event to hook into.

## Performance Tips

Chat widgets typically add 50–200 KB of JS. To avoid slowing down first paint:

* **Load with `async` or `defer`** — most provider snippets already do this
* **Place script before `</body>`** rather than in `<head>`
* **Lazy-load after idle** — for aggressive optimization, wrap the init in `requestIdleCallback`
* **Don't load on all pages** — skip the widget on high-traffic SEO pages if support isn't offered there

Example lazy-load:

```typescript theme={null}
if ('requestIdleCallback' in window) {
  requestIdleCallback(loadChatWidget);
} else {
  setTimeout(loadChatWidget, 2000);
}
```

## Customization

Most providers let you customize in their dashboard (no code):

* Bubble color and position
* Greeting messages based on page or user segment
* Operating hours (automatic "we're offline" messages)
* Pre-chat survey (name, email, reason for contact)
* Avatar and operator names

Spend 10 minutes in the provider dashboard before writing custom code — you probably don't need to.

## Using `hiveku.json` Build Env (Advanced)

For Next.js projects with per-environment widget IDs:

<Steps>
  <Step title="Set env vars">
    In **Project > Settings > Environment Variables**, add `NEXT_PUBLIC_CHAT_WIDGET_ID` per environment (dev, staging, production).
  </Step>

  <Step title="Render conditionally">
    ```typescript theme={null}
    {process.env.NEXT_PUBLIC_CHAT_WIDGET_ID && (
      <ChatWidget id={process.env.NEXT_PUBLIC_CHAT_WIDGET_ID} />
    )}
    ```

    Leave staging's var blank to disable chat there.
  </Step>

  <Step title="Deploy">
    Redeploy each environment separately after setting its var.
  </Step>
</Steps>

## Test It

<Steps>
  <Step title="Deploy to production">
    Chat widgets rarely work in local dev due to provider allow-lists. Deploy to your Hiveku URL or custom domain.
  </Step>

  <Step title="Open the live site">
    The chat bubble should appear in the corner (typically bottom-right).
  </Step>

  <Step title="Open the chat">
    Click the bubble. A chat window should open. Type a test message.
  </Step>

  <Step title="Verify on the provider dashboard">
    Log in to your chat provider. The test message should appear in their inbox or conversations view.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Widget doesn't appear">
    Open the browser DevTools console on your live site. If there's a script error (typo in the snippet, wrong ID, blocked by CSP), it'll show there. Also check **Network** tab for the widget script URL — if it's blocked or 404ing, the snippet or ID is wrong.
  </Accordion>

  <Accordion title="Widget appears but won't open">
    Usually an ad blocker or corporate firewall blocking the provider's server. Try in an incognito window with extensions disabled. If it works there, document the fix — affected visitors can whitelist the domain.
  </Accordion>

  <Accordion title="Two chat widgets showing at once">
    The script got added twice — commonly once in the root layout and once in a per-page file (or via a plugin and manually). Remove one. Browser DevTools > Elements can help you find duplicate `<script>` tags.
  </Accordion>

  <Accordion title="Page load is slower after install">
    Move the script from `<head>` to just before `</body>`, and make sure it uses `async` or `defer`. If you need aggressive optimization, lazy-load the widget with `requestIdleCallback` or a 2–3 second delay — the user won't miss a widget they can't see yet.
  </Accordion>

  <Accordion title="Widget loads before cookie consent">
    If you're using a consent library, wire the widget init to its `consented` event instead of loading directly on page load. Every major consent library has this hook; check their docs.
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Site Enhancements" icon="sliders" href="/how-tos/site-enhancements">
    Enable cookie consent and other site-wide features
  </Card>

  <Card title="Environment Variables" icon="key" href="/how-tos/env-vars">
    Store widget IDs per environment
  </Card>

  <Card title="CRM Contacts" icon="address-book" href="/how-tos/crm-contacts">
    Sync chat leads into your CRM
  </Card>
</CardGroup>
