# Troubleshooting (/docs/agents/chat-widget/troubleshooting)

> For the complete documentation index, see [llms.txt](https://docs.tandemcx.ai/llms.txt). Any page on this site can be fetched as Markdown by appending `.md` to its URL.

## Tandem won't save the widget

**"This agent doesn't take chat."** The agent you picked has **Chat** switched off in its
[Channels](/docs/agents/voice-agents/persona#channels). Switch **Chat** on and publish that
agent, or point the widget at a different one. An agent with nothing published yet is
accepted, so this only comes up for an agent that is already answering.

## Nothing appears on my site

The widget renders nothing at all — not even a launcher — when it is not
authorized, because a launcher that opens onto an error is worse for your visitors
than no launcher. Open your browser's developer console on the page
and look for a line starting `[spark-chat]`, which names the reason.

Work through these in order:

1. **The origin is not on the list.** The most common cause by far. The `Origin`
   your browser sends must match an entry exactly — `https://www.example.com` and
   `https://example.com` are different origins, and so are `http://` and
   `https://` versions of the same host. Check the address bar against your
   **Allowed Origins** list.
2. **The Allowed Origins list is empty.** A widget with no origins is authorized
   nowhere, which is also how you take a widget off a site: remove the origin.
3. **The key does not match.** Copy the snippet again from the **Install**
   section rather than editing an old one by hand.
4. **The script did not load.** Look for the request to
   `chat.tandemcx.ai` (or `chat.spark.sharpencx.com`, if that is the host your snippet
   names) in the Network tab. If it is blocked, check your
   Content Security Policy — see
   [Installing](/docs/agents/chat-widget/installing#content-security-policy).
5. **You are on a staging environment with a production snippet, or the reverse.**
   The widget derives which Tandem environment to talk to from where the script
   itself was served, so a snippet copied out of the wrong dashboard asks the
   wrong environment about a key it has never heard of. Copy the snippet from the
   dashboard for the environment you are testing.

**The editor's preview chat cannot tell you which of these it is**, and a working one does not rule
any of them out. It runs from Tandem rather than from your site, so it never uses the
key, the origin list, or the script — everything on this list. What it does rule out
is the agent itself: if the preview answers, the problem is the installation, and the
origin list is where to look first.

## The launcher appears but says the assistant is unavailable

The widget loaded, so the key and origin are fine — something behind it is not.
The visitor-facing message is deliberately the same for every cause; the specific
reason is in your Tandem logs. The usual ones:

- **The agent was deleted or re-pointed.** Open the widget in Tandem: the **Agent**
  field will be empty or naming something unexpected.
- **The agent's model credential is missing.** An agent on a keyed vendor
  (OpenAI, Gemini) needs that vendor's API key configured for your organization.
- **The agent has PII redaction on with a non-Bedrock model.** That combination is
  refused rather than run without protection. Either switch the agent to a Bedrock
  model or turn PII redaction off.

**The editor's preview chat is worth trying here**, unlike the section above: it reaches the agent
the same way a visitor's message does, so a cause on this list fails there too — and
it fails while you are looking at the field that causes it.

## A visitor was told there were too many messages

That is the rate limit. It is per visitor, per conversation, and per widget, and
it resets within a minute. It exists because each message costs a model call and
possibly a call to your own integrations — the public snippet has no secret in it,
so a limit is what caps the cost of abuse.

If real traffic is hitting it, that is worth telling us about rather than working
around.

There is a second, much looser limit on how often one visitor may load the panel's
name and avatar. A page that opens the widget once per visit will never see it; a
page that re-mounts the widget in a loop will. It also resets within a minute.

## The reply shows asterisks, pipes, or hash marks

The agent is writing markdown. The chat panel renders plain text, so markdown
syntax appears literally. Add a line to the agent's system prompt telling it to
answer in plain prose with blank lines between paragraphs and no markdown
formatting.

## The conversation resets when I reload

A reload should NOT reset it, and neither should a new tab or coming back the next
day — the conversation lives on our servers and the browser keeps only the ids
needed to ask for it. Three things do reset it, all expected:

- **A different browser, device, or private window.** The visitor is identified by
  their browser, not an account, so there is nothing to carry across.
- **The visitor cleared their site data**, which removes the ids.
- **A browser blocking storage** for embedded content. With nowhere to keep the
  ids, every page load is a new visitor. The chat still works; it just does not
  remember.

A conversation stops accepting new messages after 24 hours of inactivity, and after a long run
of messages. The visitor can still read it, but replying starts a new one.

## The chat covers something important on mobile

On a phone-sized screen the chat fills the display once opened. That is
intentional. If the _launcher_ is what collides with something (a cookie banner, a
back-to-top button), move it with the widget's **Position** setting — bottom left or
bottom right, in the Launcher section of the widget's configuration — or lower it
behind your own element with `data-spark-chat-z-index`.
