CAD Guide

GlideAjax: Asynchronous Client-Server Communication

Introduction

Client Scripts run in the browser and have no direct access to the ServiceNow database. When a Client Script needs server-side data — a lookup, a calculation, a permission check — the correct mechanism is GlideAjax: an asynchronous, callback-driven communication pattern that queries the server without blocking the browser.

This guide covers everything from basic GlideAjax usage to advanced patterns for multiple values and error handling.


The Core Pattern

GlideAjax requires two components:

  1. A Script Include that extends AbstractAjaxProcessor (server-side handler)
  2. A Client Script that instantiates GlideAjax and provides a callback (client-side caller)

Server Side: AbstractAjaxProcessor

// Script Include: IncidentAjaxHelper
// Client callable: ✅ Checked
var IncidentAjaxHelper = Class.create();
IncidentAjaxHelper.prototype = 
    Object.extendsObject(AbstractAjaxProcessor, {
    
    // Each public method is callable via sysparm_name
    getCallerInfo: function() {
        var userId = this.getParameter('sysparm_user_id');
        
        var user = new GlideRecord('sys_user');
        if (!user.get(userId)) {
            return JSON.stringify({ error: 'User not found' });
        }
        
        return JSON.stringify({
            name: user.getDisplayValue('name'),
            email: user.getValue('email'),
            department: user.getDisplayValue('department'),
            vip: user.getValue('vip') === '1'
        });
    },
    
    getOpenIncidentCount: function() {
        var assignee = this.getParameter('sysparm_assignee');
        
        var ga = new GlideAggregate('incident');
        ga.addQuery('assigned_to', assignee);
        ga.addQuery('active', true);
        ga.addAggregate('COUNT');
        ga.query();
        
        return ga.next() ? ga.getAggregate('COUNT') : '0';
    },
    
    type: 'IncidentAjaxHelper'
});

Critical settings on the Script Include record:

  • Client callable: Must be checked ✅
  • Name: Must match the class name exactly

Client Side: Making the Call

// Client Script — onChange on 'assigned_to' field
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || !newValue) return;
    
    var ga = new GlideAjax('IncidentAjaxHelper');
    ga.addParam('sysparm_name', 'getOpenIncidentCount'); // Method to call
    ga.addParam('sysparm_assignee', newValue);            // Parameters
    
    // ALWAYS use async callback — never ga.getXML() synchronously
    ga.getXMLAnswer(function(answer) {
        var count = parseInt(answer);
        if (count > 10) {
            g_form.addInfoMessage(
                'Warning: This agent has ' + count + 
                ' open incidents. Consider reassigning.'
            );
        }
    });
}

Returning Complex Data (JSON)

For multiple values, return JSON and parse on the client:

// Client Script
var ga = new GlideAjax('IncidentAjaxHelper');
ga.addParam('sysparm_name', 'getCallerInfo');
ga.addParam('sysparm_user_id', g_form.getValue('caller_id'));

ga.getXMLAnswer(function(answer) {
    try {
        var info = JSON.parse(answer);
        
        if (info.error) {
            g_form.addErrorMessage('Could not load caller info.');
            return;
        }
        
        if (info.vip) {
            g_form.addInfoMessage('VIP Caller: ' + info.name + 
                ' — handle with priority care.');
            g_form.flash('caller_id', '#FFD700', 0);
        }
        
        // Populate a display field
        g_form.setValue('u_caller_department', info.department);
        
    } catch(e) {
        gs.error('GlideAjax parse error: ' + e.message);
    }
});

getXML vs. getXMLAnswer vs. getXMLWait

Method Behavior Use
getXML(callback) Async, callback receives full XML response object When you need raw XML or multiple return values
getXMLAnswer(callback) Async, callback receives the answer string directly Most common — cleaner for single string returns
getXMLWait() Synchronous — blocks the browser Never use. Deprecated and performance-killing

Chaining Multiple GlideAjax Calls

When you need sequential server calls, chain them in callbacks:

function onLoad() {
    // First call: get caller's VIP status
    var ga1 = new GlideAjax('IncidentAjaxHelper');
    ga1.addParam('sysparm_name', 'getCallerInfo');
    ga1.addParam('sysparm_user_id', g_form.getValue('caller_id'));
    
    ga1.getXMLAnswer(function(answer) {
        var info = JSON.parse(answer);
        
        if (info.vip) {
            // Second call: get VIP's preferred contact method
            var ga2 = new GlideAjax('IncidentAjaxHelper');
            ga2.addParam('sysparm_name', 'getVIPPreferences');
            ga2.addParam('sysparm_user_id', g_form.getValue('caller_id'));
            
            ga2.getXMLAnswer(function(prefs) {
                var preferences = JSON.parse(prefs);
                g_form.setValue('contact_type', preferences.preferredContact);
            });
        }
    });
}

Security Considerations

Since Script Includes marked as "Client callable" are accessible to any browser session:

  • Always validate the sysparm_name parameter in complex Script Includes
  • Check caller permissions within the method if the data is sensitive
  • Never return data the caller shouldn't have access to, regardless of how they call it
getSensitiveData: function() {
    // Validate the caller has appropriate role
    if (!gs.hasRole('itil_admin')) {
        return JSON.stringify({ error: 'Access denied' });
    }
    // ... return sensitive data
}

Best Practices

  • Never use getXMLWait() — always async callbacks
  • Return JSON for multiple values; single string for simple values
  • Always parse JSON in a try/catch block
  • Validate permissions inside client-callable Script Includes
  • Name Script Include methods descriptively (verb + noun)
  • Keep Script Include methods focused — one method, one purpose
  • Test the Script Include server-side before writing the client call

Conclusion

GlideAjax is the safe, correct way to bridge the gap between client-side form logic and server-side data. The pattern is simple — a client-callable Script Include on the server, a callback-driven GlideAjax call on the client — but the details matter. Master JSON serialization, embrace asynchronous callbacks, and validate permissions in every public method, and your client scripts will be both powerful and secure.

Keep reading this guide

Log in to access the full study guide and supercharge your preparation.