Skip to main content
Context variables allow you to pass additional information from your web application to the embedded web chat and make it accessible to your agent during conversations. This feature enables more personalized and context-aware interactions by providing the agent with relevant data about the user or the environment. To use context variables:
  1. Enable context_access_enabled: true in your agent definition.
  2. Add variables like channel to the context_variables in your agent definition file.
  3. Reimport the agent.
  4. Include context variables in the JWT payload.
spec_version: v1
style: react
name: hello_agent
llm: watsonx/meta-llama/llama-3-1-70b-instruct
description:  'Agent description'
instructions: |
  You are a helpful agent that must answer user questions in a clean and concise manner. Be polite and do not perform harmful behavior.
collaborators: []
tools: []
context_access_enabled: true
context_variables:
  - channel     # Use it to get access to context variables on the embedded chat
You can add context variables to a JWT token using a JavaScript script. The following script shows how to include context variables inside a JWT token in your server:
createJWT
const fs = require('fs');
const RSA = require('node-rsa');
const crypto = require('crypto');
const jwtLib = require('jsonwebtoken');
const express = require('express');
const path = require('path');
const { v4: uuid } = require('uuid');

const router = express.Router();

// This is your private key that you will keep on your server. This is used to sign the jwt. You will paste your public
// key into the appropriate field on the Security tab of the web chat settings page.
// This public key is used to validate the signature on the jwt.
const PRIVATE_KEY = fs.readFileSync(path.join(__dirname, 'wxo_security_config/client_private_key.pem'));

//The code below will use this key to encrypt the user payload inside the JWT.
const PUBLIC_KEY = fs.readFileSync(path.join(__dirname, 'wxo_security_config/client_public_key.pem'));


// A time period of 45 days in milliseconds.
const TIME_45_DAYS = 1000 * 60 * 60 * 24 * 45;

/**
 * Generates a signed JWT. The JWT used here will always be assigned a user ID using the given anonymous user ID. If
 * the user is authenticated and we have session info, then info about the user will also be added to the JWT.
 * Always use the anonymous user ID even if the user is authenticated because changing the user ID in the middle of
 * a session is not allowed.
 */
function createJWTString(anonymousUserID, sessionInfo,context) {
  // This is the content of the JWT. You would normally look up the user information from a user profile.
  const jwtContent = {
    // This is the subject of the JWT which will be the ID of the user.
    //
    // This user ID will be available under integrations.channel.private.user.id in dialog and
    // system_integrations.channel.private.user.id in actions.
    sub: anonymousUserID,
    // This object is optional and contains any data you wish to include as part of the JWT. This data will be
    // encrypted using the public key so it will not be visible to your users.
    user_payload: {
      custom_message: 'Encrypted message',
      name: 'Anonymous',
    },
    context
  };

  // If the user is authenticated, then add the user's real info to the JWT.
  if (sessionInfo) {
    jwtContent.user_payload.name = sessionInfo.userName;
    jwtContent.user_payload.custom_user_id = sessionInfo.customUserID;
  }

  const dataString = JSON.stringify(jwtContent.user_payload);

  // Encrypt the data
  const encryptedBuffer = crypto.publicEncrypt(
    {
      key: PUBLIC_KEY,
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: 'sha256'  // Specify OAEP padding with SHA256
    },
    Buffer.from(dataString, 'utf-8')
  );

  // Convert encrypted data to base64
  jwtContent.user_payload = encryptedBuffer.toString('base64');
  console.log(jwtContent.user_payload)


  // Now sign the jwt content to make the actual jwt. We are giving this a very short expiration time (10 seconds)
  // to demonstrate the web chat capability of fetching a new token when it expires. In a production environment,
  // you would likely want to set this to a much higher value or leave it out entirely.
  const jwtString = jwtLib.sign(jwtContent, PRIVATE_KEY, {
    algorithm: 'RS256',
    expiresIn: '10000000s',
  });

  return jwtString;
}

/**
 * Gets or sets the anonymous user ID cookie. This will also ensure that an existing cookie is updated with a new 45
 * day expiration time.
 */
function getOrSetAnonymousID(request, response) {
  let anonymousID = request.cookies['ANONYMOUS-USER-ID'];
  if (!anonymousID) {
    // If we don't already have an anonymous user ID, then create one. Normally you would want to use a full UUID,
    // but for the sake of this example we are going to shorten it to just five characters to make them easier to read.
    anonymousID = `anon-${uuid().substr(0, 5)}`;
  }

  // Here we set the value of the cookie and give it an expiration date of 45 days. We do this even if we already
  // have an ID to make sure that we update the expiration date to a new 45 days.
  response.cookie('ANONYMOUS-USER-ID', anonymousID, {
    expires: new Date(Date.now() + TIME_45_DAYS),
    httpOnly: true,
  });

  return anonymousID;
}

/**
 * Returns the session info for an authenticated user.
 */
function getSessionInfo(request) {
  // Normally the cookie would contain a session token that we would use to look up the user's info from something
  // like a database. But for the sake of simplicity in this example the session cookie directly contains the user's
  // info.
  const sessionInfo = request.cookies.SESSION_INFO;
  if (sessionInfo) {
    return JSON.parse(sessionInfo);
  }
  return null;
}

/**
 * Handles the createJWT request.
 */
function createJWT(request, response) {
  const anonymousUserID = getOrSetAnonymousID(request, response);
  const sessionInfo = getSessionInfo(request);

  const context = {
    dev_id: 23424,
    dev_name: "Name",
    is_active: true
  }

  response.send(createJWTString(anonymousUserID, sessionInfo,context));
}

router.get('/', createJWT);

module.exports = router;
You can check the examples for watsonx Assistant web chat that are mostly compatible with the watsonx Orchestrate embedded chat to see how to use this code example After generating the JWT token, pass it to the embedded web chat. The following example shows how to do that:
JavaScript
<script>
    function getUserId() {
        let embed_user_id = getCookie('embed_user_id');
        if (!embed_user_id) {
            embed_user_id = Math.trunc(Math.random() * 1000000);
            setCookie('embed_user_id', embed_user_id);
        }
        return embed_user_id;
    }

    function getCookie(name) {
        console.log('getCookie');
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${name}=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
    }

    function setCookie(name, value) {
        document.cookie = `${name}=${value}; path=/`;
    }
    function preSendHandler(event) {
        if (event?.message?.content) {
            event.message.content = event.message.content.toUpperCase();
        }
    }

    function sendHandler(event) {
        console.log('send event', event);
    }

    function feedbackHandler(event) {
        console.log('feedback', event);
    }

    function preReceiveHandler(event) {
        event?.content?.map((element) => {
            element.type = 'date';
        });
    }

    function receiveHandler(event) {
        console.log('received event', event);
    }

    function userDefinedResponseHandler(event) {
        console.log('userDefinedResponse event', event);
        event.hostElement.innerHTML = `
                        <cds-code-snippet>
                            node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis,
                            veritatis voluptate id incidunt molestiae officia possimus, quasi itaque
                            alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae
                            laboriosam!
                        </cds-code-snippet>
                        <br><br>
                        <div style="background-color:orange;color:white;padding:10px;">
                            <p>${event.contentItem?.template || '[No message content]'}</p>
                        </div>`;
    }

    function onChatLoad(instance) {
        instance.on('chatstarted', (instance) => {
            window.wxoChatInstance = instance;
        });
        instance.on('pre:send', preSendHandler);
        instance.on('send', sendHandler);
        instance.on('pre:receive', preReceiveHandler);
        instance.on('receive', receiveHandler);
        instance.on('feedback', feedbackHandler);
        instance.on('userDefinedResponse', userDefinedResponseHandler);
    }
    async function getIdentityToken() {
        // This will make a call to your server to request a new JWT.
        const result = await fetch(
            "http://localhost:3000/createJWT?user_id=" + getUserId()
        );
        window.wxOConfiguration.token = await result.text();
    }

    window.wxOConfiguration = {
        orchestrationID: "20250430-0912-2925-309a-35c6bef54760_20250430-0949-0287-00f2-33dc583100c9",
        hostURL: "https://us-south.watson-orchestrate.cloud.ibm.com",
        rootElementID: "root",
        deploymentPlatform: "ibmcloud",
        crn: "crn:v1:bluemix:public:watsonx-orchestrate:us-south:a/123-456::",
        chatOptions: {
            agentId: "852431a8-32dd-4925-8cc3-9ea3d3162726",
            agentEnvironmentId: "5d769a04-9445-4768-a687-710d6e9a24cf",
            onLoad: onChatLoad
        },
    };
    getIdentityToken().then(() => {
        const script = document.createElement("script");
        script.src = `${window.wxOConfiguration.hostURL}/wxochat/wxoLoader.js?embed=true`;
        script.addEventListener("load", function () {
            wxoLoader.init();
        });
        document.head.appendChild(script);
    });
</script>