top of page

How to Retrieve and Optimize Reference Field Values in ServiceNow Client Scripts

  • nathanlee142
  • Mar 18
  • 12 min read

Updated: Apr 1

Reference fields in ServiceNow are special fields that link to records on other tables. For example, the Caller field on an Incident form is a reference to a user record on the User [sys_user] table. Under the hood, a reference field actually stores the unique sys_id of the related record, even though it displays a friendly name or label to users. This design helps maintain relationships between records across tables.


Retrieving the value of a reference field is a common requirement in client-side scripts – you might need to fetch additional details about the referenced record (like the caller’s department or email) or use the reference for form logic and validation. However, new developers often encounter challenges when working with reference fields on the client side, because the value you get in scripts may not be what you expect.


In this article, we’ll explain these challenges and provide proven solutions for retrieving reference field values in ServiceNow client scripts.


Common Issues with Reference Field Values in Client Scripts

Developers frequently run into a few issues when trying to get reference field values on forms:

  • Getting a sys_id instead of a name: If you use g_form.getValue() on a reference field, it returns the stored sys_id (a 32-character GUID) rather than the human-friendly display name. For instance, g_form.getValue('company') on an Incident form will return something like 82826bf03710200044e0bfc8bcbe5d0b instead of “ACME Corporation.” As one developer noted, “my script is returning a sys_id instead of the value, and client scripts don't support getDisplayValue”. This can be confusing if you were expecting to see the display value.

  • Blank values when dot-walking or using wrong field names: In client scripts, you cannot directly “dot walk” a reference field to get a sub-field. For example, calling g_form.getValue('caller_id.email') will not work on the client side. Similarly, if you try to use a field name that isn’t on the current form’s table, you’ll get an empty result. For instance, a user on the sc_task (Request Task) form tried g_form.getValue('requested_for') to get the requester’s name and got blank because requested_for isn’t a direct field on that table. The reference field (perhaps Request ID) needed to be traversed to the parent record first. In summary, what works easily on the server (dot-walking with current.caller_id.email) doesn’t directly apply on the client.

  • Asynchronous data retrieval: Even when using the proper API to retrieve a reference, it often requires an asynchronous call to the server. If you don’t account for that, you might attempt to use the data before it’s available, leading to undefined or blank values. A common mistake is calling g_form.getReference('field') without a callback and expecting an immediate return value, or not handling the timing in an onChange script (e.g. running on form load when the field is empty). Without the right approach, your script could execute before the reference data is ready.


The good news is that there are standard solutions to these issues. Below, we’ll cover several methods to correctly retrieve reference field values and avoid those “blank” or misleading results. We’ll look at using g_form.getReference() with callbacks, direct dot-walk alternatives, leveraging g_scratchpad for performance, and understanding the difference between stored values and display values.


Using g_form.getReference() with a Callback Function

One of the primary ways to retrieve information from a reference field in a client script is to use the GlideForm method g_form.getReference(). This function allows you to get a GlideRecord-like object for the referenced record, which includes all its fields. The key is to use it with a callback function, because the data is fetched from the server asynchronously.


How it works: 

g_form.getReference('<fieldName>', callback) 

It takes the name of the reference field and a callback function to execute when the data is returned. ServiceNow will asynchronously fetch the referenced record using AJAX and then call your callback, passing in the record object. At that point, you can access properties of the record (just like fields on a GlideRecord). For example, if caller_id is a reference to the User table, the returned object will have properties like first_name, last_name, email, etc., corresponding to the user’s record.


Example: Suppose we want to show an alert if the selected Caller is a VIP user.

We can use an onChange client script on the Caller field:

function onChange(control, oldValue, newValue, isLoading) {
  if (isLoading || newValue === '') {
    return; 
	// ignore initial form load or clearing the field
  }
  g_form.getReference('caller_id', handleVIPStatus);
}

function handleVIPStatus(callerRecord) {
  if (callerRecord.vip === 'true') {
    alert('Heads Up: This caller is a VIP!');
  }
}

In this script, when the Caller field changes, g_form.getReference('caller_id', handleVIPStatus) triggers an asynchronous lookup of the User record. Once retrieved, our callback function handleVIPStatus runs, receiving callerRecord as an argument. We can then check callerRecord.vip (the VIP field on the User record) and act on it. The form UI remains responsive while the lookup happens, and our code only runs after the data is available.


Always use a callback: It’s technically possible to call g_form.getReference('field') without a callback, which would make a synchronous server call (blocking the browser until it returns).

However, this is not recommended – it can freeze the form, and ServiceNow strongly advises using the callback approach. In fact, in newer ServiceNow versions, omitting the callback may not even work as expected due to client-script modernization. Always opt for the asynchronous pattern for a smoother user experience.

Why use getReference: This method is useful when you need more than just the display value of a reference. For example, if the form has a reference to a Configuration Item and you need to get its serial number and model, getReference() can fetch the whole record in one go so you can access those fields in the callback. Essentially, it saves you from writing a separate server-side script or extra AJAX call in simple cases – the platform handles the query for you.

Be mindful of performance: It’s important to note that g_form.getReference() retrieves the entire referenced record (all fields) by default.

This can have a performance impact if used excessively (for example, in multiple client scripts or in loops) because each call is a server round-trip pulling a lot of data. As a best practice, use it sparingly or prefer other methods (like g_scratchpad or GlideAjax) if you need to retrieve many fields or do this frequently. For single use on a form (such as one onChange or onLoad action), it’s usually fine, but be cautious not to degrade form performance.

Always ensure the callback logic is efficient and consider user experience – the asynchronous call is fast, but not instantaneous, so design your script flow accordingly (e.g., don’t immediately require that data for a critical UI path without a loading indication).


Using Dot-Walking to Access Reference Values

On the server side, “dot-walking” is a convenient way to get values from referenced records (for example, current.caller_id.email in a business rule).

In client scripts, however, you cannot directly dot-walk by simply adding a dot in g_form.getValue(). As mentioned earlier, something like g_form.getValue('caller_id.email') will return nothing.

So how can we get the equivalent of dot-walking on the client?


There are a few strategies to effectively “dot-walk” on the client:

  • Use getReference() as a dot-walk substitute: The easiest way to get a referenced field’s value is to first use g_form.getReference() on the primary reference field, then access the desired property from the returned object. For example, if you want the Caller’s email without adding it to the form, do:

g_form.getReference('caller_id', function(caller) { 
	console.log("Caller email: " + caller.email);
});

Here, caller.email is essentially dot-walking through the reference to get the email. This approach is straightforward and leverages the example above – the difference is just which field you use from the returned record. It’s ideal for one-off needs in response to user actions (onChange, onSubmit, etc.). Keep in mind the same asynchronous caveats and performance notes from the previous section apply.

  • Add the dot-walk field to the form (as a workaround): If you frequently need a certain referenced value on the client side (e.g. Caller’s department), consider adding that as a read-only field on the form via Form Designer. ServiceNow allows you to drag in fields like Caller → Department onto the form.

    This means the platform will dot-walk and load that value automatically when the form loads. Then, your client script can simply do g_form.getValue('caller_id.department') or even g_form.getValue('u_caller_department') (depending on how it’s added) because it’s now actually present on the form. This isn’t exactly scripting, but a configuration solution – it ensures the data is readily available without extra script calls. The downside is cluttering the form with additional fields (even if hidden), and it only helps for fields known at form load, not dynamic user-driven changes.

  • Use GlideAjax for complex dot-walking: If you need to dot-walk through multiple levels of references or perform conditional logic, a GlideAjax (client-callable Script Include) might be more suitable. For example, say on an Incident form you want to get the Manager’s email of the Caller’s Department (two levels down: Incident -> Caller -> Department -> Manager’s email). You could write a Script Include to query that info and call it via GlideAjax from the client script. This avoids pulling entire records at each step. GlideAjax is beyond the scope of this article, but it’s the recommended approach for complex or performance-critical data retrieval from client scripts. (If using GlideAjax, you’d still use g_form.getValue('reference_field') to send the reference’s sys_id to your Script Include as a parameter.)


In summary, dot-walking in client scripts is achieved indirectly. The simplest method is to use g_form.getReference() and then treat the returned object’s properties as your dot-walked values. If the value comes back as undefined or empty, double-check that the reference field actually has that related field accessible (some fields might not be populated or have read access). Also remember to verify that the reference field itself is not blank before dot-walking; if the reference is empty, any dot-walk attempt is moot.


Leveraging g_scratchpad for Efficient Reference Value Retrieval

While client-side APIs like getReference and GlideAjax can fetch reference details on demand, another approach is to pre-fetch the data on the server side and pass it to the client using the g_scratchpad object. This is especially useful on form load or in situations where the reference data is known ahead of time and needed for client scripts. By using a Display Business Rule on the form’s table, you can put desired data into g_scratchpad, and it will be available to all client scripts (without additional round trips after the form loads).


What is g_scratchpad? It’s a special object that exists during the rendering of a form. A Display Business Rule (which runs on the server before the form loads) can add properties to g_scratchpad. Those properties get sent down to the client along with the form, so your client script can read them directly. Essentially, it’s a server-to-client data passing mechanism that is very efficient because it’s bundled with the initial form data.


Use case: Imagine you want to show a message on an incident form that says “You need approval from [Caller’s Manager Name]” when a certain condition is met. The Caller’s Manager is two references away (Incident → Caller → Manager), which would normally require a server lookup. Instead, you can have a Display Business Rule on the Incident table do:

// Display Business Rule on Incident
g_scratchpad.managerName = current.caller_id.manager.getDisplayValue();

This runs on the server. When the form is sent to the browser, g_scratchpad.managerName now contains the manager’s name (or is empty if not applicable). In your client script, you can directly use that value without any getReference or GlideAjax call:

if (g_scratchpad.managerName) {
  alert('You need to attach a form signed by' + g_scratchpad.managerName);
}

This example, adapted from ServiceNow’s documentation, shows how g_scratchpad can carry over a manager’s name that was retrieved via a dot-walk on the server (using server-side getDisplayValue() for accuracy).


Performance benefits: Using g_scratchpad is very fast for the client because there’s no additional network call – the data comes with the form. It’s ideal for data that you know you’ll need as soon as the form is displayed (or that doesn’t change during the session). It avoids the slight latency of getReference and is kinder to your server/database than pulling entire records repeatedly. In fact, ServiceNow best practices mention g_scratchpad as a preferred solution over getReference for passing server data to client.


Limitations: The limitation is that g_scratchpad data is only loaded on form load. If the user changes a reference field after the form is loaded and you need new info, g_scratchpad won’t automatically update. In those cases, you’d fall back to getReference or GlideAjax in an onChange script. Also, implementing g_scratchpad requires creating a Display Business Rule, which means a bit more setup. But for frequently used or critical data, it’s worth it.


Tip: 

Only put the data you need into g_scratchpad. Don’t dump whole GlideRecord objects or large chunks of data unnecessarily – that would negate the performance gains. Stick to primitive values (strings, booleans, etc.) or small objects.

Also, remember that g_scratchpad is available to all client scripts on that form, so name your properties distinctly to avoid conflicts and document their usage for future maintainers.


Understanding getValue() vs getDisplayValue() for Reference Fields

When working with reference fields, it’s crucial to understand the difference between a field’s actual value and its display value:

  • g_form.getValue('<reference_field>'): Returns the raw value that the field stores. For reference fields, this is the sys_id of the referenced record. For example, g_form.getValue('caller_id') might return "62826bf03710200044e0bfc8bcbe5d01" which is the unique ID of the user record. This is useful if you need an identifier (e.g., to pass to a server script or compare two references), but it’s not human-friendly.

  • Display value of a reference field: The display value is what users see on the form (usually a name or number that represents the referenced record). On the client, there isn’t a direct g_form.getDisplayValue('<field>') method for individual fields. Many new developers assume such a method exists, but in client scripts getDisplayValue() without parameters actually gives the current form record’s display value (e.g., the Incident number), not the reference field’s display text. That’s why the user quote earlier said “client scripts don't support getDisplayValue” in the way they expected.


So how do you get the display text of a reference in a client script? There are two main ways:

  1. Use getReference() (or dot-walk in callback) to get a field that is the display value. Typically, reference fields have a designated display field (for example, the display value of Caller [sys_user] is the user’s Name). If you use getReference, you can either:

    • Access the display value via a known field (e.g., callerRecord.name if “Name” is the display field).

    • Or use the record object’s getDisplayValue() method if available. For instance, inside the callback: callerRecord.getDisplayValue() should return the user’s display name. (This approach returns the record’s display value as a whole, which for a user is typically their name.)

    Using the callback approach is the most robust, because it ensures you have the correct data from the server. In our example above, callerRecord.name would give the same result as the display value in most cases.

  2. Use the form’s display box element (DOM): A less formal but handy trick is to use g_form.getDisplayBox('<reference_field>'). This returns the HTML input element that holds the display value on the form. By accessing its .value property, you get the text that's showing in the field. For example:

var callerNameText = g_form.getDisplayBox('caller_id').value; alert("Caller Name: " + callerNameText);

This would pop up the caller’s name as seen on the form. Under the hood, the reference field on the form is actually split into a hidden <input> for the sys_id and a visible <input> for the display value. getDisplayBox gives you that visible input. This approach was suggested on the community for getting a reference’s display value quickly. Be aware that this is somewhat dependent on the form rendering and might not work in Service Portal or future interfaces, but in the standard UI15/UI16 it’s reliable.


Illustration: In the screenshot below, the Caller reference is “Andrew Jackson,” and we have two fields capturing his Department. The Department Reference field (u_department_reference) is a reference field showing “Product Management” (the actual department name), whereas the Department string field (u_department) is showing the raw sys_id of the department because it was set via a script that used the reference value directly instead of the display value. This highlights why understanding the difference matters – if you set or compare values incorrectly, you may use an ID when you intended to use a name, or vice versa.


On this Incident form, the Department field (string) contains a sys_id value, while the Department Reference field shows the actual name. The script pulled the Caller’s department by sys_id and populated both fields, demonstrating the difference between raw values and display values.

In most cases, if you’re writing a client script and want to use a reference field’s value for comparisons or populating other fields, you’ll use getValue() (to get the sys_id) if you plan to fetch related info, and getReference() or getDisplayBox().value if you need the display text. Also remember that if you are setting a reference field’s value via script, you must use the sys_id (g_form.setValue('field', sys_id, displayValue) if you want to also set the display text). Using a name string in setValue for a reference field will not work unless that exact display value is uniquely matched, because the system expects a sys_id internally.


Conclusion

Working with reference fields in ServiceNow client scripts is a common task that becomes easy once you understand how reference data is stored and retrieved. Remember these key takeaways and best practices:

  • Reference fields store sys_ids, not names. The form shows a friendly name, but scripts by default get the underlying ID. Always decide whether you need the ID or the display value for your purpose.

  • Use g_form.getReference() with a callback to safely retrieve referenced record details. This is the go-to method for getting additional fields from the referenced record on the client side. It’s asynchronous – design your script accordingly – and avoid overusing it to keep forms snappy.

  • Direct dot-walking in client scripts isn’t supported, but you can achieve the same result by using the returned object from getReference or by server-side preparation. If a value comes back blank, ensure you’re using the correct field name and that the reference is not empty or out of scope for the form.

  • Leverage g_scratchpad for performance when you need reference information at form load. It’s a best practice to use a Display Business Rule to pre-load data that your client scripts will use, especially if it avoids multiple client calls. Use GlideAjax for on-demand scenarios where g_scratchpad isn’t applicable.

  • Know the difference between getValue() and display value. Use the right method to get what you need – sys_id vs human-readable text – and remember that getValue() alone will give you IDs for references. If you need the display text in a pinch, getReference or g_form.getDisplayBox().value are your friends.


By applying these methods, you can reliably retrieve and work with reference field values in your ServiceNow client scripts without those frustrating blanks or unexpected IDs. This will allow you to create more dynamic and user-friendly form experiences, whether you’re auto-populating fields based on a selection or enforcing rules like “Requester cannot be the Approver.” As a best practice, always test your client scripts with different scenarios (field empty vs filled, user changes the field, etc.) to ensure the reference value logic holds up. With a solid grasp of reference field handling, your ServiceNow customizations will be both technically sound and efficient, enhancing the platform’s capability to tailor to your business needs.

CONTACT

New Zealand HQ

Integrated Knowledge Consulting Office

Level 3, 93 Grafton Road

Auckland

South Korea

Integrated Knowledge Consulting Office

BMY역삼타워 6층

서울특별시 강남구 역삼동 678-10번지

 

info@ikconsulting.com

Thanks for submitting!

  • LinkedIn Social Icon

© Copyright 2025 Integrated Knowledge Consulting. All rights reserved.

bottom of page