Customization and security

What to configure in Kustomer versus in code, custom launchers, language and right-to-left support, domain restrictions, Content Security Policy with nonces, and privacy considerations for web chat.

Web chat is configured in two places. Admins set the brand's look and behavior in Kustomer, and every SDK (web, iOS, Android) picks it up. Your code controls where and how the widget sits on your page.

Configured in Kustomer

These come from the brand's chat settings and apply to every platform at once, with no deploy:

SettingEffect
Colors, team name and iconThe widget's theme and header
Greeting and wait messageText before and after the customer's first message
Business hours and off-hours displayWhether chat shows as online, offline (leave a message), or is hidden outside hours
AssistantThe chatbot that answers first
Knowledge baseWhether the widget shows chat, the knowledge base, or both
Conversation historyWhether customers see past conversations, and whether they can have more than one open
AttachmentsWhether customers can send files
Ending conversationsWhether customers can end a conversation themselves
Page rulesWhich page URLs show chat

The Core API returns all of these from init, so a custom UI can honor them.

Configured in code

NeedOption or method
Move the launcherchatIconPosition: 'left', or { alignment, horizontalPadding, verticalPadding }
Resize the launcherchatIconSize: 64
Your own launcherhideChatIcon: true plus Kustomer.open()
Open on the knowledge basepreferredView: 'kb'
Force a languagelang: 'de'
Fix stackingzIndex
Different brand per section of your sitebrandId

See Start options for the full list.

Use your own launcher

Hide Kustomer's button and drive the widget from yours, with an unread badge:

Custom launcher
<button id="help" type="button">Help <span id="help-badge" hidden></span></button>

<script>
  window.addEventListener('kustomerLoaded', function () {
    Kustomer.start({ brandId: 'YOUR_BRAND_ID', hideChatIcon: true }, function () {
      var badge = document.getElementById('help-badge')
      Kustomer.addListener('onUnread', function (res) {
        badge.hidden = !res.total
        badge.textContent = res.total
      })
      document.getElementById('help').addEventListener('click', function () {
        Kustomer.open()
      })
    })
  })
</script>

If chat can be hidden outside business hours, hide your button too: check Kustomer.isChatAvailable().availability when the page loads.

Language

The widget follows the visitor's browser language unless you set lang. It ships translations for more than 50 languages, including en_us, es, fr, de, it, pt, pt_br, nl, sv, da, no, fi, pl, cs, tr, ru, uk, ja, ko, zh_cn, zh_tw, th, vi, id, hi, ar and he.

  • Codes are matched case-insensitively, and pt-BR is treated as pt_br.
  • A regional code without its own translation falls back to the base language, so fr_ca uses fr.
  • ar and he switch the widget to right-to-left layout.

Text you control in Kustomer (greeting, assistant dialogs, knowledge base articles) is translated separately in Kustomer.

Restrict where chat runs

Admins can limit chat to pages whose URL matches rules in the brand's chat settings. The widget hides itself on pages that don't match, and checks again whenever the URL changes, so it works with client-side routing: you can load the script on every page and let the rules decide.

Headless UIs apply the same rules with KustomerCore.isUrlAllowed({ url: location.href }), which returns { allowed }.

These rules control where chat is shown. They aren't an access control: the chat key itself still works anywhere, which is safe because of what the org.tracking role allows.

Content Security Policy

The widget runs in iframes created from your page, so your page's Content Security Policy applies to it.

Use a nonce

If your policy uses nonces, put the nonce on the script tag:

HTML
<script
  src="https://cdn.kustomerapp.com/chat-web/widget.js"
  data-kustomer-api-key="YOUR_CHAT_KEY"
  nonce="r4nd0m-per-request"
></script>

The SDK reads the nonce from the tag with data-kustomer-api-key and adds it to the scripts it loads, but only to inline scripts and scripts from Kustomer's CDN (https://cdn.kustomerapp.com). Scripts from any other origin never get your nonce. The same works for core.js.

Directives

Chat needs to load scripts from the CDN, call Kustomer's API, hold a realtime connection, and show images and attachments. Start from this policy, which is known to work, in Content-Security-Policy-Report-Only mode, then tighten connect-src, img-src and media-src using the violations your browser reports:

Text
script-src 'nonce-r4nd0m-per-request';
style-src * 'unsafe-inline';
img-src * data: blob: https:;
media-src *;
connect-src *;
object-src 'none';

style-src 'unsafe-inline' is required: the widget sets inline styles for positioning and theming.

Privacy

  • Chat keys are public. Anyone can read them from your page. That's expected: the org.tracking role can only act as the chat customer on that browser. Never put any other kind of API key in a web page.
  • Anonymous by default. Until you call login, Kustomer only knows the browser. Don't use describeCustomer to attach an email or phone you haven't verified; use login with a signed token instead.
  • Log out on shared devices. Call Kustomer.logout() when your user signs out, so the next person on the device doesn't see their conversations.
  • Browser storage. The SDK stores the session in the browser so conversations survive reloads. logout() clears it.