Debugging ServiceNow Performance Issues

Performance issues are often some of the most difficult to fix. There are dozens of variables from code to networking that must be examined in order to track down the problem and trying to get the problem to manifest while you are looking can be next to impossible…unless you know where to look.

In this article I will outline several scenarios in which performance is degraded. I’ll use Helsinki for this but most of these techniques should work for Geneva and Fuji as well.

Transaction Logs

The main tool we will use is ServiceNow itself.  The transaction log will contain most of the evidence we need to investigate performance issues.

  1. Under System Logs navigate to one of the Transaction Logs.
  2. On the List view add all the columns referencing “Time” there are about a dozen total.
  3. On the List view add Session, System ID and User Agent
  4. On the form view add every single field.
    I like to create a separate section for the time fields.


I will break these scenarios into one of three categories:

  • Client is the users browser or machine
  • Server is the ServiceNow server
  • Network is everything in between

For each scenario I will list symptoms and potential root causes.

Scenario 1: Poor Network Performance

A fairly common scenario, users may experience poor network performance especially when there are multiple locations, in an on-premise installation, where the users must VPN in or where additional devices such as firewalls or proxies come into play.


  • One or more users will report intermittent degraded performance
  • If multiple users report issue it may only occur at specific times or locations
  • If a single user reports issue it may only happen at specific locations

Verifying The Issue Users should try the following.

  • Logout, completely clear cache, delete all cookies and try logging in again
  • Log in from a different browser
  • Log in from a different machine on the same network

If the issue still persists it may be an issue with the network. To verify:

  1. Navigate to Transaction Logs (All User)
  2. Find all transactions for a particular users session
  3. Find all transaction where the Client response time or Network time is excessive (>5000ms)
  4. If there are excessively high Network times then those should be flagged and you should look for additional logs around the same time
  5. If additional log entries are found this trend will likely point to a network issue
  6. If there are excessively high Client response times you should compare this time to the other “time” fields (excluding Browser Time)
  7. If the sum of the other time fields does not closely match the Client response time then it is likely a network issue.

Once you have determined you have a network issue it is necessary to look for trends to isolate the problem.

  • Do affected users have the same location or network?
  • Is the issue isolated to a specific time of day?
  • Do any users access ServiceNow through a proxy?
  • Is the issue intermittent or consistent?

Potential Root Causes

  • Overloaded or malfunctioning networking equipment – This would almost certainly affect other applications as well.
  • Overloaded proxy – If users access ServiceNow through a proxy, is the machine correctly configured and will it support the current load?
  • Insufficient bandwidth.
  • Poor wireless signal.


  • Unfortunately for networking issues there is not much that can be done from ServiceNow. Infrastructure may need to be upgraded or reconfigured to support the load.

Scenario 2: Mis-configured ACL

Usually occurring for non-admin users or those with specific roles, mis-configured ACLs can impact forms but especially lists where ACLs run multiple times.


  • One or more users will report excessively long load times for lists or forms.

Verifying The Issue

  1. Navigate to Transaction Logs (All User).
  2. Find all transactions for a particular users session.
  3. Find all transaction where the ACL time is excessive (>100ms).
  4. For ACLs even a fraction of a second is a very long time.
  5. Search for any other transactions for the same URL.
  6. If the same URL has a trend of long ACL times there may be a mis-configured ACL.

Validate the ACL is mis-configured

  1. Based on the URL you should be able to find the affected table. Usually it will be in the name however if it is not a standard List or Form page (for instance a UI Page) you may need to look through the contents of the page to see the source table(s).
  2. View the ACLs for the table.
  3. Look for any ACLs with Scripted Conditions.
  4. Verify the Script does not have nested for loops or any other violations of best practice.

Potential Root Causes

  • Poorly written Scripted ACLs
  • Excessive number of records being accessed


  • Scripts should be re-written to be as efficient as possible.
  • Lists and queries should be properly limited where necessary.
  • Additional filters can be added to lists to cut down on the number of records returned.
  • Potentially re-structuring tables or columns to simplify the script.

Scenario 3: Mis-configured Business Rule

A very common scenario is when Business Rules are not written correctly or several rules are written poorly and stack up to create a poor user experience. Most commonly when a user creates or updates but this can occur any time a business rule runs with the exception of asynchronous types.


  • One or more users will report excessively long wait times saving or loading a record.

Verifying The Issue

  1. Navigate to Transaction Logs (All User).
  2. Find all transactions for a particular users session.
  3. Find all transaction where the Business rule time is excessive (>2000ms).
  4. Find all transaction where the Business rule count is excessive (>10).
  5. Search for any other transactions for the same URL.
  6. If the same URL has a trend of long Business rule times or counts there may be an issue with the BRs.

Validate incorrect Business Rules

  1. Open the Business Rules for the particular table.
  2. Look for Business Rules which match the conditions reported by user (when saving, when creating).
  3. Look for all After or Before rules (Async rules will not apply since they do not stop the user session).
  4. Verify there are not an excessive number or rules.
  5. While having many Business Rules is not bad or uncommon the efficiency of those rules needs to increase with the number. Otherwise many rules that are somewhat slow can add up to a long wait time for end users.
  6. Verify the content of the Business Rules.
  7. Like ACLs you should avoid making an excessive amount of queries or nested queries in a BR.

Potential Root Causes

  • Multiple poorly written Business rules
    • Example: 10 or more rules which each take 250ms will end up 2.5 seconds for the user, this is only a part of the process though so the over all time may end up being excessive.
  • Single poorly written Business rule
    • A single rule taking more than 1000ms will directly impact the users experience


  • Scripts should be re-written to be as efficient as possible.
  • Minimizing the number of GlideRecord queries and number of results returned.
  • Potentially moving some scripts to asynchronous where possible

Scenario 4: Under-performing Node

A very uncommon scenario but also one that is not fixable except by ServiceNow. This will usually involve ServiceNow restarting and possibly decommissioning the node.


  • Multiple users will report excessive wait times performing any action in the system
  • Issue will usually be intermittent
  • Issue will occur more frequently at peak times

Verifying The Issue

  1. Navigate to Transaction Logs (All User).
  2. Find all transactions where the Response Time is excessive (>5000ms).
  3. Add the System ID column
  4. Verify that no other cause (Network, BR, ACL) is affecting the performance.
  5. This may manifest as a longer Session wait time, Semaphore Wait time or SQL time
  6. You may also try to eliminate transactions that are expected to take longer, such as those with larger outputs (Output length)
  7. You may also eliminate those requests which affect multiple System IDs
  8. If there is a node (System ID) which is constantly under-performing and where the same requests execute quickly on other nodes it may be isolated to that node.
  9. You may open a HI server ticket to confirm the node is not functioning correctly

Potential Root Causes

  • If the issue consistently happens even after restarting the node hardware may be defective
  • Many other causes are unknown especially since we do not have access to the back-end


  • Ask ServiceNow to restart the node via HI ticket or Support

Scenario 5: Browser Performance

A very common scenario especially for environments with older browser (specifically Internet Explorer). Poor performance is almost exclusively limited to IE but there are scenarios where Chrome and Firefox will not work correctly.


  • One or more subset of users will report a performance issue especially loading forms or custom pages
  • Issue will be consistent and easily reproduced
  • Issue will only occur on a certain browser or machine

Verifying The Issue

Before verifying check that the user is actually using a Browser on their desktop or laptop and it is not related to a mobile device.

  1. Navigate to Transaction Logs (All User).
  2. Add the User Agent column.
  3. Find all the Transactions for a particular users session who is reporting the issue.
  4. OR Find all transactions where the Response Time is excessive (>5000ms).
  5. Eliminate any transactions which can be explained by other issues.
  6. Try to correlate any poor performance to a particular User Agent.
  7. Look up the Users User Agent string to determine which browser they are using.

Validate the browser is not running in “Compatibility Mode”

  1. For Internet Explorer ask the User to verify their version by going to “About Internet Explorer”
  2. If the user reports a version which does NOT match the User Agent reported in the transaction log they may have compatibility mode on which should be disabled.

Validate the Browser is supported

  1. Older versions of Internet Explorer (<10) generally do not perform well enough to have a good User Experience in ServiceNow
  2. Versions of Internet Explorer (<9) may not work at all

Validate extensions are not interfering

  1. Ask the user to disable extensions OR run an instance of the browser in private browsing mode (this usually disables all extensions)
  2. If the issue does not persist with extensions disabled review the extensions to see if any may be causing an issue
  3. Disable extensions one a time to verify.

Validate no errors are being reported

  1. Ask the user to verify there are no errors in the JavaScript console. Most browsers have a developer console which will output all JavaScript errors.
  2. Believe it or not some errors are expected but an excessive amount especially those which report missing resources could be affecting the user experience.

Potential Root Causes

  • Unsupported Browser.
  • Browser running in compatibility mode.
  • Browser extension impacting performance.
  • GPO pushing browser setting which impacts performance.
  • GPO pushing system setting which prevents caching.
  • Cache disabled through browser setting.
  • Browser unable to reach resources – this may also manifest as the UI appearing strange.


  • Upgrading to the latest browser version.
  • Disabling Compatibility Mode.
  • Removing or resolving extension or browser configuration.
  • Verifying network configuration (firewall or proxy) allows users machine to retrieve correct resources.

Scenario 6: Excessive or Incorrect Client Side Scripts

Another common scenario is for the user to see poor performance due to too much form automation on the client side. Offloading some work to Business rules or re-architecting it for performance will usually resolve these.


  • One or more users will report an issue with forms taking a long time to load.
  • Users may reports jittery or unresponsive form when changing values.

Verifying The Issue

  1. Navigate to Transaction Logs (All User).
  2. Find all transactions for the table or form where the issue is reported which have an excessive (>2000ms) Client script or UI Policy time
  3.  Note that these values will only include those scripts run when loading.
  4. If script time is consistently long there may be an issue with the number or efficiency of the script.

Validate the script is impacting performance

  1. For either/both UI Policies and Client Scripts disable all scripts.
  2. Enable each script testing the form.
  3. Take note of the load time. If a single script increases the load time dramatically there may be an issue with the script.
  4. If each script or policy increases the load slightly resulting in a long load time, there may be an issue with the quantity of scripts.

Validate the form layout

  1. Validate there is not an excessive amount of fields,tabs, related lists or embedded lists on the form.
  2. Validate there are not custom Formatters present.
  3. If there are an excessive amount of controls on a form it will directly impact the load time for the user.

Potential Root Causes

  • Too many Scripts or Policies.
  • Poorly written Scripts.
  • Excessive amount of AJAX transactions in scripts.
    • Some AJAX is OK, but while those transactions are occuring synchronously the user is unable to do anything.
    • Synchronous AJAX should only be used when the result is NECESSARY for the user to proceed.
  • Too many fields present on form.
  • Too many lists or embedded lists.


  • Re-writing Scripts to be more efficient.
  • Refactoring or combining UI Policies.
  • Changing synchronous AJAX to asynchronous where possible.
  • Changing some form automation to run as Business rules where possible.
  • Removing fields or creating additional views to only show necessary fields.
  • Removing unnecessary fields or lists.

Scenario 7: Incorrect User Expectations

A perfectly valid expectation is that every page will respond quickly but not every page in ServiceNow is equal. Sometimes 5, 10 or even 30 seconds is reasonable when the system is crunching 1000s or rows to display in a report.


  • User reports performance issue for particular pages.

Verifying The Issue

  1. Navigate to Transaction Logs (All User).
  2. Find all the transactions for the users session.
  3. Find any excessively long transactions (>5000).
  4. Take note of the URL.
  5. If the user is loading or a report it may be valid to expect wait times greater than 5 seconds.

Potential Root Causes

  • User is loading a Report or Dashboard.
  • User is loading too many records on a list.


  • Explain to the user the wait times are valid.
  • Reconfigure the report to have additional conditions.
  • Reset the user preference to display less rows.
  • Change the users Home page if possible.

Getting the Current URL

Recently ran into this wall which stumped me for a few.  Had to get the full URL including the path from a UI Page on the server.  Using my book as a reference (shameless plug) I found `RP.getReferringURL()`, but this only returns the page name I found out and RP is not a usable object everywhere.

The solution was to find the actual Request object through the Transaction.

var tr = new GlideTransaction.get();

So what is happening here? GlideTransaction.get() returns the current transaction. It has a scriptable method ‘getRequest()’ which returns the underlying request for this transaction which an HTTPServletRequest. Not every method is going to be available since SN has whitelisted/blacklisted many but `getRequestURL()`.

There you have it the full URL with the path! What other methods have you found to get the URL?

YouTube Like Loader

Just a simple script to add a YouTube like loading bar to the top of the page for AJAX Requests. Many users said they wanted a way to know when the system was “thinking”. There actually is a loading GIF in the top right (I noticed it in Fuji) but it’s a bit hard to see. This adds a very obvious loader to every page, even popups and CMS page.

This should go in a Global UI Script. Tweak as necessary!

if(self == top){
var loadingDiv = document.createElement("div");
var loadingInterval = false;
var loadingIntervalWidth = 0;
var stopLoading = false; = "100%"; = "fixed"; = "2px" = "0"; = "0"; = "2000"; = "#29d"; = "none";

document.addEventListener("DOMContentLoaded", function(event) {

function startProgress(){

if(loadingInterval == false){
stopLoading = false; = "block"; = "0%";
loadingIntervalWidth = 0;
loadingInterval = setTimeout(incrementProgress, 50);


function incrementProgress(){

loadingIntervalWidth++; = loadingIntervalWidth.toString() + "%";
if(loadingIntervalWidth < 100 && stopLoading == false){ loadingInterval =setTimeout(incrementProgress, 50); } else { loadingDiv.display = "none"; stopProgress() } } function stopProgress(){ stopLoading = true; = "100%"; loadingInterval = setTimeout(hideProgress, 100); } function hideProgress(){ loadingInterval = false; loadingIntervalWidth = 0; loadingDiv.display = "none"; = "0%"; clearTimeout(loadingInterval); } CustomEvent.observe('ajax.loading.start', function() { startProgress() }); CustomEvent.observe('ajax.loading.end', function() { stopProgress(); }); }

Two Big Announcements

One, I am at Knowledge15!  Please come say “Hi” at the Cerna Solutions booth.

Second, and this is the reason I have not been blogging much lately, I am nearly done writing my first – and I am pretty sure the world’s only -and I am certain the world’s LAST – book on Jelly in ServiceNow!

Here is a quick summary of what the book “Using Jelly in ServiceNow” contains:

  • Start to end walkthrough of every function with examples
  • Full page examples with walkthroughs
    • Everything from simple pages to portals and AJAX pages
    • Examples showing how to use Frameworks
  • Documentation on all Glide API Interfaces for Jelly
  • Full language reference
  • Full JavaScript Object reference
  • Over 200 Pages of content

During the conference I am offering pre-orders at a special price of $25.  As soon as the book is ready (~Mid April or earlier) it will be delivered by email.

Any questions feel free to stop by the booth or leave a comment here!  Thanks.

Get the book now!

Update: Some folks were asking for more details so here is the Table of Contents for Using Jelly In ServiceNow.

  • 0. Introduction
  • 1. Jelly
  • 1.1. Key Concepts
  • 1.2. Jelly and ServiceNow
  • 1.2.1. UI Pages
  • 1.2.2. UI Macros
  • Formatters
  • 1.2.3. Other Scriptable Areas
  • 2. Jelly Scripting
  • 2.1. Jelly Tag Library
  • 2.1.1. Variables
  • 2.1.2. Output
  • 2.1.3. JEXL Expressions
  • 2.1.4. Conditions
  • 2.1.5. Looping
  • 2.1.6. Unused Jelly Tags
  • 2.2. Glide Tag Library
  • 2.2.1. Setting Up A Reference
  • 2.2.2. Scripting Tags
  • Running JavaScript
  • Scripting Helpers
  • Using Functions and Macros
  • Debugging Tags
  • Miscellaneous Functions
  • 2.2.3. UI Tags
  • Basic HTML Elements
  • HTML Elements
  • Form Elements
  • Choice Lists
  • ServiceNow Elements
  • Miscellaneous Tags
  • Undocumented Tags
  • 2.3. Debugging
  • 3. Advanced Usage
  • 3.1. Glide and Jelly JavaScript Objects
  • 3.1.1. Executing Jelly
  • 3.1.2. Render Properties
  • 3.1.3. Jelly Contexts
  • 3.1.4. Evaluating Expressions
  • 3.2. Overriding Default Templates
  • 3.3. System Properties
  • 3.4. UI Element Tags
  • 3.5. Creating Custom UI Tags
  • 4. Jelly Examples
  • 4.1. Core Concepts
  • 4.1.1. Multiple Phases
  • 4.1.2. Fibonacci Numbers
  • 4.1.3. Bubble Sort
  • 4.2. Static Page
  • 4.2.1. Hello World
  • 4.2.2. Simple Calculator
  • 4.2.3. Output A List
  • 4.2.4. Simple Form
  • 4.2.5. Form Using Macros
  • 4.3. Dynamic Page
  • 4.3.1. Dynamic Calculator
  • 4.4. Multi-Page Application
  • 4.4.1. Simple Portal
  • 4.4.2. Advanced Form
  • 4.5. AJAX Application
  • 4.5.1. AJAX Form
  • 4.5.3. AJAX Form Widget
  • 4.6. Custom Formatter
  • 4.6.1. Custom Element
  • 4.6.2. Form Widgets
  • 4.7. Mobile Page
  • 4.7.1. Mobile Only Page
  • 4.7.2. Responsive Page
  • 4.8. Frameworks and Libraries
  • 4.8.1. Datatables List
  • 4.8.2. Twitter Bootstrap
  • 5. Jelly XML Language Reference
  • 6. JavaScript Objects Reference

SNinja – Minimal ServiceNow Menu

Well that was a long break.  To start the New Year off I am publishing a tool I have been working on called SNinja.  It aims to be a replacement for the standard Left Hand Nav window.


Using SNinja is easy just hit the ` button to begin.  That’s the backtick button right above Tab.  Hit ` again or Escape to close the SNinja window.

As you start typing the auto-complete will match Modules and Table names.  Hit up and down to move through the options or Tab to auto-complete the current selection.

For Modules just hit enter to execute them.

For tables you can either hit Tab again and enter a search term to Search the table or hit period and enter one of these commands.

  • list – Brings up a list
  • form – Goes to the form view
  • dict – Loads the dictionary values
  • recent – Brings up records edited today
  • br – Brings up a list of business rules
  • cs – Brings up a list of client scripts
  • acl – Brings up a list of ACLs
  • act – Brings up a list of UI Actions
  • pol – Brings up a list of UI Policies

You can also type current in place of a table name to reference the current table you are on if you are in a list or form view.

Finally you can go directly to a page  by typing the name of the page and .do at the end.  Like “”

Source Code and Update Sets are here:


Using cURL To Upload Files

Uploading files is fairly easy in SN but what if you need to upload a lot of files?

There are some solutions using the AttachmentCreator service which work great but I wondered if it was possible to do it without any programming at all. So I racked my brain then I remembered a tool: cURL.

cURL is a tool used for making all sorts of web related requests. The best part about is it a command line tool so if you are in need of automating web requests this is the tool to use. Theres several versions for every OS out there and its fairly well documented.

So lets take a look at how to use it…

If you haven’t already grab a copy of cURL from

Logging in is a two step process, first we need to initialize our connection and set up a cookie:

curl --cookie-jar cjar -k -o output1.log --location ""

The –cookie-jar cjar parameter creates a cookie called cjar so that we can save our information

-k tells cURL to just accept any certificates that the site offers, this gets us by HTTPS if that’s enabled on your instance.

-o output1.log tells curl to output to a log file instead of the screen

–location tells curl to follow any redirects

Finally we put our instance URL.

Once you run this command and you have a cookie jar created you can attempt to log in.

curl --cookie cjar --cookie-jar cjar -k -o output2.log --data user_name=USERNAME --data user_password=PASSWORD --data ni.nolog.user_password=true --data ni.noecho.user_name=true --data ni.noecho.user_password=true --data remember_me=true --data screensize=1920x1080 --data sys_action=sysverb_login --location ""

This command reuses some of the same parameters but also specifies all the data used to log in. Just replace USERNAME, PASSWORD and INSTANCE and you should get a positive response back.

The way to check that everything is working properly is in the output files. If they return the code that would be the homepage you are golden.

Finally once you have your cookie and are logged in you can start uploading files.

curl --cookie cjar --cookie-jar cjar -k -o output3.log --location -F attachFile=@test.png ""

In this case I am uploading a PNG file called test that’s located in the same directory as cURL. If this is successful you will now be able to see the newly uploaded file on your instance.

Because this is an image file it will be available in the Image file browser but also at or

Note: Theres also no need to keep logging in, once you are in you can continue to upload files.

If you’ve got tons of files no problem, just couple this technique with the `for` command (Windows Systems) and you can loop through all the files in a directory.

Heres a quick tutorial on that command:

Simple Service Catalog Gallery

Here is a really simple Gallery View for Service Catalog built as an example for a fellow SN Developer.  It uses Jelly mostly and incorporates some jQuery for displaying details.

I have kept it very simple on purpose so it may be extended and changed to fit any needs.

Here is the Gist on GitHub.  Feel free to modify it however you need.  To install it  just create a UI Page and drop the contents in.

Service Catalog Gallery

Layout and Styling has been adapted from

Background is from


ServiceNow Coding Style Part 2

So as a continuation to the previous article I want to expand the entire process of Coding Style with steps you can use in your own coding practices and as the basis of a Peer Code review process.

Step 0 – Installing Sublime (or another Smart Editor)

These instructions are set up for Sublime but are mostly tool agnostic as long as a similar plugin can be found.   This process will take a few minutes, but it will save you so much time I don’t think you will mind.  While it’s good to be aware of all the recommendations so you can use them naturally when you are coding, rely on tools as much as possible to automate code cleanup.

Grab Sublime from .  It’s $70 for a User License, but it’s worth every penny IMO.  You can evaluate it before you buy it to make sure it’s right for you.

Install the Sublime Package Control tool using the instructions from

Install node.js from  This is required for JSHint.

Install JSHint

Install the JSBeautify, DocBlocker, JSHint Sublime Plugins by opening Sublime and pressing Ctrl+Shift+P (Mac users figure this out on your own!) and typing “Package Control: Install Package”

When the Plugin window pops up start typing the name of the plugins, then press enter to install.

JSHint and JSBeautify both work on .js files, so to test create a test JS file with this content and press Ctrl+Alt+F to format it, and Ctrl+Alt+J to JSHint it.  If everything is installed correctly you should get a list of errors in the script.

function fakeFunction(name, cb, isBool) {
Step 1 – Formatting

This refers back to the last post and is the first thing I usually look for in a code review.  Using JSBeautify makes this very simple, just run it, I accept most of the defaults, the only thing I might change is the indent_size setting to “4”.  All plugin settings can be tweaked in Sublime by going to Preferences > Package Settings > Package Name > Settings Default.  All changes should update immediately.

Step 2 – Naming Conventions

Avoiding poorly named variables, functions and records is essential to understanding code.  Properly named functions and variables make the code self-documenting and eliminate the need for many comments.  Here is a recap of the Coding Standards from the last article.

Variables – camelCase
Functions – camelCase
Private Functions – _camelCase
Classes – InitialsAreCapitals
Constants – ALL_CAPITALS
CSS Class – kebab-case
ServiceNow Records – PREFIX – Record Name
(for records that don’t use the name as a file name)
For UI Scripts it can be anything just no spaces.
For UI Macros I try to identify the usage like service_catalog_menu

Step 3 – JSHint Errors

JSHint will likely drive you insane with it’s complaining but it WILL make you a better coder and less dependent on JavaScript to ignore your mistakes.  To run it in Sublime you must save the file as .js

It will run automatically on Save or by pressing Ctrl+Alt+J

Certain things you can ignore are issues regarding using a function before it was defined, any complaints about ServiceNow specific objects not being declared (since they are global) and the error Do Not use JSON as a constructor.

Other than those exceptions I try to, and recommend you try to, fix all errors reported.  == versus === is very important to pay attention to because in MANY places === will break previously working functionality.  It is still best to use === and to explicitly compare types correctly or convert objects to strings before comparing.

It is most definitely more work NOW but it will save you headaches in the long run.

Step 4 – Engineering Principles

Two Principles that I mentioned before are DRY and SOC.  These should be applied when possible.  It is important to understand how to properly use ServiceNow to implement these principles.

Example – Within a series of business rules the same function is repeated and changed only slightly in each business rule.  The correct way to apply DRY in this case is to generalize the function so that the “tweaked” part is a parameter and then move that function to a Script Include.  It may even be possible at that point to move all the Business Rules to a single rule.

Example – Several reports were created as UI Pages that use the same basic layout but with just tweaked values.  In this case it may be best to either pass the parameters in the request OR to relocate the copied layout to a UI Macro and then include the macro.

Example – The same function is used within Client Scripts throughout the system.  In this case moving the function to a UI Script might be the best solution so the function is available to all Client Scripts.

The other principle I try to implement is Separation of Concerns.  This too goes back to understanding where all the code should be placed in ServiceNow.

Example – If styling is included directly in HTML  it is best to move that to a Style Sheet record and include that sheet.

Example – When working on a custom UI Page JavaScript to manipulate the DOM and make GlideRecord queries is mixed within functions.  This is definitely a bad way to do things, at the very least the code should be separated into functions whose intention is very specific.  At first glance, this may seem like just extra busy work, but the inevitably the application will grow, and if code is all separated by concern, it makes it easier to understand and re-use.

These principles are not hard rules, they need to be applied with some discretion.  If it is the 11th hour before a production push I would not recommend re-factoring all code into Script Includes.

Step 5 – ServiceNow Best Practices

This is a growing list of fixes or quirks within ServiceNow which just need to be memorized and looked for.  This list will update as I find and create more worst practices.

Do not use current.update() in onBefore Business Rules
Limit Synchronous GlideRecord Calls
Create functions in Business Rules and call them
Avoid nesting GlideRecords deeply
Don’t hardcode values; use Constants or System Properties
GlideRecords should check for next or hasNext before using them
All variables should be declared
A function should not be longer than one screen and ideally not even remotely that large
All paths in an AbstractAJAXProcessor Script Include should return a value
To get a GlideRecord field value, always use .toString() or .getDisplayValue()

Step 6 – Documentation

For all non-generated functions, like Client Scripts, I try to generate documentation.  This is not the same as comments, which should be used SPARINGLY.   Documentation states exactly what a function does, what it accepts as parameters and what it returns.  This is especially important in JavaScript because we don’t always know the type of parameters and returns.

To create a block like this, in your file right before a function you can type /** and enter.  This will automatically look at the function and pull out its parameters and returns and create the documentation for you.  I used an onChange function here for example but since they wont typically change parameters its not necessary to document each param, just the description.


* Looks up the current caller and adds VIP styling
* and sets location based on the callers location
* @param {Object} control
* @param {String} oldValue
* @param {String} newValue
* @param {Boolean} isLoading
function onChange(control, oldValue, newValue, isLoading) {

If all of your code lives locally on your system, you will be able to create API documentation automatically with these blocks.

Local Files and Backup

I find it a best practice to store every file I work on locally.  Typically I will create a folder structure in a directory that is backed up to a service like  The folder structure can mimic the table structure in ServiceNow, so a folder for sys_script_include, sys_script, sys_ui_script.  Or using friendly names Script Includes, Business Rules and so on.  Don’t get lazy here!  Keeping you files organized will speed things up in the future.

RemoteGlideRecord Revisited

So there was a request to bring back an old article on RemoteGlideRecord.  I am fairly certain ServiceNow will want to deprecate this Package.  I have tested the following in Eureka and it still works but I don’t know for how long.  Of course, even if you use this and it gets deprecated you always have the option of another integration type.

So what is RemoteGlideRecord?  It is a Package that allows you to use GlideRecord to query from one ServiceNow Instance to another.  If you are interested, behind the scenes this is executing a SOAP Request and uses Basic Authentication to authenticate to the second instance.

To create a basic instance of the Package use the following syntax.

var gr = new"", "TABLE");
gr.setBasicAuth("USER", "PASS");


Of course replace INSTANCE with your target instance, TABLE with the target TABLE and USER/PASS with the user and password.

WOAH!  Wait a second.  I don’t want to store my passwords in plain text in a script file!

Great point.  So here is an example of the Encrypter class.  You can encrypt and store passwords as properties and decrypt them when you need them.

var encrypter = new GlideEncrypter();
var encryptedPass = encrypter.encrypt("test");

gs.log( encrypter.decrypt(encryptedPass) );


Once we have the basic object set up the query can be executed.  Here is a sample of the code to run that query complete with some error checking to make sure the connection is valid.

if (gr.isValid()) {

while ( {

} else {
gs.print("not valid");


Notice that you cannot just dot.walk to the field name you must use getValue, getDisplayValue, getIntValue, getBooleanValue.

Likewise setting a value is done with setValue(field, value).

There are also a few configuration options which may or may not help you.

setAcceptGZIP(boolean) and setSendGZIP(boolean) obviously instruct the RemoteGlideRecord to send and receive GZIP.  This should be true.

setRedirectSupported(boolean) I can only assume tells RemoteGlideRecord to follow redirects, although I cannot test this theory.

setupProxy( host, port, user, pass ) seems like it can route the call through a proxy although I can think of no reason why that would ever happen.

setReturnDisplayValue(boolean) will turn of returning display values, if you aren’t planning on using them it can save some bytes off of what gets transferred.

setDebug(boolean) turns off and on debugging.  Off by default this will add invaluable log outputs that will definitely help if you don’t get connected straight away.

There is also a RemoteGlideAggregate which extends RemoteGlideRecord.  Seems to have the same methods as a standard GlideAggregate.  So there’s that to try as well.

Start using Now

Given that I work remotely most of the time I am quick to try new tools but very rarely does something change enough to provide a reason to change.  Over the years IM, Email and Yammer have held true while Mumble, IRC and others have failed.

Well today I finally signed up for, an enterprise communication platform, and I immediately realized the awesome potential.  The interface is clean and to the point but just beneath the surface are a ton of functions that either completely missing or practically unusable in other apps.  File sharing and code sharing were the two that jumped out immediately.  Then digging even more the integrations hooks caught my eye.

Of course this is ripe for integrating with ServiceNow so I took a stab at it.  Turned out to be incredibly easy.

Here I will walk you through setting up Slack with ServiceNow.

First set up a private test channel in Slack.  Then go to “+ Add a service integration”.  Towards the bottom is “Incoming WebHooks”

Add an Incoming WebHook and copy the WebHook URL that was generated.  Believe it or not we are already half done.

In ServiceNow create a new Outbound REST Web Message.  Set the REST Endpoint to that WebHook URL and Save.

Then go to the “post” function – actually this is the only one we need so you can remove the others.  In the Content field add the following:


Add a REST Message Function Parameter and name it text and set the value to Hello World.

That’s it.  Run a test to make sure it works and you are good to start using the integration.

Now you may want to add additional configuration, such as setting the name and channel which you can do by adding more parameters into the Content field.  You can also configure these properties in Slack on the Integration details page.

Here’s an example with Username specified.  Don’t forget to add the Function Parameter.


So that’s a basic integration.  You can also build more complicated messages.  Here is one setup for sending out an Incident notification.

"fallback": "${fallback}",
"text": "${text}",
"pretext": "${pretext}",
"color": "${color}",
"fields": [{"title":"Priority","value":"${priority}","short":false},{"title":"Short Description","value":"${short_description}","short":false}]


That’s it!  I wish they were all that easy.