I’m building a chat interface that connects to Claude’s API via API Connector. The chat works for 2-3 messages, then breaks. Claude loses all conversation history and starts fresh.
The Problem: After 2-3 exchanges, I get either:
“messages.X: all messages must have non-empty content” error
Blank screen with no response
Claude repeats its opening greeting (forgets entire conversation)
My Setup:
Storing conversation in a custom state (list of texts) on the page
Each message formatted as: {“role”: “user”, “content”: “message text”}
Passing to API as: chat’s Conversation join with “,”
Using :formatted as JSON-safe on content field
What I’ve Tried (all failed):
Format as text with JSON-safe
Manual find & replace for special characters
Toolbox JavaScript for escaping
Different quote/escape combinations
Storing in database instead of custom state
Root Cause (I believe): Claude’s responses contain newlines, quotes, and special characters. Bubble’s text manipulation can’t properly escape these for valid JSON, especially inside :format as text.
What I Need: Multi-turn conversation with system prompt (I’m building a guided interview that asks ~10 questions). Need Claude to remember the full conversation history.
Questions:
Has anyone successfully implemented multi-turn Claude chat with conversation history in Bubble?
Is there a plugin that properly handles the messages array with JSON escaping?
Any workarounds for the :format as text newline issue?
The easiest way to debug this is to copy your API call in the workflow, and prepend a link to a https://webhook.site / request catcher URL to the API call URL (you can do this by making the URL an optional parameter in the API Call).
That will forward your raw request to the request catcher, so you can inspect the payload. It will tell you what part of your JSON is invalid and hence why it’s not working.
Additionally, I’d recommend storing messages as a data type rather than a list of texts. It gives you metadata like when the message was sent, which role etc and will give you more flexibility in the long time. Your current solution won’t solve page refreshes, for example.
You can then provide your messages as Do a search for Messages where Conversation = (The Conversation):format as text.
The webhook.site debugging approach makes sense. I’d like to see exactly what’s breaking in the payload rather than guessing.
Quick context: I’m storing conversation history in a custom state (list of texts) formatted as JSON for the Claude API. Works fine for the first message, but breaks on the second — my guess has been that Claude’s response contains line breaks or special characters that corrupt the JSON when I try to append it back to the list.
A few questions if you don’t mind:
For the webhook.site approach — do I just prepend the webhook URL to my actual API endpoint URL? So it would be something like https://webhook.site/my-unique-id/https://api.anthropic.com/v1/messages?
On storing messages as a Data Type — would that be something like a “Messages” table with fields for role (user/assistant), content (text), timestamp, and a link to a parent Conversation? Then the :format as text would build the JSON array from those records?
Does :format as text handle escaping automatically, or would I still need to deal with line breaks in Claude’s responses somehow?
Appreciate the guidance — I’m relatively new to Bubble and trying to get this working for a Valentine’s Day launch.
Role should be an option set. You’ll have System, Assistant, and User probably. Their IDs can be system, assistant, and user respectively (essentially what you’re passing to the AI). Could you just lowercase the display and use that? Possibly, but the display is a display intended to be readable, not the ID. So create an ID attribute and use that
On a tangentially related note, you might consider using https://openrouter.ai instead of Anthropic directly, because you can use any provider’s models with one API call.