Chat Injection
Dynamically override assistant instructions and pre-populate chat history when embedding. Useful for personalizing behavior per user, per page, or per context — without creating separate assistants.
Prerequisites
Section titled “Prerequisites”- Enable Injection under Dashboard → Deployment → Embedding → Additional Permissions.
- Turn on request signing under Dashboard → Deployment → Embedding → Security. Injection is only accepted on signed requests: an unsigned link or form carrying injection fields still loads, but the injection is ignored.
Overview
Section titled “Overview”Chat Injection lets you pass two optional payloads when loading the chat embed:
| Field | Purpose |
|---|---|
instructionOverrides |
Override or extend the assistant’s Custom Instructions and/or Opening Instructions (greeting). These affect LLM behavior. |
prefillMessages |
Pre-populate the chat with visual-only speech bubbles. These are not sent to the LLM — they only appear in the UI. |
Here’s a combined example showing both fields:
{ "instructionOverrides": { "customInstructions": { "value": "Always respond in formal English. Focus on enterprise pricing plans.", "mode": "append" }, "openingInstructions": { "value": "Welcome! I see you're interested in our Enterprise plan.", "mode": "replace" } }, "prefillMessages": [ { "type": "message", "role": "assistant", "content": "Hi there! How can I help you today?" }, { "type": "message", "role": "user", "content": "I'd like to learn about your Enterprise plan." } ]}Instruction Overrides
Section titled “Instruction Overrides”Each field in instructionOverrides accepts a value (string) and a mode:
| Field | Description | Max length |
|---|---|---|
customInstructions |
Maps to the Custom Instructions textarea on the Personality tab. Shapes overall LLM behavior. | 7,500 characters |
openingInstructions |
Maps to the Opening Instructions field. Controls the assistant’s greeting message. | 2,000 characters |
Replace vs. Append
Section titled “Replace vs. Append”The mode field controls how the injected value interacts with the value already configured in the dashboard:
// "replace" — completely overrides the assistant's configured value{ "customInstructions": { "value": "You are a billing support agent. Only answer billing questions.", "mode": "replace" }}
// "append" — adds to the end of the existing value (separated by a newline){ "customInstructions": { "value": "\nAdditional context: the user is on the Pro plan, billed annually.", "mode": "append" }}| Mode | Behavior |
|---|---|
replace |
Completely replaces the dashboard-configured value with the injected value. |
append |
Appends the injected value to the existing value, separated by a newline. |
Both fields are optional — you only need to include the ones you want to override.
For the wider picture — deciding what belongs in the dashboard versus what to send per request, splitting a long prompt across conversation stages, and managing instructions from code — see Dynamic Instructions.
Prefill Messages
Section titled “Prefill Messages”prefillMessages renders speech bubbles in the chat UI as if a conversation already occurred. These messages are purely visual — they are never included in the conversation history sent to the LLM.
// Current format — text messages only[ { "type": "message", "role": "assistant", "content": "Hello! What can I help with?" }, { "type": "message", "role": "user", "content": "Tell me about your API." }]
// The "type" field allows future extensions, e.g.:// { "type": "choices", "options": ["Option A", "Option B"] }// { "type": "card", "title": "...", "body": "..." }| Property | Type | Description |
|---|---|---|
type |
"message" |
Message type. Currently only "message" is supported (extensible for future types). |
role |
"user" | "assistant" |
Determines which side the bubble appears on. |
content |
string | The text displayed in the bubble. Max 2,000 characters per message. |
Limits: At most 50 prefill messages, each at most 2,000 characters. A set that breaks either
limit, or contains anything but user / assistant messages, is dropped whole: no bubbles are
shown.
Delivery: POST Body
Section titled “Delivery: POST Body”Pass injection fields as hidden form fields (JSON strings) alongside your external variables. The
form’s action URL must be signed by your server, and the signature covers the raw form body as
well (see Signing Injection Requests):
<iframe name="ragtime-chat" width="100%" height="700" style="border: none; border-radius: 12px;" allow="microphone"></iframe>
<form id="ragtime-form" method="POST" action="SIGNED_URL_FROM_YOUR_SERVER" target="ragtime-chat" style="display:none;"> <!-- Instruction overrides (JSON string) --> <input type="hidden" name="instructionOverrides" value='{ "customInstructions": { "value": "Focus on Enterprise pricing.", "mode": "append" } }' />
<!-- Prefill messages (JSON string) --> <input type="hidden" name="prefillMessages" value='[ { "type": "message", "role": "assistant", "content": "Welcome back! Ready to continue?" } ]' />
<!-- You can also include external variables alongside injection --> <input type="hidden" name="user_name" value="John" /></form>
<script> document.getElementById('ragtime-form').submit();</script>Delivery: Query Parameters
Section titled “Delivery: Query Parameters”For GET requests (iframe src), base64-encode the JSON values, then sign the URL on your server
(see below). The browser-side snippet only shows the encoding:
// Build the URL with base64-encoded injection paramsconst instructionOverrides = btoa( JSON.stringify({ customInstructions: { value: 'Always respond in formal English.', mode: 'append' } }));
const prefillMessages = btoa( JSON.stringify([{ type: 'message', role: 'assistant', content: 'Welcome!' }]));
const url = new URL('https://your-ragtime-instance.com/chat/org-slug/assistant-slug/device-slug');url.searchParams.set('instructionOverrides', instructionOverrides);url.searchParams.set('prefillMessages', prefillMessages);
// Use as iframe srcdocument.querySelector('iframe').src = url.toString();Note: Query parameters are visible in the URL bar and browser history. For sensitive instructions, prefer the POST body. Either way the request must be signed.
Signing Injection Requests
Section titled “Signing Injection Requests”Injection is only accepted on signed requests, so the URL (and, for a POST, the form body) must be
signed by your server with the Signing Secret from Deployment → Embedding → Security. The
signature is an HMAC-SHA256 over the sorted query string (including timestamp, excluding
signature) followed by the raw request body, if any. A signature is valid for 5 minutes, so
generate the URL when your page is rendered, not once at build time.
import crypto from 'crypto';
// Generate a signed URL with injection parametersfunction buildSignedInjectionUrl( baseUrl: string, secret: string, overrides: object, prefill: object[]) { const params = new URLSearchParams();
// Add injection (base64-encoded JSON) params.set('instructionOverrides', btoa(JSON.stringify(overrides))); params.set('prefillMessages', btoa(JSON.stringify(prefill)));
// Add timestamp and sign params.set('timestamp', Date.now().toString()); params.sort(); const payload = params.toString(); const signature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); params.set('signature', signature);
return `${baseUrl}?${params.toString()}`;}For a POST, sign the URL’s query string followed by the exact form body bytes you send. See Embedding for full signing details.
Error Handling
Section titled “Error Handling”| What happens | Cause |
|---|---|
401 Invalid signature |
The URL or body is not signed, the signature does not match, or it is older than 5 minutes. |
500 signing not configured |
Request signing is on but no Signing Secret is set. |
| Injection ignored, page loads | Injection is not enabled, or the request was not signed. |
| Fields ignored | Malformed JSON, or prefill messages outside the limits above. |
422 |
An override exceeds a character limit, or the resulting instructions fail the safety check. |
429 |
Rate limit exceeded (standard chat rate limits apply). |
The page load is where injection is checked. Ragtime verifies the signature there and seals the accepted overrides into the chat session, so the chat cannot be handed different overrides later from the browser. Standard IP-based (60 req/min) and organization-wide (200 req/min) rate limits apply to the chat as usual.
- Use append mode to layer context on top of carefully tuned dashboard instructions, rather than replacing them entirely.
- Prefill messages are great for onboarding flows — show the user a simulated conversation before they type their first message.
- Instruction overrides are applied per embed load. They don’t persist between sessions.
- The same character limits that apply on the Personality tab apply to injected values. Keep custom instructions under 7,500 chars and opening instructions under 2,000.
- Injected instructions go through the same safety check as published ones. Text that tries to switch off the platform’s rules, or that is harmful, is refused.
- Combine injection with External Variables for maximum flexibility — use variables for user data and injection for behavior tuning.