Call UI actions with REST using ServiceNow OOTB way – UPDATED

Note: this out of the box method is only available from Madrid version and up, if you are using prior versions click here.

Ever since Agent Workspace was introduced work has started to lose dependencies from interacting with Jelly and Java pages which led to introduction of GraphQL and other OOTB REST functionally.

One of them, which was previously only possible through some what complicated scripting, is calling UI actions.

A new way is simple and straightforward.

There is only one endpoint to do POST call for UI actions.

POST @ /api/now/ui/ui_action/${sys_id_of_UI_action}

Additionaly, there are same 3 mandatory body parameters:

  1. sysparm_table – table name of UI action.
  2. sysparm_sys_id – sys_id of the record you want to run UI action against.
  3. api=api (this has to be static).

If your UI action is designed to take additional parameters, you can pass them as well.


How ServiceNow is updating it’s Tech Stack and is using GraphQL

One of the biggest complaints ServiceNow receives is that it is running on old technology. It is true that most of ServiceNow is running on Java, Jelly, AngularJS, which comes with poor performance, but ServiceNow is working to change that.

New ServiceNow features introduced in Madrid and enhanced in New York comes with more modern technology stack.

  • The core component of newly designed pages is not a Jelly UI page anymore (it still is for Service Portal – $, but it is done with modern JS frameworks like React or ServiceNow JavaScript UI Framework. That means no Java and no Jelly.
  • To access other specific components, there are at least 50 new OOTB undocumented REST API’s to perform ServiceNow functionality which was only possible by old school HTTP requests only (history, favorites, breadcrumbs, filters, date, impersonation, UI action, etc.). This means almost all the required functionality is accessible in the front end.
  • However, not everything is upgraded to new stack yet, there are still some iFrames that call Jelly pages and some REST API’s are missing. Those too can be called using REST API’s, but it’s complicated.
  • More API’s and more components are coming to ServiceNow. A lot of performance optimizations happen when you move away from Java and Jelly.

But the natural problem arises: if we have so many different REST API’s to call to fill our page with everything we need, it becomes too complicated to continue developing and grow. We need some way to perform BATCH REST API operations.

Here is where GraphQL comes to ServiceNow.

As REST replaced SOAP, it is believed by some, that GraphQL will replace REST due to handy benefits:

  1. You only call one endpoint to get all the date instead of calling many – you do not need to call 20 different REST API’s to get all information into one page
  2. You only get the data you ask for and not what REST API developer wanted you to get – you only get what you ask for, so you can limit the transaction size to be as little as possible – hence performance increase

It iIt is also possible to use GraphQL for your ServiceNow integrations and ditch REST API’s.

  1. You only need to call one endpoint with POST for everything you need.


2. All the parameters are in request body.

How do I call ServiceNow using GraphQL?

For example, if you wanted to get encodedRecord, sys Id and record values for specific incident:

We can also retrieve any other elements from the page (related lists, UI actions, formatters, etc.) or perform GlideRecord equivalent operations, like  isValidRecord, lastErrorMessage, canReadRecord.

To get all incidents, it looks more complicated, but way less complicated than the old way. Remember this is all done from client side and you have access to anything you ask for.

Also, as this is fully undocumented yet, I haven’t spent much time around to find the ideal queries. This probably could be optimized a lot.

What are other tools in ServiceNow to support GraphQL?

1 ) You can debug GraphQL execution by opening “Debug GraphQL” module. Session debugger was greatly enhanced with New York release, but is possible in Madrid as well the same way you debug service portal. More can be found here.

You can do some ‘mouse clicking’ in ServiceNow UI while session debugger is running and copy your GraphQL queries.

2) GraphQL subscription feature might enable you to build modern pub/sub message queues for client-side application solutions. Same as for AMB and AngularJS record watchers you could define subscriptions (ServiceNow calls them ‘Channel Responders’). With GraphQL you can do the same by utilizing sys_rw_amb_graphql_action table, which extends sys_rw_amb_action.

3) All transactions using GraphQL have “Batch REST” type and cannot be tracked separately. Logging can only be enabled at node level enabling advanced REST debugging.

How to cancel script, update or plugin rollback when it’s stuck and is breaking ServiceNow

A useful roll back and delete recovery feature was released to ServiceNow. With each script execution you can track all the database changes with possibility to recover everything with Rollback Executor.

It sounds very useful and seems like it will fix all your oopsies. However, it has flaws, does not always recover everything and might take days or weeks to finish.

One resultant flaw is that RollbackExecutor is being counted an as ‘upgrade’ activity. While it’s running you will not be able to use preview and commit update set functionality – “Update set preview and commit are unavailable because the system is currently upgrading. Click here for the Upgrade Monitor”.

As well as scheduled jobs with upgrade_safe=false parameter will not be executed while rollback is running.

Usual way to stop any transaction is by following:

  1. Go to “Progress workers”, locate the running worker and change its state to cancelled.
  2. Go to “Active Transactions (All Nodes)” or “Active Transactions”, locate the transaction you want to kill, right click it and select kill.

This is what you must do, however, both steps are not enough to kill RollbackExecutor process. You can verify it’s still running by going to and looking for background_progress_workers:

<background_progress_workers count="1" size="16">
  <running_background_progress_workers count="1">
    <background_progress_worker created_on="2019-08-14 20:38:40" executed_time="19:21:08.698" processor="glide.scheduler.worker.6" progress_worker_record="ebbefa45db97bb00c3e6294d0b96196d" queued_time="0:00:00.154" schedule_job="e7befa45db97bb00c3e6494d0b961970" total_duration="19:21:08.852">Executing Rollback</background_progress_worker>

Luckily, we can figure out next steps based on the node logs:

The upgrade system is busy because the GlideSystem is Paused

GlideSession message was modified by sanitization. [message=Update set preview and commit are unavailable because the system is currently upgrading. <a href="$">Click here</a> for the Upgrade Monitor][sanitized=Update set preview and commit are unavailable because the system is currently upgrading. <a href="$" rel="nofollow">Click here</a> for the Upgrade Monitor]

Now we simply use undocumented GlideSystem API functions.

First, we can verify if GS is paused with gs.isPaused();

Then we simply resume GlideSystem with:


Finally, our rollback activity is cancelled and we can use our update sets and scheduled jobs!

How to use ServiceNow platform system diagnostics debugger in Service Portal

Note: this is only applicable to Madrid or older ServiceNow versions. Since New York upgrade session debugging is done in a separate user friendly window.

NOW platform and Service Portal shares a lot of common utilities that are used in many places thorough the platform. For example, ACL’s, user criteria, text search are used in both parts of ServiceNow. We know we can use system diagnostics debugger tool on the platform, but what about the portal?

When we enable the debugger in the platform, at the bottom of our page,we can see what is happening under the hood of SNOW. For example, how are the database records we are trying to reach are processed, how ACL and user criteria rules were evaluated, what was the text search score for each returned item generated.

However, when we enable the debugger, this same information is not available at the bottom of our portal page.

So how do we debug platform-shared features in Service Portal?

You have to have 2 windows open. One must have Service portal opened and another one must have the platform.

  1. On platform under ‘Session debug’ select ‘Enable all’.
  2. Reload the current page you are on the portal or load any other portal page.
  3. Go back to the platform and in the filter navigator type any non existing table/UI page name and add .do in the end, for example,, or if you just want to get done with it faster something like ‘’.

That’s it. Because this ‘ isthisreal’ page does not exist, it loads debugger information of the last page that was loaded successfully, which is in our case, the Service Portal.

Apply effects of User Criteria without the need to log out and back in – ServiceNow

Have you ever had a need to apply the effects of user criteria immediately, after the user performed some actions? For example, he changed his location or his language, therefore he must see different items in the catalog or the knowledge base?

The out of the box way to apply User Criteria is tedious. First, the user needs to log out, which is something that everyone hates. The user has to go through multiple SSO white flashing screens or he has to re-enter his password. Overall, it might take up to 20 seconds till he can use ServiceNow again (for example, user has to open his KeePass to find his SNOW password).

Secondly, users want the effect to happen immediately. If you have changed your location from Norway to Sweden and you are still seeing only location specific requests for Norway employees, you might think it’s not working as expected. Everyone hates situations when they call Service Desk complaining something is not working and they are presented the same old question – ‘Have you tried logging out and in?’. There are no winners here.

Log out requirement is done for performance reasons: User Criteria is cached and is only build once, when the user has logged in.

There are some drawbacks in OOTB UC set up:

1) User needs to log out and back in which can take some time.

2) Complete user cache has to be rebuilt from 0. I would think this has quite some performance impact compared what I will suggest next.

Let’s say the criteria is based on user’s language and the user is using service portal. Let’s make sure he has no need to log out to see his language-based catalog items.

Now let’s create some Scripted user criteria records which would confirm the user criteria was applied immediately. Do this for Sweden and Norway. As in example:

Add the user criteria to some catalog items. Let’s say iPad’s can only be ordered if your language is Swedish, and iPhone’s if it’s Norwegian. Now let’s open the Service Portal:

You can see both criteria’s were evaluated and Sweden one was applied, however, when we change our language to Norway, this is not re-displayed and the criteria is not re-applied until we log out or clear server cache.

So how can we do it without logging out or clearing all server cache?

By clearing user’s private user criteria cache object whenever he changes his language.

If we use cache inspector tool (more on my previous article), we can locate the UC cache object name: criteria_cache.

To add it to the portal let’s modify the ‘User Profile’ Service Portal widget by cloning it and adding the copy to our page. Modify the server code whenever user language is changed to clear his UC cache with this code:


That’s it! No more need to log out and back in. Effects are immediate once you go back to the catalog.

Does this kind of scripted user criteria have performance implications?

No, because there is another user object cached which holds all user profile specific information, including his language setting. Therefore, user criteria scripts are only looking for the value in the cache and not performing any database queries.

How to modify ServiceNow customer hidden UI Pages

Have you ever ran into a business requirement that you thought could not be done?

I’m talking about the cases when your answer was something between these lines: “We are the customers of NOW platform and we do not have access to the source code, there are limited things we can do and modify with SNOW”.

But how limited are you actually? How much is that related to the lack of knowledge?

I want to share the findings that allowed me to make a breakthrough as a SNOW developer to support integrations that are not supported officially by ServiceNow, like corporate mobile and other restricted applications related to security requirements.

So what can you do with the information below?

  1. Find undocumented system properties and use them
  2. Modify customer hidden UI pages – modify designers, fix role issues
  3. Fix compatibility issues for SNOW unsupported unique corporate applications

First you will need to modify one ACL rule. Elevate your role to security_admin, go to ACL’s menu, find the cache_inspect UI page read ACL rule and select the “admin overrides” checkmark and save it.

Now go to the cache_inspect page by typing in the filter navigator. You will be presented with the cache inspector (v2) tool.

Here you can browse through the Shared and Private cache. Shared cache is what is put to cache for use by all SNOW users. Private cache is something that is unique to the user’s cache. For example, his recently viewed UI pages, user criteria evaluations. If the user just logged in, his cache would not have as much information loaded as if he browsed through SNOW for an hour. This means that you will only see cached items here only If you visited it through the UI first.

Now select cache type: Private and locate “syscache_jelly_template” property. This contains all cached jelly templates (UI Pages).

Jelly is language used to connect java, javascript, HTML, CSS, angular,js code together and display the contents to the user. Every single page you open in SNOW is essentially a jelly page. Even if the service portal is mostly angular.js and HTML, the initial layer for the page is jelly. Without jelly SNOW does not work.

Jelly files have .xml extension, so you will see a list of xml files in your cache inspector and the name of the plugin it came with. Now, if you click on each of them you will find the source code for each of the page in the details tab.

Let’s take $sp page which is page for any service portal. It loads $sp.xml to figure out doctype compatibility, then loads the sp.xml to figure out which portal you want to go to and does the rest. Let’s do a short POC to show this actually works for this article’s sake.

In the filter navigator go to UI pages and create a new one. Name it exactly as it is named in the cache without the .xml: $sp.

Paste the source code and modify it :

First remove the first line: java.lang.String (1112):

Next we can see that when opening any portal it first checks your browsers doctype compatibility, if it is fine, then it starts loading service portal, otherwise it redirects you to /ess page.

So, let’s just try the POC and do the opposite, if the doctype is compatible, do not load the portal, but redirect to /ess page.

Now we save it and we go to /sp and there it is, you get redirected to /ess. From the transaction log this is what we see ( is the UI page for /ess):

So why does it work and what is actually happening?

Because every time you try to load any type of resource it always first try to look in the database, if the database cannot be found for the record then it looks into application node files, usually in the JAR files or other non-compressed XML files.

All we need to do is put this in the database!

By creating a UI page, naming it $sp, the same name as it is named in the JAR file – $sp.xml, it will always load the file from the database first if it exists there.

But this is not supported by SNOW and is a customization?

Exactly, that is the reason why we would want to do it – to support something we have to support in our unique corporate environment that ServiceNow does not support officially. This can be labelled as a customization as well and could become maintenance issue if not handled properly. But if you are customizing in the right way then there is no problem modifying customer hidden content.

How to call any UI action with REST API or AJAX – ServiceNow

Note: you should only follow this guide if you are on any version prior Madrid. If you are using Madrid version or up, there is OOTB way to call UI actions. Click here.

Have you ever had a business requirement that some external integration needed more access to ServiceNow, for example, call UI actions, like execute change record risk assessment? You can do that in SNOW with a click of a button. But how can you do it externally, through an automatic solution that uses REST API or client side vanilla JavaScript?

Well here I will tell you how to do it and how it exactly works.

First, let’s prepare our environment. Open google chrome, open any change record, press F12 to access developers tools, hit the Network tab, press the clear button to clear everything and check the box next to the “Preserve Log” button.

Now, lets examine the behavior of normal UI action interaction – in the change record press “Execute Risk calculation” UI action. In the networks tab we can see exactly what happened – HTTP POST request was sent to The user-agent (Google chrome) parsed all of our information from our interaction with the web page and created a HTTP POST request.

If we know how the user-agent sends this HTTP request, can we do the same with vanilla JavaScript and REST API‘s ourselves? Let‘s have a look.

First, let‘s ignore the information we do not need to call our UI action. We only need:

sysparm_ck – our session token

sys_action – sys_id of UI action

sys_base_uri – our instance URL

sys_target – target table

sys_uniqueValue – sys_id of the change record

Let’s first try XMLHttpRequest with vanilla JavaScript straight from our browser console.

// First, we create XMLHttpRequest object

var XHR = new XMLHttpRequest();

// Now we configure our request parameters

var urlEncodedData =

“” + // This is percent encoded URL for our instance

“&sys_target=change_request” + // Target table the UI action is set for

“&sys_uniqueValue=016e2b3ddb3223009373793ebf9619ff” + // Target change record sys_id

“&sys_action=eea1aa78c0a8ce01002aa530a8f1eb65” +  // Sys_id of the Risk assesment calculation UI action

“&sysparm_ck=c42d5306dbXXXXXXXX73793ebf9619XXXX0aad94eXXXXccc1XXXX801dXXXX6a8af9aaee1”; // Our SNOW session Token

 // Set up our request‘POST’, ‘;);

 // Add the required HTTP header for form data POST requests

 XHR.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);

 // Finally, send our data.


Note that any non-alpha numerical characters have to use percent-encoding.

After XHR.send method we can see that the risk assessment calculation was performed and console logged change.updated event.

Now let‘s do the same with REST API using POSTMAN.

But how do we get the session token value first? This means that a session has to exist in current SNOW sessions list, otherwise it will not work. So we have to make 2 REST API calls for this to fully work.

Before we have our full integration running, we need to establish a Session with SNOW, retrieve our session token, then make our call to execute the UI action.

We need to create a scripted REST API that returns our session token by returning gs.getSessionToken() string. Let’s assume that we have the sys_id of our change record already from Table API.

Create POST API with /api/XXXXXX/sessiontoken/{name} resource path.

Since we cannot use gs.getSessionToken() API in our REST script, we have to gliderecord into sys_user_session table to get the csrf token.

(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {

                var body = {};


                var getToken = new GlideRecord(‘sys_user_session’);

                getToken.addQuery(‘name’,; // We use user name as query param


                if ({

                                body.token = getToken.csrf_token;



})(request, response);

We make the call in POSTMAN to get the token:

And we make the second call using the token to execute UI action.

That‘s it! Now with 2 API calls we can call any SNOW UI action from anywhere!