Security and troubleshooting

What's public and what's checked, the content security policy to allow, fixes for common problems, and working with other Subcontext embeds.

Privacy and security#

What's public. Your agent's id is in your page's source, so anyone can see it. There is no key and no list of allowed websites. Any page with the id can show your agent's chat while the Web channel is on. Switching the Web channel off hides the chat on websites, but a program outside a web browser can still reach a live agent.

What's checked.

  • The agent must be live and its Web channel on (see Before you start).
  • Anything a page sends in subcontext (including partner details) is treated as unchecked. The agent is told to confirm partner details with the customer.
  • Quote form application tokens, lead form tokens and email link tokens are checked against your firm, then removed before the information is saved.

The conversation pass. Starting a conversation gives the browser a private pass (a "session token") that only works for that one conversation. It expires after 7 days without use. The chat saves it in the browser for 24 hours so a returning visitor can carry on. Any script running on your page could read it, so don't put the chat on pages that run scripts you don't trust.

Isolation from your page. The chat is drawn inside its own sealed area of the page (a "closed Shadow DOM") on <div id="subcontext-webchat">. Your page's styles don't affect it and its styles don't affect your page. Agent replies are cleaned before they are shown, so they can't run code on your page.

Payments. Card and Direct Debit forms are shown in frames served by Subcontext, so payment details never pass through your page.

Limits. Subcontext limits how often one internet address can make requests. Over a limit, the API answers with status 429 and Rate limit exceeded. Please try again later.:

  • 300 requests in 5 minutes overall;
  • 5 contactMe requests an hour made before a chat has started;
  • 10 voice starts an hour, per conversation and per address.

What the chat saves in the visitor's browser (useful for your cookie policy):

Where Name What and how long
Local storage subcontext_webchat The visitor id, and the current conversation and its pass. The conversation part is dropped after 24 hours.
Session storage subcontext_webchat_dismissed:<agent id> Records that the visitor closed the panel, until the tab is closed.

To wait for consent before anything is saved, load the chat with enabled: false and call enable() once the visitor agrees.

Content security policy#

A content security policy (CSP) is a header that tells the browser which other sites your page may load from. If your site has one, add these:

Directive Add Why
script-src https://js.subcontext.com The chat script.
connect-src https://subcontext.com wss://subcontext.com Messages, the live connection (wss://subcontext.com/cable) and talking in the browser (wss://subcontext.com/web/voice/stream).
img-src https: (or at least https://subcontext.com plus the address your agent's uploaded images are served from) The agent's picture and images in replies.
frame-src https://subcontext.com, plus https://www.youtube.com https://player.vimeo.com if your agent shares videos Payment forms and videos.
media-src https:, if your agent shares video files Video replies.
style-src nothing The chat's styles are inside its own sealed area.

Troubleshooting#

Start by turning on debugging. Add debug: true (or data-debug="true"), then open your browser's developer tools:

  • The Console tab shows lines starting [Subcontext.Webchat]. The first line is the version, for example [Subcontext.Webchat] v1.2.0, so you can tell whether an old copy is cached.
  • The Network tab shows requests to https://subcontext.com/api/v1/webchat/ and the live connection to wss://subcontext.com/cable.

The chat doesn't appear#

What you see What to do
Only the version line in the console, nothing else The tag has no data-agent-id, so the chat is waiting for init(). Add the attribute, or call init().
agent <id> did not load, so the chat is hidden: no agent has this id. Check data-agent-id / agentId. The id is wrong. Copy it again from the dashboard snippet.
agent <id> did not load, so the chat is hidden: it isn't live (no production version) or its organisation's account isn't in good standing. Promote a version of the agent. If one is live, check your subscription.
agent <id> did not load, so the chat is hidden: Web chat is switched off for this agent. Switch it on in the dashboard: Agents, the agent, Channels, then the channel's Configure and Enable. Switch the Web channel on: Channels, Web, Configure, Enable.
agent <id> did not load, so the chat is hidden: could not reach <address> (...). Check baseUrl / data-base-url. baseUrl is wrong, Subcontext couldn't be reached, or your CSP's connect-src blocks https://subcontext.com.
missing agentId: embed cannot boot. ... init() was called without agentId.
Embedded mode requires a data-target attribute Embedded mode needs target (or container).
Target element not found: #chat The box for embedded mode isn't on the page when the chat starts. Make sure it exists first.
Requests go to the wrong address Pass baseUrl: 'https://subcontext.com'.
You set defaultOpen but the panel doesn't open It never opens by itself on phones, with startUnread or launchAnimation, or once the visitor has closed it in this tab. To test again, open a new tab.
The dark theme is hard to read You set a light backgroundColor with theme: 'dark'. Leave backgroundColor out to get the dark default.

Messages won't send#

What you see What to do
The greeting shows, but sending says "Could not connect. Please try again." and the console says startConversation failed: Error: WebSocket connection timeout The live connection was blocked. Check that your CSP's connect-src allows wss://subcontext.com, and that no firewall or proxy blocks WebSockets.
Console startConversation failed: Error: Agent not available, or ... Web chat is switched off for this agent The agent stopped being live, or the Web channel was switched off, after the page loaded. Check the dashboard.
"Rate limit exceeded. Please try again later." Too many requests from one internet address. Wait and try again.

The wrong conversation shows#

What you see What to do
An old conversation appears, and new subcontext information is ignored The chat picked up the conversation saved in this browser (it keeps it for 24 hours). Use freshConversation: true, call resetConversation(), or type /new in the chat.
An earlier conversation won't load (the API answers 410 conversation not resumable, or 401 Unauthorized) That conversation was closed, or its pass expired. resetConversation() or freshConversation: true starts a new one.

Talking in the browser#

What the chat says What to do
"Voice limit reached for today." or "Voice calls aren't available right now..." Your voice budget is used up (the API answers 402 budget_cap). Ask Subcontext.
"Voice needs a secure (https) connection..." Serve the page over https://.
"Microphone access was blocked..." The visitor said no to the microphone. They can allow it from the microphone icon in the address bar.
"We couldn't find a microphone on this device." No microphone is connected.
"Your microphone is being used by another app..." Another app is using the microphone.

Carrying the chat on elsewhere#

What you get What to do
contactMe gives { status: 'unavailable' } The agent has no SMS or WhatsApp channel with a number switched on. Add one on the Channels tab.
contactMe gives { status: 'consent_withdrawn' } The person asked you before to stop messaging that number. Ask them, then call again with consent_confirmed: true.
contactMe fails with Rate limit exceeded... More than 5 requests in an hour from one address before a chat had started.

If you're still stuck, email hello@subcontext.com with your agent's id, the page address and what the console says.

Working with other Subcontext embeds#

  • Quote form. The quote form can load and control this chat itself (its webchat option, which passes on options such as launchAnimation). The two share one application: the quote form passes its application through setContext(), docks the chat beside the form with dock(), and reports progress with notifyFormProgress(). If the agent starts the application first, the subcontext:application-ready event hands it to the quote form. See the quote form guide.
  • Lead form. After a lead form is sent, it can open an embedded chat. The agent then greets the visitor using what they sent.
  • Form guide. A separate script. The two don't interact.

Stuck, or something missing?

Get in touch and a person on the team will help.

Contact us