How to Implement Branching Logic with ASSIGN and IF in NICE CXone Studio
What You Will Build
- This tutorial demonstrates how to construct a dynamic decision tree within NICE CXone Studio using the ASSIGN and IF actions to route users based on runtime data.
- This implementation uses the CXone Studio API and the CXone Studio Snippet syntax to programmatically define logic that would otherwise require manual drag-and-drop configuration.
- The code examples are written in JavaScript, utilizing the NICE CXone JavaScript SDK to interact with the Studio API for creating and testing these flows.
Prerequisites
- OAuth Client Type: You need an OAuth client with the
studio:flow:readandstudio:flow:writescopes. - SDK Version:
@nice-dcx/js-sdkversion 2.0.0 or higher. - Runtime Requirements: Node.js 18+ or a modern browser environment with fetch support.
- Dependencies:
@nice-dcx/js-sdk(installed via npm)dotenv(for managing environment variables)
Authentication Setup
NICE CXone uses OAuth 2.0 for authentication. You must obtain an access token before making any API calls. The following JavaScript code demonstrates how to authenticate using a client credentials grant, which is suitable for server-side integrations.
// auth.js
import { OAuth2 } from '@nice-dcx/js-sdk';
import dotenv from 'dotenv';
dotenv.config();
const CXONE_BASE_URL = process.env.CXONE_BASE_URL; // e.g., https://us-east-1.platform.nice-in接触.com
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
/**
* Authenticates with CXone and returns an access token.
* @returns {Promise<string>} The access token string.
*/
export async function getAccessToken() {
try {
const auth = new OAuth2({
baseUri: CXONE_BASE_URL,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET
});
// Request the token. The SDK handles the POST to /oauth/token
const tokenResponse = await auth.getAccessToken();
if (!tokenResponse.access_token) {
throw new Error('Failed to retrieve access token');
}
return tokenResponse.access_token;
} catch (error) {
console.error('Authentication Error:', error.message);
throw error;
}
}
Store your credentials in a .env file:
CXONE_BASE_URL=https://your-organization.platform.nice-contact.com
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
Implementation
Step 1: Define the Studio Flow Structure
In CXone Studio, flows are defined as a graph of nodes. To implement branching logic, you need three components:
- ASSIGN Action: To set a variable based on input or calculation.
- IF Action: To evaluate a condition and route to different paths.
- Outcome Nodes: To handle the true and false branches.
The following JSON structure represents a minimal flow that checks if a user’s age is greater than 18.
{
"id": "branching-logic-flow",
"name": "Age Verification Flow",
"version": 1,
"nodes": [
{
"id": "start",
"type": "Start",
"properties": {}
},
{
"id": "assign-age",
"type": "Assign",
"properties": {
"assignments": [
{
"variable": "userAge",
"value": "{{input.age}}",
"type": "number"
}
]
}
},
{
"id": "check-age",
"type": "If",
"properties": {
"condition": "{{userAge}} > 18"
},
"edges": [
{
"id": "edge-true",
"source": "check-age",
"target": "adult-response",
"condition": "true"
},
{
"id": "edge-false",
"source": "check-age",
"target": "minor-response",
"condition": "false"
}
]
},
{
"id": "adult-response",
"type": "End",
"properties": {
"message": "Access granted. You are an adult."
}
},
{
"id": "minor-response",
"type": "End",
"properties": {
"message": "Access denied. You are under 18."
}
}
],
"edges": [
{
"id": "edge-start-to-assign",
"source": "start",
"target": "assign-age"
},
{
"id": "edge-assign-to-if",
"source": "assign-age",
"target": "check-age"
}
]
}
Step 2: Create the Flow via API
You will use the CXone Studio API to create this flow. The endpoint for creating a flow is POST /api/v2/studio/flows.
// createFlow.js
import { Studio } from '@nice-dcx/js-sdk';
import { getAccessToken } from './auth.js';
/**
* Creates a new Studio flow with branching logic.
* @param {string} token - The OAuth access token.
* @param {Object} flowDefinition - The JSON definition of the flow.
* @returns {Promise<Object>} The created flow object.
*/
export async function createBranchingFlow(token, flowDefinition) {
const studio = new Studio({
baseUri: process.env.CXONE_BASE_URL,
token: token
});
try {
// The Studio API expects the flow definition in the request body
const response = await studio.flows.createFlow(flowDefinition);
console.log('Flow created successfully:', response.id);
return response;
} catch (error) {
if (error.status === 409) {
console.error('Flow with this ID already exists.');
} else {
console.error('Failed to create flow:', error.message);
}
throw error;
}
}
Step 3: Simulate the Flow Execution
To verify that the branching logic works, you can use the Studio Simulation API. This allows you to test the flow without triggering real customer interactions.
// simulateFlow.js
import { Studio } from '@nice-dcx/js-sdk';
/**
* Simulates a flow execution with specific input data.
* @param {string} token - The OAuth access token.
* @param {string} flowId - The ID of the flow to simulate.
* @param {Object} input - The input data for the simulation.
* @returns {Promise<Object>} The simulation result.
*/
export async function simulateFlow(token, flowId, input) {
const studio = new Studio({
baseUri: process.env.CXONE_BASE_URL,
token: token
});
try {
// The simulation endpoint allows you to pass input variables
const simulationData = {
flowId: flowId,
input: input
};
const result = await studio.flows.simulateFlow(simulationData);
return result;
} catch (error) {
console.error('Simulation failed:', error.message);
throw error;
}
}
Step 4: Test the Branching Logic
The following script ties everything together. It authenticates, creates the flow, and then simulates two scenarios: one where the user is 20 years old (should trigger the true branch) and one where the user is 15 years old (should trigger the false branch).
// main.js
import { getAccessToken } from './auth.js';
import { createBranchingFlow } from './createFlow.js';
import { simulateFlow } from './simulateFlow.js';
async function main() {
try {
// 1. Authenticate
const token = await getAccessToken();
// 2. Define the flow structure
const flowDefinition = {
id: "age-verification-test",
name: "Age Verification Test",
version: 1,
nodes: [
{
id: "start",
type: "Start",
properties: {}
},
{
id: "assign-age",
type: "Assign",
properties: {
assignments: [
{
variable: "userAge",
value: "{{input.age}}",
type: "number"
}
]
}
},
{
id: "check-age",
type: "If",
properties: {
condition: "{{userAge}} > 18"
},
edges: [
{
id: "edge-true",
source: "check-age",
target: "adult-response",
condition: "true"
},
{
id: "edge-false",
source: "check-age",
target: "minor-response",
condition: "false"
}
]
},
{
id: "adult-response",
type: "End",
properties: {
message: "Access granted. You are an adult."
}
},
{
id: "minor-response",
type: "End",
properties: {
message: "Access denied. You are under 18."
}
}
],
edges: [
{
id: "edge-start-to-assign",
source: "start",
target: "assign-age"
},
{
id: "edge-assign-to-if",
source: "assign-age",
target: "check-age"
}
]
};
// 3. Create the flow
const flow = await createBranchingFlow(token, flowDefinition);
const flowId = flow.id;
// 4. Simulate Scenario 1: User is 20 (Should be Adult)
console.log('\n--- Simulating User Age: 20 ---');
const resultAdult = await simulateFlow(token, flowId, { age: 20 });
console.log('Result:', resultAdult.output.message);
// 5. Simulate Scenario 2: User is 15 (Should be Minor)
console.log('\n--- Simulating User Age: 15 ---');
const resultMinor = await simulateFlow(token, flowId, { age: 15 });
console.log('Result:', resultMinor.output.message);
} catch (error) {
console.error('Main execution failed:', error);
}
}
main();
Complete Working Example
The following is a consolidated script that you can save as branching-logic-demo.js and run directly. Ensure you have the .env file set up with your credentials.
// branching-logic-demo.js
import { OAuth2, Studio } from '@nice-dcx/js-sdk';
import dotenv from 'dotenv';
dotenv.config();
const CXONE_BASE_URL = process.env.CXONE_BASE_URL;
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
async function authenticate() {
const auth = new OAuth2({
baseUri: CXONE_BASE_URL,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET
});
const tokenResponse = await auth.getAccessToken();
return tokenResponse.access_token;
}
async function createFlow(studio, flowDef) {
try {
return await studio.flows.createFlow(flowDef);
} catch (error) {
if (error.status === 409) {
console.log('Flow already exists, skipping creation.');
// For demo purposes, we assume the flow ID is known or retrieved
// In a real app, you would fetch the flow by ID
return { id: flowDef.id };
}
throw error;
}
}
async function simulateFlow(studio, flowId, input) {
const simulationData = {
flowId: flowId,
input: input
};
return await studio.flows.simulateFlow(simulationData);
}
async function main() {
try {
const token = await authenticate();
const studio = new Studio({
baseUri: CXONE_BASE_URL,
token: token
});
const flowDef = {
id: "demo-branching-logic",
name: "Demo Branching Logic",
version: 1,
nodes: [
{ id: "start", type: "Start", properties: {} },
{
id: "assign-age",
type: "Assign",
properties: {
assignments: [
{ variable: "userAge", value: "{{input.age}}", type: "number" }
]
}
},
{
id: "check-age",
type: "If",
properties: { condition: "{{userAge}} > 18" },
edges: [
{ id: "edge-true", source: "check-age", target: "adult", condition: "true" },
{ id: "edge-false", source: "check-age", target: "minor", condition: "false" }
]
},
{ id: "adult", type: "End", properties: { message: "Adult Access Granted" } },
{ id: "minor", type: "End", properties: { message: "Minor Access Denied" } }
],
edges: [
{ id: "e1", source: "start", target: "assign-age" },
{ id: "e2", source: "assign-age", target: "check-age" }
]
};
const flow = await createFlow(studio, flowDef);
const flowId = flow.id;
console.log('Testing with age 20...');
const res1 = await simulateFlow(studio, flowId, { age: 20 });
console.log('Output:', res1.output.message);
console.log('Testing with age 15...');
const res2 = await simulateFlow(studio, flowId, { age: 15 });
console.log('Output:', res2.output.message);
} catch (error) {
console.error('Error:', error.message);
}
}
main();
Common Errors & Debugging
Error: 400 Bad Request - Invalid Condition Syntax
- What causes it: The condition string in the IF action is malformed. CXone Studio uses a specific expression language.
- How to fix it: Ensure that variables are wrapped in
{{ }}. For example, use{{userAge}} > 18instead ofuserAge > 18. - Code showing the fix:
// Incorrect "condition": "userAge > 18" // Correct "condition": "{{userAge}} > 18"
Error: 409 Conflict - Flow Already Exists
- What causes it: You attempted to create a flow with an ID that already exists in your organization.
- How to fix it: Check if the flow exists before creating it, or use a unique ID for each test.
- Code showing the fix:
try { await studio.flows.createFlow(flowDef); } catch (error) { if (error.status === 409) { console.log('Flow exists, proceeding with existing ID.'); } else { throw error; } }
Error: 500 Internal Server Error - Simulation Failed
- What causes it: The flow logic contains a circular dependency or an undefined variable.
- How to fix it: Review the flow structure for infinite loops. Ensure all variables used in conditions are assigned before they are evaluated.
- Code showing the fix:
// Ensure the Assign node comes before the If node in the edge structure "edges": [ { "source": "assign-age", "target": "check-age" } ]