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(includingpartnerdetails) 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
contactMerequests 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 towss://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
webchatoption, which passes on options such aslaunchAnimation). The two share one application: the quote form passes its application throughsetContext(), docks the chat beside the form withdock(), and reports progress withnotifyFormProgress(). If the agent starts the application first, thesubcontext:application-readyevent 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.