# Widget embed code, React and CSP

> The chat widget embed code, the command queue, React and other SPAs, Next.js, Content Security Policy, allowed domains and common problems.

Everything a developer needs to add the chat widget: the code, single page apps, CSP and allowed domains. The quick way without code is [Install the chat widget on your website](https://hrc.lt/en/docs/getting-started/install-widget).

## The short code

Your widget key is in Settings, Chat widgets, Install. The code loads asynchronously and never blocks your page.

```html
<script
  src="https://widget.hrc.lt/v1/loader.js"
  data-widget-key="wk_xxxxxxxxxxxxxxxxxxxx"
  async
></script>
```

The optional `data-locale` attribute sets the language (`auto` by default).

## The full code with the command queue

This code creates the `HrcWidget` function at once, so you can call it before the widget has loaded. Calls wait in the `HrcWidget.q` queue and run in order when the loader arrives.

```html
<script>
  (function (w, d) {
    w.HrcWidget = w.HrcWidget || function () {
      (w.HrcWidget.q = w.HrcWidget.q || []).push(arguments);
    };
    var s = d.createElement('script');
    s.async = true;
    s.src = 'https://widget.hrc.lt/v1/loader.js';
    d.head.appendChild(s);
  })(window, document);
  HrcWidget('init', {
    widgetKey: 'wk_xxxxxxxxxxxxxxxxxxxx',
    locale: 'auto',
  });
</script>
```

If the loader is included twice, the first one stays. If the page already queued its own `init`, the short code's `data-widget-key` is ignored.

## React and other SPAs

There is no npm package: copy this hook. It loads the widget once and keeps user recognition in step with your sign-in.

```tsx
// useSupportWidget.ts: loads the widget once, follows your sign-in
import { useEffect } from 'react';

type Identity = {
  externalId?: string;
  email?: string;
  name?: string;
  userHash: string;
};
type Queue = ((...args: unknown[]) => void) & { q?: unknown[][] };
declare global {
  interface Window { HrcWidget?: Queue }
}

function hrc(...args: unknown[]) {
  if (!window.HrcWidget) {
    const queue: unknown[][] = [];
    const stub = (...a: unknown[]) => { queue.push(a); };
    window.HrcWidget = Object.assign(stub, { q: queue });
    const s = document.createElement('script');
    s.async = true;
    s.src = 'https://widget.hrc.lt/v1/loader.js';
    document.head.appendChild(s);
  }
  window.HrcWidget(...args);
}

export function useSupportWidget(options: {
  widgetKey: string;
  locale?: string;
  identity?: Identity | null;
}) {
  const { widgetKey, locale = 'auto', identity } = options;
  useEffect(() => {
    hrc('init', { widgetKey, locale });
  }, [widgetKey, locale]);
  useEffect(() => {
    if (identity) hrc('identify', identity);
    else hrc('reset');
  }, [identity?.externalId, identity?.email, identity?.userHash]);
}

// Open from your own button:
// hrc('open', { view: 'new', type: 'bug' })
```

- The loader notices route changes (`pushState`, `popstate`) by itself; no call is needed.
- With Next.js and other server rendering, use the hook in a client component only.
- `reset` with no user on the first render is harmless: it only replaces a recognized session.

## Content Security Policy

If your site sends a CSP header, allow the widget:

```text
script-src https://widget.hrc.lt;
frame-src https://widget.hrc.lt;
img-src data:;
```

`data:` in `img-src` is for the one-click screenshot. Without it the screenshot falls back to the browser's picker. Images and fonts from other origins are drawn in the screenshot only where `connect-src` allows those origins.

## Allowed domains

The widget works only on the domains listed on the General tab. Add each one as `https://shop.example.com`. `https://*.example.com` covers every subdomain of your domain. A shared host such as `*.vercel.app` or `*.github.io` cannot be a wildcard: add your exact address. For development, turn on "Allow localhost".

## If the widget does not show

- **Domain not allowed.** Check that the page's address is in the allowed domains.
- **CSP.** Look for a message about `widget.hrc.lt` in the browser console.
- **Changed key.** After the widget key is changed, the old one stops working: add the new code.
- **More detail.** `init` with `debug: true` explains in the console why a value or a command was dropped. Every warning starts with `[support widget]`.

Every command is described on [JavaScript API](https://hrc.lt/en/docs/widget/javascript-api).
