GlideAjax in ServiceNow — Complete Guide with Examples

How GlideAjax works in ServiceNow — making asynchronous server calls from Client Scripts, building Script Includes that extend AbstractAjaxProcessor, and the patterns that work reliably in production.

GlideAjax is how Client Scripts communicate with the server in ServiceNow. It allows you to run server-side code (GlideRecord queries, Script Include methods, system property reads) from a client-side script without refreshing the page. This guide covers how it actually works and the patterns used in production.

Why GlideAjax Exists

Client Scripts run in the browser — they cannot directly access the database, query GlideRecord, or call server-side APIs. GlideAjax bridges that gap by making an asynchronous HTTP request to a server-side Script Include and returning the result to the client callback.

The Two Parts — Script Include and Client Script

Every GlideAjax implementation has two parts:

  1. Server side — a Script Include that extends AbstractAjaxProcessor
  2. Client side — a Client Script that calls the Script Include using GlideAjax

Server Side — Building the Script Include

// Script Include: UserUtils
// Client callable: true (must be checked)
var UserUtils = Class.create();
UserUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    // Method called by the client
    getUserManager: function() {
        // Read parameters sent from client
        var userSysId = this.getParameter('sysparm_user_id');
        
        // Do server-side work
        var gr = new GlideRecord('sys_user');
        if (gr.get(userSysId)) {
            // Return data to client
            return gr.getDisplayValue('manager');
        }
        return '';
    },
    
    // Another method on the same Script Include
    getDepartmentUsers: function() {
        var dept = this.getParameter('sysparm_dept');
        var gr = new GlideRecord('sys_user');
        gr.addQuery('department.name', dept);
        gr.addQuery('active', true);
        gr.query();
        
        var users = [];
        while (gr.next()) {
            users.push({
                sys_id: gr.getUniqueValue(),
                name: gr.getDisplayValue('name')
            });
        }
        // Return JSON string for complex data
        return JSON.stringify(users);
    },
    
    type: 'UserUtils'
});

Client Side — Calling the Script Include

// Client Script — onChange on assigned_to field
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || !newValue) return;
    
    // Create GlideAjax object with Script Include name
    var ga = new GlideAjax('UserUtils');
    
    // Specify which method to call
    ga.addParam('sysparm_name', 'getUserManager');
    
    // Pass parameters to the server method
    ga.addParam('sysparm_user_id', newValue);
    
    // Make the async call — callback fires when server responds
    ga.getXMLAnswer(function(answer) {
        // 'answer' is the string returned by the server method
        g_form.setValue('u_manager', answer);
        g_form.setDisplay('u_manager', answer !== '');
    });
}

Returning Complex Data — JSON Pattern

// Client Script calling getDepartmentUsers
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || !newValue) return;
    
    var ga = new GlideAjax('UserUtils');
    ga.addParam('sysparm_name', 'getDepartmentUsers');
    ga.addParam('sysparm_dept', g_form.getDisplayValue('department'));
    
    ga.getXMLAnswer(function(answer) {
        // Parse the JSON string returned by the server
        var users = JSON.parse(answer);
        
        // Use the data — e.g., populate a reference field options
        users.forEach(function(user) {
            console.log(user.sys_id + ': ' + user.name);
        });
    });
}

getXMLAnswer vs getXML

MethodUse when
getXMLAnswer(callback)Server returns a single value via return
getXML(callback)Server uses this.newItem() to return structured XML

For most use cases, getXMLAnswer() with a JSON string return is the cleanest approach.

Critical: Client Callable Must Be Checked

The Script Include must have Client callable checked, otherwise GlideAjax calls will fail with an access error. This is the most common reason GlideAjax calls appear to do nothing — the Script Include is not marked as client callable.

Error Handling

// Server side — return structured response
getUserManager: function() {
    var userSysId = this.getParameter('sysparm_user_id');
    
    if (!userSysId) {
        return JSON.stringify({ error: 'user_id required', data: null });
    }
    
    var gr = new GlideRecord('sys_user');
    if (!gr.get(userSysId)) {
        return JSON.stringify({ error: 'user not found', data: null });
    }
    
    return JSON.stringify({ 
        error: null, 
        data: gr.getDisplayValue('manager') 
    });
},

// Client side — handle errors
ga.getXMLAnswer(function(answer) {
    var result = JSON.parse(answer);
    if (result.error) {
        console.error('GlideAjax error: ' + result.error);
        return;
    }
    g_form.setValue('u_manager', result.data);
});

Performance Consideration

GlideAjax calls are asynchronous — they do not block the UI. However, every call is an HTTP round trip to the server. Avoid making multiple GlideAjax calls in sequence — design your Script Include to return all the data needed in a single call.

// ❌ Two separate server calls
ga1.getXMLAnswer(function(manager) {
    ga2.getXMLAnswer(function(department) {
        // Two round trips
    });
});

// ✅ One call returning all needed data
getUserDetails: function() {
    var gr = new GlideRecord('sys_user');
    gr.get(this.getParameter('sysparm_user_id'));
    return JSON.stringify({
        manager: gr.getDisplayValue('manager'),
        department: gr.getDisplayValue('department'),
        location: gr.getDisplayValue('location')
    });
}

Want the complete reference?

This article is part of the NowSpectrum knowledge library. Browse all products for cheat sheets, interview prep, and deep-dive reference guides.

Browse All Products →
← Back to all posts