
ServiceNow GlideAjax Explained: Calling Server-Side Code From Client Scripts
A Client Script runs in the user's browser.
A GlideRecord query normally belongs on the server.
So what happens when your Client Script needs information that is not already available on the form?
That is where GlideAjax becomes useful.
GlideAjax provides a controlled bridge between client-side and server-side ServiceNow code.
A Client Script can send parameters to a client-callable Script Include, allow the server to perform the required processing, and then receive the result asynchronously.
A typical flow is:
Client Script → GlideAjax → Script Include → server-side logic → response → Client Script
This allows us to keep database queries and reusable business logic on the server while still providing responsive client-side behaviour.
In this guide, we'll look at how GlideAjax works, how to build the Script Include and Client Script sides, how to return single or multiple values, how to handle asynchronous responses correctly, and how to avoid common performance and security mistakes.
What Problem Does GlideAjax Solve?
Imagine an Incident form with a Caller field.
When the user selects a caller, we want to display the caller's manager.
The Client Script knows the caller's sys_id.
But the manager information lives in the sys_user table.
We could try to make the client retrieve more data directly, but that mixes browser logic with server-side data access.
A better architecture is:
Client Script
Knows which caller was selected.
GlideAjax
Sends the caller ID to the server.
Script Include
Looks up the user and determines the manager.
Callback
Receives the answer.
Client Script
Updates the form.
Each layer has a clear responsibility.
The Two Sides of a GlideAjax Call
Every normal GlideAjax implementation contains two important pieces.
The client side creates the request:
1var ga =2 new GlideAjax(3 'UserAjax',4 )5
6ga.addParam(7 'sysparm_name',8 'getManagerName',9)10
11ga.addParam(12 'sysparm_user_id',13 userSysId,14)15
16ga.getXMLAnswer(17 function(answer) {18 // use response19 },20)The server side receives it:
1var UserAjax =2 Class.create()3
4UserAjax.prototype =5 Object.extendsObject(6 global.AbstractAjaxProcessor,7 {8 getManagerName:9 function() {10 var userSysId =11 this.getParameter(12 'sysparm_user_id',13 )14
15 // server-side logic16
17 return result18 },19
20 type:21 'UserAjax',22 },23 )The client does not directly execute GlideRecord.
The server handles that work.
Create the Client-Callable Script Include
Let's build the server side first.
Create a Script Include named:
UserAjax
Enable:
Client callable
Then use:
1var UserAjax =2 Class.create()3
4UserAjax.prototype =5 Object.extendsObject(6 global.AbstractAjaxProcessor,7 {8 getManagerName:9 function() {10 var userSysId =11 this.getParameter(12 'sysparm_user_id',13 )14
15 if (!userSysId) {16 return ''17 }18
19 var userGR =20 new GlideRecord(21 'sys_user',22 )23
24 if (25 !userGR.get(26 userSysId,27 )28 ) {29 return ''30 }31
32 return userGR33 .manager34 .getDisplayValue()35 },36
37 type:38 'UserAjax',39 },40 )This Script Include accepts a User sys_id, retrieves that User on the server, and returns the display value of their Manager.
Why AbstractAjaxProcessor Is Required
A GlideAjax-compatible Script Include extends:
1global.AbstractAjaxProcessorThis provides the server-side request-processing functionality used by GlideAjax.
It gives the Script Include methods such as:
1this.getParameter()which lets us read values provided by the Client Script.
In scoped applications, using:
1global.AbstractAjaxProcessormakes it clear that AbstractAjaxProcessor comes from the global scope.
The Script Include Must Be Client Callable
A normal server-side Script Include is not automatically exposed through GlideAjax.
If the browser needs to call it, configure the Script Include as:
Client callable
This should be intentional.
Do not make every Script Include client callable just in case you need it later.
Server-only logic should normally remain server-only.
Only expose the operations the client genuinely requires.
Call the Script Include From a Client Script
Now create the client-side call.
For example, an onChange Client Script for caller_id might contain:
1function onChange(2 control,3 oldValue,4 newValue,5 isLoading,6 isTemplate,7) {8 if (9 isLoading ||10 !newValue11 ) {12 return13 }14
15 var ga =16 new GlideAjax(17 'UserAjax',18 )19
20 ga.addParam(21 'sysparm_name',22 'getManagerName',23 )24
25 ga.addParam(26 'sysparm_user_id',27 newValue,28 )29
30 ga.getXMLAnswer(31 function(answer) {32 if (!answer) {33 return34 }35
36 g_form.setValue(37 'u_manager_name',38 answer,39 )40 },41 )42}The flow is now complete.
The browser sends the user ID.
The server finds the user's manager.
The response comes back.
The callback updates the form.
sysparm_name Selects the Server Method
This line is particularly important:
1ga.addParam(2 'sysparm_name',3 'getManagerName',4)sysparm_name tells GlideAjax which method inside the Script Include should run.
In our example, the Script Include contains:
1getManagerName:2 function() {3 // ...4 }So the client sends:
1'sysparm_name',2'getManagerName'If those names do not match, the expected method will not run.
Custom Parameters Must Begin With sysparm_
Additional parameters should also use the sysparm_ prefix.
For example:
1ga.addParam(2 'sysparm_user_id',3 userSysId,4)Then retrieve it on the server:
1var userSysId =2 this.getParameter(3 'sysparm_user_id',4 )This creates a clear contract between the Client Script and Script Include.
Avoid using ServiceNow's predefined GlideAjax parameter names for your own data, including:
sysparm_namesysparm_functionsysparm_valuesysparm_type
Use descriptive custom parameters instead, such as:
sysparm_user_id
or:
sysparm_category
GlideAjax Is Asynchronous
This is one of the most important concepts to understand.
When we call:
1ga.getXMLAnswer(2 function(answer) {3 // response4 },5)the browser sends the request and continues executing.
It does not freeze while waiting for the server.
Later, when the server responds, the callback runs.
That means this code is wrong:
1var managerName = ''2
3ga.getXMLAnswer(4 function(answer) {5 managerName = answer6 },7)8
9g_form.setValue(10 'u_manager_name',11 managerName,12)The final setValue() may run before the server response has arrived.
At that moment:
1managerNamemay still be empty.
Code That Depends on the Response Belongs in the Callback
Instead, write:
1ga.getXMLAnswer(2 function(answer) {3 g_form.setValue(4 'u_manager_name',5 answer,6 )7 },8)Anything that depends on the server result should happen:
- inside the callback
- or inside another function called from that callback
This asynchronous model is fundamental to client-server development.
Avoid Synchronous GlideAjax Calls
ServiceNow also has historical synchronous patterns such as:
1getXMLWait()These should generally be avoided.
A synchronous request blocks client execution while waiting for the server.
If the network or server is slow, the interface can appear frozen.
Asynchronous GlideAjax lets the browser continue operating while the request is processed.
For modern client-side development, design around callbacks rather than blocking requests.
getXMLAnswer() Is Convenient for Simple Returns
When the Script Include simply returns a value:
1return managerNamegetXMLAnswer() provides a convenient way to receive that result.
For example:
1ga.getXMLAnswer(2 function(answer) {3 console.log(answer)4 },5)The callback receives the answer directly.
This works well for results such as:
- a name
- an email address
- a boolean represented as a string
- a
sys_id - JSON text
getXML() Gives Access to the Full Response
Another asynchronous option is:
1ga.getXML(2 function(response) {3 var answer =4 response5 .responseXML6 .documentElement7 .getAttribute(8 'answer',9 )10
11 console.log(answer)12 },13)This gives you access to the response XML.
For many simple use cases, getXMLAnswer() is easier to read because you're interested primarily in the returned answer.
Use the response style that matches what the implementation actually needs.
Returning More Than One Value
Sooner or later, one string is not enough.
Suppose the client needs:
- user's name
- manager
- department
We could create four GlideAjax calls.
But that would mean four client-server round trips.
A better approach may be to return one JSON object.
On the server:
1getUserDetails:2 function() {3 var userSysId =4 this.getParameter(5 'sysparm_user_id',6 )7
8 if (!userSysId) {9 return ''10 }11
12 var userGR =13 new GlideRecord(14 'sys_user',15 )16
17 if (18 !userGR.get(19 userSysId,20 )21 ) {22 return ''23 }24
25 var result = {26 name:27 userGR.getDisplayValue(),28
29 email:30 userGR.getValue(31 'email',32 ) || '',33
34 manager:35 userGR36 .manager37 .getDisplayValue(),38
39 department:40 userGR41 .department42 .getDisplayValue(),43 }44
45 return JSON.stringify(46 result,47 )48 }The Script Include still returns a string, but that string contains JSON.
Parse JSON on the Client
The Client Script can receive the response:
1ga.getXMLAnswer(2 function(answer) {3 if (!answer) {4 return5 }6
7 var user =8 JSON.parse(answer)9
10 g_form.setValue(11 'u_user_email',12 user.email,13 )14
15 g_form.setValue(16 'u_manager_name',17 user.manager,18 )19
20 g_form.setValue(21 'u_department_name',22 user.department,23 )24 },25)One request now supplies all three values.
This is often cleaner and more efficient than several separate calls.
Return Only What the Client Needs
Just because you can return a large object does not mean you should.
Suppose the browser only needs:
- manager name
Do not return:
- every User field
- roles
- department metadata
- preferences
- audit information
- unrelated reference data
Returning the smallest useful response improves:
- clarity
- network efficiency
- security
- maintainability
The browser should receive only the information required for the client-side feature.
Validate Every Parameter on the Server
The Client Script may send:
1sysparm_user_idBut the server should not blindly assume that value is valid.
For example:
1var userSysId =2 this.getParameter(3 'sysparm_user_id',4 )5
6if (!userSysId) {7 return ''8}9
10var userGR =11 new GlideRecord(12 'sys_user',13 )14
15if (16 !userGR.get(17 userSysId,18 )19) {20 return ''21}The server verifies that:
- a value was provided
- the record exists
For sensitive operations, validation may need to go further.
Never Treat Client Input as Trusted
This is an important security principle.
Even if your own Client Script normally calls:
1ga.addParam(2 'sysparm_user_id',3 g_form.getValue(4 'caller_id',5 ),6)the server should not assume that every request contains a legitimate caller ID.
Client-side values can be manipulated.
A client-callable Script Include is a server endpoint.
Treat incoming parameters accordingly.
Validate:
- record IDs
- allowed values
- authorization
- relationships
- operation scope
when the feature requires it.
Client Callable Does Not Mean Permission Granted
Suppose a Script Include contains:
1deleteSensitiveRecord:2 function() {3 var sysId =4 this.getParameter(5 'sysparm_record_id',6 )7
8 // delete record9 }Making that method client callable should not automatically give every caller permission to delete the record.
The server-side operation still needs appropriate authorization.
A browser request expresses intent.
The server decides whether that intent is allowed.
This is the same security principle used in APIs and multiplayer game servers:
Never make the client the authority for privileged operations.
Keep Client-Callable Methods Focused
A Script Include called:
EverythingAjax
with 50 unrelated methods quickly becomes difficult to maintain.
Instead, group related operations.
For example:
UserAjax
might provide client-required User information.
IncidentAjax
might provide Incident-specific calculations.
AssignmentAjax
might expose assignment-related operations.
This keeps client-facing server endpoints easier to understand and secure.
Separate Ajax Wrappers From Core Business Logic
One particularly useful architecture is to keep the client-callable Script Include small.
Suppose the real assignment logic already lives in:
AssignmentService
The Ajax Script Include can call it:
1var AssignmentAjax =2 Class.create()3
4AssignmentAjax.prototype =5 Object.extendsObject(6 global.AbstractAjaxProcessor,7 {8 getSuggestedGroup:9 function() {10 var category =11 this.getParameter(12 'sysparm_category',13 )14
15 var service =16 new AssignmentService()17
18 return service19 .getSuggestedGroup(20 category,21 )22 },23
24 type:25 'AssignmentAjax',26 },27 )Now the architecture is:
Client Script
→ AssignmentAjax
→ AssignmentService
→ GlideRecord / business logic
The client-facing layer remains narrow.
The reusable business logic remains available to server-side callers too.
Why This Separation Matters
Suppose assignment logic is needed by:
- a Client Script
- a Business Rule
- a Scheduled Script
- a Scripted REST API
If the actual algorithm exists only inside the Ajax Script Include, server-side callers may be tempted to duplicate it.
Instead:
AssignmentService
contains the reusable business rule.
AssignmentAjax
provides the client-facing bridge.
This keeps GlideAjax as a transport mechanism rather than the owner of the entire feature.
GlideAjax vs Client-Side GlideRecord
A common question is:
Why not query the table directly from the Client Script?
GlideAjax usually gives us much more control over the client-server boundary.
The Script Include can decide:
- which table to query
- which conditions to use
- which fields to return
- what validation to apply
- what information the client is allowed to receive
The browser simply asks for the specific result it needs.
That generally creates a clearer architecture than exposing broad data access to the client.
Don't Return an Entire Record When You Need One Field
Imagine the Client Script only needs a user's email.
A focused Script Include can return:
1return userGR.getValue(2 'email',3)The browser does not need the entire sys_user record.
Small responses add up.
One inefficient call may be unnoticeable, but many forms making many unnecessary requests can affect the user experience.
Reduce the Number of Server Round Trips
Suppose an onChange Client Script does this:
- GlideAjax call for email
- GlideAjax call for manager
- GlideAjax call for department
- GlideAjax call for location
All four requests relate to the same User.
A single getUserDetails() method may be a better design.
Return:
1{2 email: '...',3 manager: '...',4 department: '...',5 location: '...'6}Now the form makes one round trip instead of four.
Don't Call the Server If You Already Have the Data
GlideAjax is useful, but it should not become your default for every form operation.
Before making a server call, ask:
Is this information already available on the client?
If it is already present in a form field, use:
1g_form.getValue()If a simple UI Policy can solve the requirement, use the UI Policy.
If server information could reasonably be supplied during form load through an appropriate mechanism, consider that architecture too.
Every unnecessary GlideAjax request adds latency and server work.
Be Careful With onChange Scripts
An onChange Client Script can execute frequently.
Suppose every change to a field immediately calls GlideAjax.
If the user changes the value several times, the form may issue several server requests.
Ask whether:
- every change really needs server processing
- the script should ignore empty values
- the script should ignore form loading
- some results can be reused
- multiple values can be returned in one call
Good client-side performance often comes from simply avoiding unnecessary calls.
Always Handle isLoading
For an onChange Client Script, a common pattern is:
1if (2 isLoading ||3 newValue === ''4) {5 return6}Without the isLoading check, the script may trigger a GlideAjax call while the form is initially loading.
That may be unnecessary.
Only run the server request when the requirement actually needs it.
Watch Out for Race Conditions
Asynchronous calls introduce another issue.
Imagine the user selects:
User A
A GlideAjax request begins.
Before it returns, the user changes the field to:
User B
A second request begins.
If User A's slower response arrives after User B's response, the form might display stale information.
One way to protect against this is to verify that the field still contains the value associated with the request.
For example:
1var requestedUserId =2 newValue3
4ga.getXMLAnswer(5 function(answer) {6 if (7 g_form.getValue(8 'caller_id',9 ) !== requestedUserId10 ) {11 return12 }13
14 g_form.setValue(15 'u_manager_name',16 answer,17 )18 },19)Now an outdated response is ignored.
Handle Empty and Invalid Responses
Do not assume every Ajax request succeeds with useful data.
For example:
1ga.getXMLAnswer(2 function(answer) {3 if (!answer) {4 g_form.clearValue(5 'u_manager_name',6 )7
8 return9 }10
11 g_form.setValue(12 'u_manager_name',13 answer,14 )15 },16)Think about:
- no matching record
- missing reference
- empty field
- rejected access
- invalid parameter
A predictable failure path makes the form more reliable.
Handle JSON Parsing Carefully
If the server returns JSON, avoid blindly parsing an empty response.
For example:
1ga.getXMLAnswer(2 function(answer) {3 if (!answer) {4 return5 }6
7 try {8 var result =9 JSON.parse(answer)10
11 // use result12 } catch (error) {13 console.error(14 'Unable to parse GlideAjax response',15 error,16 )17 }18 },19)In a controlled application, malformed JSON should be unusual.
But defensive parsing can make troubleshooting much easier.
Prefer Stable Response Shapes
Suppose getUserDetails() normally returns:
1{2 email: '[email protected]',3 manager: 'Manager Name'4}Do not sometimes return:
1falseand other times return:
1'User not found'and other times return an object.
That forces the client to understand several unrelated response formats.
Prefer a predictable structure.
For example:
1{2 success: true,3 email: '[email protected]',4 manager: 'Manager Name'5}or:
1{2 success: false,3 message: 'User not found'4}The shape stays consistent.
A Structured JSON Response
The server could return:
1var result = {2 success: false,3 email: '',4 manager: '',5 message: '',6}7
8if (!userSysId) {9 result.message =10 'User ID is required'11
12 return JSON.stringify(13 result,14 )15}16
17var userGR =18 new GlideRecord(19 'sys_user',20 )21
22if (23 !userGR.get(24 userSysId,25 )26) {27 result.message =28 'User not found'29
30 return JSON.stringify(31 result,32 )33}34
35result.success = true36
37result.email =38 userGR.getValue(39 'email',40 ) || ''41
42result.manager =43 userGR44 .manager45 .getDisplayValue()46
47return JSON.stringify(48 result,49)Now the client has a consistent response contract.
Keep Server Methods Small
A client-callable method should not become a thousand-line business process.
For example:
getManagerName()
should probably retrieve or determine a manager name.
It should not also:
- update the Incident
- create tasks
- send notifications
- trigger integrations
- change assignments
Those responsibilities belong elsewhere.
GlideAjax works best when the client asks for a focused server operation.
Avoid Overriding AbstractAjaxProcessor Methods
When creating a client-callable Script Include, avoid casually overriding methods inherited from:
AbstractAjaxProcessor
such as initialize.
The superclass provides the functionality GlideAjax needs for processing requests.
If you replace inherited behaviour incorrectly, the Script Include may stop working as expected.
Keep the Ajax Script Include straightforward unless you have a specific reason and understand the superclass behaviour.
Methods Beginning With _ Are Useful for Internal Helpers
Client-callable methods should represent operations the browser is allowed to request.
If the Script Include needs helper functions that should not be directly callable by the client, using a leading underscore is a useful convention.
For example:
1getUserDetails:2 function() {3 var userSysId =4 this.getParameter(5 'sysparm_user_id',6 )7
8 return this._buildUserResult(9 userSysId,10 )11 },12
13_buildUserResult:14 function(userSysId) {15 // internal helper16 }This helps distinguish the client-facing API from internal implementation details.
GlideAjax Is Not for Server-to-Server Calls
GlideAjax exists to bridge:
Client → Server
If you're already inside:
- a Business Rule
- Script Include
- Scheduled Script
- Scripted REST resource
you normally do not need GlideAjax to call another Script Include.
Instantiate the server-side class directly.
For example:
1var service =2 new AssignmentService()3
4var result =5 service.getSuggestedGroup(6 category,7 )Using GlideAjax from server-side code would add the wrong layer of abstraction.
Use GlideAjax for a Real Client Need
Good GlideAjax use cases include:
- retrieve information not present on the form
- calculate a server-derived value
- validate something against server-side data
- retrieve a small set of related values
- ask a reusable server service for a suggestion
Examples might include:
- get a caller's manager
- determine a recommended assignment group
- check whether a relationship exists
- retrieve server-calculated configuration
- return several related values for a selected reference
When GlideAjax Is Probably the Wrong Tool
GlideAjax may be unnecessary when:
- the value already exists on the form
- a UI Policy handles the requirement
- the logic is entirely client-side
- the operation belongs in a Business Rule after save
- a Data Policy should enforce the rule
- the user does not need the server result immediately
- a broader process belongs in Flow Designer
Do not create client-server communication unless the requirement actually crosses the client/server boundary.
GlideAjax Does Not Replace Business Rules
Suppose a Client Script uses GlideAjax to check whether a record is valid before submission.
That can improve the user experience.
But if the validation is important for data integrity, server-side enforcement may still be required.
Why?
Because records can be created or updated through:
- REST APIs
- imports
- integrations
- Background Scripts
- server-side automation
Those operations may never execute your Client Script.
GlideAjax helps the browser.
It does not automatically become the authoritative business rule.
GlideAjax Does Not Replace ACLs Either
A client-callable Script Include must still be designed securely.
Do not say:
The Client Script only shows this button to managers, so the server method is safe.
A user can potentially manipulate client-side behaviour.
Sensitive server operations should enforce appropriate access on the server.
UI restrictions improve usability.
ACLs, roles, and server-side checks enforce security.
Example: Populate User Information
Let's combine everything into a practical example.
The requirement is:
When Caller changes, populate the caller's email and manager.
The server-side Script Include:
1var UserAjax =2 Class.create()3
4UserAjax.prototype =5 Object.extendsObject(6 global.AbstractAjaxProcessor,7 {8 getUserDetails:9 function() {10 var userSysId =11 this.getParameter(12 'sysparm_user_id',13 )14
15 var result = {16 success: false,17 email: '',18 manager: '',19 }20
21 if (!userSysId) {22 return JSON.stringify(23 result,24 )25 }26
27 var userGR =28 new GlideRecord(29 'sys_user',30 )31
32 if (33 !userGR.get(34 userSysId,35 )36 ) {37 return JSON.stringify(38 result,39 )40 }41
42 result.success = true43
44 result.email =45 userGR.getValue(46 'email',47 ) || ''48
49 result.manager =50 userGR51 .manager52 .getDisplayValue()53
54 return JSON.stringify(55 result,56 )57 },58
59 type:60 'UserAjax',61 },62 )The Script Include is configured as client callable.
Example Client Script
The onChange Client Script:
1function onChange(2 control,3 oldValue,4 newValue,5 isLoading,6 isTemplate,7) {8 if (9 isLoading ||10 !newValue11 ) {12 return13 }14
15 var requestedUserId =16 newValue17
18 var ga =19 new GlideAjax(20 'UserAjax',21 )22
23 ga.addParam(24 'sysparm_name',25 'getUserDetails',26 )27
28 ga.addParam(29 'sysparm_user_id',30 requestedUserId,31 )32
33 ga.getXMLAnswer(34 function(answer) {35 if (36 g_form.getValue(37 'caller_id',38 ) !== requestedUserId39 ) {40 return41 }42
43 if (!answer) {44 return45 }46
47 var result =48 JSON.parse(answer)49
50 if (!result.success) {51 return52 }53
54 g_form.setValue(55 'u_caller_email',56 result.email,57 )58
59 g_form.setValue(60 'u_manager_name',61 result.manager,62 )63 },64 )65}This gives us:
- one asynchronous request
- server-side GlideRecord
- a small JSON response
- stale-response protection
- no duplicated database logic in the browser
Troubleshooting GlideAjax
If a GlideAjax call does not work, check the basic contract before rewriting everything.
Confirm that:
- the Script Include is active
- Client callable is enabled
- the class name matches the Script Include name
- it extends
AbstractAjaxProcessor - scoped applications use the appropriate global reference
sysparm_namematches the method- custom parameters begin with
sysparm_ - the Script Include retrieves the exact same parameter names
- the server method actually returns a value
- the callback is executing
- JSON returned by the server is valid
Logging each side separately can make debugging much easier.
Debug the Client Side
You can temporarily log:
1console.log(2 'Calling UserAjax for:',3 newValue,4)Then inside the callback:
1console.log(2 'GlideAjax response:',3 answer,4)This tells you whether:
- the call was initiated
- a response reached the browser
If no callback occurs, investigate the Script Include configuration and request itself.
Debug the Server Side
During development, server logging can confirm whether the method executes.
For example:
1gs.debug(2 'UserAjax.getUserDetails called'3)You can also log important parameters while troubleshooting.
Avoid leaving excessive logging inside frequently called production Ajax methods.
Client-side form interactions can invoke these methods many times.
A Practical GlideAjax Checklist
Before adding GlideAjax to a Client Script, ask:
- Does the client genuinely need server-side information?
Don't make a server request for data already available locally. - Can one request return everything required?
Reduce unnecessary round trips. - Is the Script Include client callable?
Client access must be deliberate. - Does it extend
AbstractAjaxProcessorcorrectly?
This provides the Ajax processing layer. - Does
sysparm_namematch the server method?
That selects the method to execute. - Are custom parameter names clear and prefixed with
sysparm_?
Keep the request contract obvious. - Is the call asynchronous?
Avoid blocking the browser. - Does the callback contain logic that depends on the result?
Don't assume the response is immediately available. - Is server input validated?
Never blindly trust client parameters. - Does the server return only what the client needs?
Keep responses small and intentional. - Could an old response overwrite newer form state?
Consider race conditions on frequently changing fields. - Is this operation truly authorized?
Client callable is not a substitute for server-side security.
Common GlideAjax Mistakes
A few patterns cause a large percentage of GlideAjax problems.
Trying to use the response before the callback runs
Remember that the request is asynchronous.
Forgetting Client callable
The browser needs permission to invoke the Script Include through GlideAjax.
Forgetting sysparm_name
The server needs to know which method to execute.
Mismatched parameter names
sysparm_user_id on the client must match sysparm_user_id on the server.
Using too many separate Ajax calls
Return related values together when appropriate.
Doing server work the client does not need
Return focused results rather than entire records.
Trusting client-supplied values
Validate again on the server.
Putting all business logic in the Ajax Script Include
Keep reusable server logic in dedicated services where appropriate.
Using GlideAjax from server-side scripts
Call server-side Script Includes directly instead.
Using client logic as security
The server must enforce sensitive access and operations.
The Architecture to Aim For
A well-designed GlideAjax feature has a clear path.
Client Script
Detects a user interaction and requests information.
↓
GlideAjax
Transfers a small set of parameters asynchronously.
↓
Client-Callable Script Include
Validates the request and exposes a focused server operation.
↓
Reusable Server Service
Optionally contains shared business logic.
↓
GlideRecord / Platform APIs
Retrieve or calculate the required information.
↓
Response
Returns only the required result.
↓
Client Callback
Updates the user experience.
Each layer does one job.
Why This Pattern Scales
Today you may only need:
Get the caller's manager.
Later the same server-side logic may be required by:
- another Client Script
- a Workspace interaction
- a Business Rule
- a Scheduled Script
- an API
- another application feature
If the real business logic is already separated from the Ajax transport layer, you can reuse it without duplicating the implementation.
That is the difference between treating GlideAjax as a quick workaround and treating it as part of a maintainable client-server architecture.
Conclusion
GlideAjax is ServiceNow's bridge between client-side form logic and server-side processing.
The fundamental pattern is straightforward:
1var ga =2 new GlideAjax(3 'UserAjax',4 )5
6ga.addParam(7 'sysparm_name',8 'getUserDetails',9)10
11ga.addParam(12 'sysparm_user_id',13 userSysId,14)15
16ga.getXMLAnswer(17 function(answer) {18 // process result19 },20)On the server, a client-callable Script Include receives those parameters, performs the required processing, and returns a focused response.
The most important principles are not the syntax.
They are the architectural boundaries:
Keep database access on the server.
Keep the browser responsive with asynchronous calls.
Return only what the client actually needs.
Validate everything supplied by the client.
Keep authoritative business rules and security on the server.
Reuse server-side services instead of duplicating logic inside Ajax endpoints.
And perhaps most importantly:
Do not make a client-server request unless you genuinely need to cross the client-server boundary.
Used carefully, GlideAjax gives ServiceNow Client Scripts access to server-derived information without turning the browser into a database layer or duplicating server-side business logic.
That makes forms more responsive, code easier to reuse, and the overall application architecture much easier to maintain.

Learn how ServiceNow Script Includes organize reusable server-side logic, reduce duplicated code, work with GlideRecord, and support GlideAjax client calls.

Learn the difference between ServiceNow Client Scripts and Business Rules, when to use each, common mistakes, performance considerations, and practical examples.

Learn how to use ServiceNow GlideRecord for server-side queries, filters, updates, inserts, reference fields, encoded queries, and performance-friendly scripting.