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:
- Server side — a Script Include that extends
AbstractAjaxProcessor - 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
| Method | Use 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')
});
}