The Shift: Applications That Act, Not Just Respond
Traditional chatbots answer questions. Embedded agents execute actions.
An embedded agent runtime turns your app into a system that executes user intent, not just responds to it. This isn’t about adding a help widget. It’s about embedding an action engine inside your application that can execute workflows, invoke APIs, update systems, and orchestrate multi-step processes.
This guide walks you through building your first embedded agent experience using a fictitious GrandShield Insurance company as a real-world example.
Why This Matters
- Reduces user friction → No navigation across flows, everything in one conversation
- Cuts support & ops workload → Agents handle routine tasks autonomously
- Increases conversion → Quotes → policies, claims → completion, all in-flow
- Enables automation without rebuilding UI → Add capabilities without touching frontend
Bottom line: Users express intent. Your application executes it. No clicks, no forms, no friction.
Who Should Read This
- Engineers building embedded AI experiences
- Product teams designing workflow automation
- Developers new to watsonx Orchestrate
- Anyone wanting to add conversational AI to their app
About GrandShield Insurance
This article documents the real-world implementation of GrandShield Insurance, a production-ready insurance platform built with watsonx Orchestrate embedded chat. GrandShield demonstrates how embedded agents can transform traditional insurance workflows, from quote generation to policy management to claims processing, into seamless conversational experiences.
What makes this an agentic solution?
Traditional insurance platforms require users to navigate through multiple screens, fill out forms, and wait for manual approvals. GrandShield’s embedded agents act autonomously on behalf of users:
-
Customers get instant quotes by describing their needs in natural language
-
Underwriters receive AI-powered risk assessments and approval recommendations
-
Claims managers process claims with automated document verification and fraud detection
The agents don’t just answer questions, they execute workflows, call backend systems, and orchestrate multi-step processes across the entire insurance lifecycle.
Now let’s dive into how we built it.
What This Looks Like in the Product

GrandShield customer dashboard with embedded agent
The Architecture: Agents, Tools, and Systems
Before we dive into authentication and initialization, let’s understand what we’re building:
The Agent Ecosystem
GrandShield uses specialized agents for different user roles:
| Agent |
Role |
Key Capabilities |
| Customer Agent |
Policyholders |
Quote generation, policy lookup, claims filing |
| Underwriter Agent |
Risk assessment |
AI-powered risk scoring, approval workflows |
| Claims Manager Agent |
Claims processing |
Document verification, fraud detection, settlement |
How Agents Connect to Systems
Each agent has access to specialized tools that connect to backend systems:
User Message
↓
Embedded Chat (with JWT context)
↓
watsonx Orchestrate Agent
↓
Tools (Python/OpenAPI)
↓
Backend Systems (PostgreSQL, APIs, Email)
Example:
When a customer asks, “What’s my deductible?”, the agent:
1. Receives the message with JWT context (user email, role)
2. Calls the get_policy_details tool with the user’s email
3. Tool queries PostgreSQL database
4. Returns policy details to agent
5. Agent formats response for user
The key insight: Agents don’t just retrieve data, they execute actions. They can create quotes, update policies, file claims, and trigger workflows across multiple systems.
Part 1: Where Context Begins (Login → JWT → Agent)
GrandShield login page
This is where agent context starts. The user logs in with an email, the backend generates a signed JWT containing identity and role, and watsonx Orchestrate receives that verified context before the agent acts.
Login → JWT → Embedded Chat → Agent → Tools → Systems
Key insight: The agent does not ask who the user is. It already knows because identity is injected at login.
Part 2: JWT Authentication - Why It Matters
JWT authentication isn’t just about security, it’s about preventing impersonation inside your app and ensuring the agent acts on behalf of the right user.
User Login
↓
JWT Server signs token
↓
Embedded chat receives token
↓
watsonx Orchestrate verifies token
↓
Agent acts for the verified user
The Flow in GrandShield
- Customer logs in → Backend receives email and role
- JWT Server signs token → Embeds user context in token
- Frontend receives token → Passes to embedded chat
- Agent receives JWT → Knows exactly who it’s talking to
- Agent calls tools → Uses email from JWT context
- Tool queries database → Returns only that customer’s data
Without JWT: Anyone could claim to be anyone. The agent would have no way to verify identity.
With JWT: The agent knows with cryptographic certainty who the user is and can safely execute actions on their behalf.
The RS256 Advantage
RS256 uses asymmetric encryption:
Private key (on your server): Signs tokens
Public key (on watsonx Orchestrate): Verifies tokens
Even if someone intercepts a token, they can’t create new ones without your private key. This is critical for embedded agents that can execute actions, not just answer questions.
What the JWT Contains
The token embeds user context that the agent can trust:
{
sub: "john@example.com", // Subject (user identifier)
context: {
user_email: "john@example.com", // Who they are
user_name: "John Doe", // Display name
user_role: "customer" // What they can do
},
exp: 1234567890 // Expiration (1 hour)
}
Key points:
Signed with RS256 (private key on your server)
Verified by watsonx Orchestrate (public key)
Contains user identity and role
Expires after 1 hour (auto-refresh handled by events)
Impact: Secure, verifiable identity that enables safe agent actions.
Part 3: Context Variables - The Agent’s Eyes and Ears
Context variables are what transforms a generic chatbot into a personalized assistant that understands your users and their current state.
Without context variables, your agent operates in the dark:
- It doesn’t know who the user is
- It can’t see what they’re currently viewing
- It has no awareness of their session state
- Every interaction requires the user to re-explain their situation
With context variables, your agent becomes contextually aware: - It knows the user’s identity and role from JWT - It sees what page they’re on and what data they’re viewing - It understands their current workflow state - It can provide instant, personalized responses
For GrandShield’s implementation, we use two types:
1. JWT Context (Stable Identity)
Set once at login and embedded in the authentication token: -
user_email - Who they are
user_name - Display name for personalization
user_role - What they can access (customer, underwriter, claims_manager)
2. Dynamic Context (Current State)
Injected per-message to capture what’s happening right now:
chat.on("pre:send", (event) => {
event.context = {
current_page: window.location.pathname,
selected_policy: getSelectedPolicy(),
form_data: getCurrentFormData()
};
});
Impact: Eliminates 2–3 back-and-forth messages per interaction.
Dashboard and agent sharing user session
The dashboard and embedded agent share the same user session, allowing the agent to reason over who the user is and what they are currently viewing.
Part 4: Initialize embedded chat via watsonx Orchestrate Script
The initialization follows three steps:
1. Load the watsonx Orchestrate Script
const script = document.createElement('script');
script.src = 'https://dl.watson-orchestrate.ibm.com/wxoLoader.js?embed=true';
document.head.appendChild(script);
2. Create the Chat Instance
const instance = window.WxOChat.createInstance({
element: document.getElementById('chat-container'),
agentID: 'your-agent-id',
region: 'us-south',
serviceInstanceID: 'your-instance-id',
authToken: jwtToken // From your JWT server
});
3. Set Up Event Handlers
Events let you customize behavior at key moments:
// Inject context before each message
instance.on('pre:send', (event) => {
event.context = {
current_page: window.location.pathname,
selected_policy: getSelectedPolicy()
};
});
// Handle token refresh automatically
instance.on('authTokenNeeded', async (event) => {
event.authToken = await getNewToken();
});
// Chat is ready
instance.on('chat:ready', () => {
console.log('Chat initialized');
});
Key events: -
pre:send - Inject dynamic context before each message
authTokenNeeded - Refresh expired tokens seamlessly
chat:ready - Chat loaded and ready for interaction
That’s it! The chat is now embedded, authenticated, and context-aware.
Part 5: Seeing It in Action
Here’s what the complete flow looks like:

Quote creation conversation
When a customer asks “I need a quote for my 2020 Honda Civic”:
Customer logs in → JWT token generated with their email and role
Dashboard loads → Embedded chat initializes with GrandShield agent
Customer asks: “I need a quote for my 2020 Honda Civic”
Agent receives message with context:
user_email: “john@example.com” (from JWT)
user_name: “John Doe” (from JWT)
current_page: “/dashboard” (from instance context)
Agent calls backend tools to get customer data and calculate premium
Agent collects details via conversational form
Quote created in under 60 seconds
The result: All of this happens in one conversation, without leaving the dashboard.
For the detailed technical walkthrough with all tool calls and data flows, see Part 2: Building Production Agent Runtimes (coming soon).
Common Pitfalls and How to Avoid Them
1. No Context → Agent Asks Dumb Follow-Ups
Problem: Without context variables, agent asks “What’s your email?” even though the user is logged in.
Fix: Always inject user context via JWT and pre:send events.
2. Weak Auth → Dangerous Impersonation Risk
Problem: Without JWT, anyone can claim to be anyone. Agent might show the wrong user’s data.
Fix: Use RS256 JWT with proper key management. Never trust client-provided identity.
3. Poor Event Handling → Inconsistent State
Problem: Token expires mid-conversation, chat breaks, user loses context.
Fix: Implement authTokenNeeded handler for seamless token refresh.
4. Stale Context → Wrong Answers
Problem: User switches pages, agent still thinks they’re on old page.
Fix: Use pre:send to inject fresh context with every message.
What You’ve Built
By following this guide, you’ve created:
- Secure authentication with JWT tokens
- Context-aware agent that knows who users are
- Dynamic state injection for personalized responses
- Seamless token refresh for uninterrupted conversations
- Production-ready foundation for embedded agents
Next Steps
Now that you have the basics working, you’re ready for:
- Part 2: Building Production Agent Runtimes (role-based routing, MCP integration, advanced architecture)
- Agent customization: Adding custom tools and workflows
- Multi-agent systems: Coordinating multiple specialized agents
- Advanced patterns: Proactive agents, real-time data, voice integration
Key Takeaways
- JWT is not just auth → it’s agent identity: The token tells the agent who it’s acting on behalf of
- Context is everything: Without context variables, your agent is blind
- Events = extensibility: The event system lets you customize every interaction
- Security enables action: Proper auth lets agents safely execute workflows
- Start simple, scale smart: Get the basics right before adding complexity
Resources
See also: Building Intelligence with Intelligence
Built with: IBM Bob, watsonx Orchestrate, Node.js, PostgreSQL
Coming soon -> Part 2: Building Production Agent Runtimes - Advanced architecture, MCP, and role-based routing
#community-stories1#watsonxOrchestrateClientAdoptionExperience