top of page

Experiencing challenges with ServiceNow support?

Access professional, reliable assistance tailored to your needs—without breaking your budget.

Understanding the Difference Between server.get() and server.update() in ServiceNow

Updated: Mar 29

ServiceNow developers working with Service Portal widgets often encounter the methods server.get() and server.update() in server-side scripts. This article aims to clarify the differences between these two methods and explain when to use each one. Understanding server.get() vs server.update() is essential for building efficient, interactive ServiceNow applications without confusion or bugs. By mastering these methods, developers can retrieve and update data seamlessly from the server within widgets, enabling dynamic user experiences (such as forms, data lookups, or record updates) without full page reloads.


In the sections below, we will discuss what each method does, common scenarios where they are used, and how to handle both retrieving and updating data in the same script. We will also explore troubleshooting tips for typical issues developers face with these methods and provide practical examples of their usage.


Common use cases for these methods include loading record details into a Service Portal widget (server.get()), saving user-entered form data back to ServiceNow (server.update()), refreshing data on user action, and any situation where the client-side (browser) needs to communicate with the server-side script in real time. Let's dive in and see how each method works and when to use them.


What is server.get() and When to Use It


In a ServiceNow Service Portal widget, server.get() is a client-to-server call used primarily for retrieving data. When you call server.get() from a widget's client script, it triggers the widget's server script to run and sends a custom input object (if provided) to the server. The server script can then use this input to perform operations (typically read operations like querying a record or list of records) and return updated data to the client.


Key points about server.get():


  • Data Retrieval: Use server.get() when you need to fetch data from the server without necessarily saving any changes. For example, if a user clicks a button to load additional information (like related records or a filtered list), you would use server.get() to fetch that data from the database via the server script.

  • Custom Input: This method allows you to pass an object as a parameter. For instance, c.server.get({ filter: 'open', limit: 5 }) will send an input object with properties filter and limit to the server script. In the server script, this data is accessible via the input variable (e.g., input.filter).

  • No Automatic Data Post: Unlike server.update(), which sends the entire current data state, server.get() only sends what you explicitly pass. This makes it useful for cases where you want to minimize data transfer or you have specific query parameters. It does not automatically push your widget’s $scope.data, so any unsaved fields on the client won’t be sent unless you include them in the object.

  • Promise and Response: The call returns a promise, meaning it’s asynchronous. server.get() automatically updates the widget’s data object ($scope.data) with the response from the server. While you can use .then() to handle additional logic, the retrieved data is already available in the widget without extra processing. – the framework will update the widget’s data object ($scope.data) with whatever the server script returns. However, you can use the promise to run additional logic after data is returned if needed:

// Client script example: 
var c = this; 
c.loadData = function() {   
	c.server.get({ category: 'Network' }).then(function(response) {      
		// Optionally handle the response      
		console.log("Data loaded", response.data);   
    }); 
};
  • In this example, calling c.server.get({...}) will execute the server script. The server script might perform a GlideRecord query based on input.category == 'Network', populate the data object, and when done, the promise resolves with updated response.data (which also maps to c.data on the client).


When to use server.get(): Choose server.get() for retrieving or refreshing data without saving user input. It's ideal for on-demand data fetches like filtering lists, loading record details, or pulling in related data based on user actions. Because you can pass a tailored input, it’s great for scenarios like searching records by criteria or retrieving data for a selected item (by passing an sys_id or query parameter). This method helps keep your server script logic clean by differentiating read operations from write operations.


What is server.update() and When to Use It


server.update() is the counterpart to server.get() and is used primarily for saving or updating data on the server. When you call server.update() from a widget's client script, it re-runs the server script just like get does, but with an important difference: it automatically sends the widget’s current data object ($scope.data) to the server as the input. In simpler terms, it takes whatever data is currently in the widget (including any user-modified fields bound via ng-model) and posts it to the server script for processing.


Key points about server.update():


  • Data Update/Save: Use server.update() when you need to persist changes made on the client side back to the server (the ServiceNow database). For example, if your widget is a form where a user edits an incident’s details (like updating the description or state), you would call server.update() to send those changes to the server script. The server script can then use that data (accessible via the input object) to perform operations like a GlideRecord update on the incident.

  • Automatic Input from Data: This method sends the entire data object from the client to the server. You don’t need to explicitly pass an object as a parameter (in fact, server.update() typically doesn’t take any arguments). It’s a convenient way to transfer all user inputs and current state. For instance, if your client script has c.data with properties like c.data.incidentNumber or c.data.updatedFields, those will be available in the server script’s input object after calling c.server.update().

  • Re-render and Refresh: After the server script runs (e.g., after performing the update logic), the updated data object is sent back to the client and the widget view is refreshed. This means any changes to data on the server (like setting a message or updating fields to new values from the database) will automatically reflect in the UI once the promise resolves. You typically don't need to manually handle the promise unless you have additional client-side actions; simply calling c.server.update() will cause the widget to refresh with new server-side data.

  • No Explicit Return Value Needed: The updated data object is what gets returned. For example, after saving a record, you might update data.statusMessage on the server to indicate success. Once server.update() completes, that statusMessage will be present in c.data for the client to display.

// Client script example: 
c.saveChanges = function() {   
	// Assume c.data.fields has been bound to form inputs for a record   
	c.server.update().then(function() {      
		console.log("Update complete, refreshed data:", c.data);   
	}); 
};
  • In the server script, you would handle the input (which mirrors c.data) to perform the actual update.


When to use server.update(): Use this method for submit or save actions – whenever the user has provided input that needs to be processed on the server. Common use cases include form submissions (creating or updating records), actions like approving/declining a request (where you might set some field or workflow state), or any time you want to send the entire current state back to the server for further processing. Because it sends everything, server.update() is straightforward for forms where many fields might have changed; you don’t have to manually construct an input object, you simply rely on the data binding. However, with this convenience comes the responsibility to ensure that your data object only contains relevant information to avoid sending unnecessary data (more on this in troubleshooting).


Handling Retrieval and Updates in the Same Server Script


In many real-world widgets, you might need to both retrieve data and update data within the same server script, depending on what the client is doing. ServiceNow’s widget framework uses a single server script that runs on initial load and again on any client calls (get/update). So how can you differentiate between a retrieval scenario and an update scenario in one script? The key is the input object.


When a widget loads for the first time (or whenever it runs without a client trigger), there is no input object. But when the client calls c.server.get({...}) or c.server.update(), the server script runs with input available (even if it’s an empty object). You can use this to branch your logic:


  • Initial Load vs Postback: Typically, you check if input exists.

    For example:

// Server script pseudo-code 
(function() {   
	if (input) {      
		// This block runs on a client-triggered call 
		// (either get or update)   
	} else {      
		// This block runs on the initial widget load (no input)   
	} 
})();
  • By using if (input), you ensure code inside that block only runs when the client has sent something (i.e., not on the initial page load).

  • Multiple Actions in One Script: If your widget has more than one type of action (perhaps a "refresh list" button and a "save form" button), you can distinguish them by adding a property in the input object to indicate the action.

    For example, you might set input.action = "refresh" for one call and input.action = "save" for another. In the server script, you can then do:

if (input && input.action == "save") {     
	// perform save logic (update record) 
} else if (input && input.action == "refresh") {     
	// perform data retrieval logic (query records) 
} else {     
	// default logic for initial load or other cases 
}
  • This way, both server.get() and server.update() calls can be handled appropriately. In practice, a server.update() call might not need an explicit action flag if its sole purpose is to save form data, whereas different server.get() calls could use an action or parameters to specify what data to fetch.

  • Avoiding Overlap: It’s important to separate the logic for retrieving data and updating data so they don't interfere. For instance, if you have an if (input) block that updates a record, you may want to put your data retrieval (query) logic in the else (when no input) or in a separate conditional branch. Otherwise, you might accidentally re-query data after you just updated it, or vice versa. A common pattern is:

if (input) {   
	// Update case (e.g., save changes)   
	// ... use input values to update GlideRecord ...   
	current.update();  
	// or gr.update()   
	// set data.message or data.result as needed 
}  
// Retrieve data (run always on initial load, and maybe again after update to get fresh data) 
var gr = new GlideRecord('some_table'); 
if (input && input.sys_id) {   
	// If we have an input sys_id (perhaps from update or passed explicitly), get that record   
	gr.get(input.sys_id); 
} else {   
	// Otherwise, get default data (e.g., initial load scenario or list)   
	gr.get('<some default record or query criteria>'); 
} 
// populate data from gr data.record = {}; 
if (gr.isValidRecord()) {   
	data.record.name = gr.getValue('name');   
	// etc... 
}
  • In the above pseudo-code, the script updates a record if input is present (meaning an update was triggered), then regardless, it proceeds to retrieve data (maybe to show the updated record or to refresh the view). You might choose to run certain retrieval only on else, or on both cases, depending on if you want to refresh the displayed data after an update.


The main idea is to use the presence and properties of input to control flow. If you call server.update(), all of c.data becomes input, so you might have many properties. If you call server.get(obj), then input will contain just what you passed. Designing your server script with clear sections for "if updating" and "if retrieving" will make it easier to manage both in one place.


Step-by-Step Troubleshooting Tips for server.get() and server.update()


Working with these client-server methods can sometimes be tricky. Here are some common issues and troubleshooting steps to resolve them:


  1. Nothing Happens on Button Click: If you call c.server.get() or c.server.update() and nothing seems to occur, first ensure that your client script function is actually being invoked (e.g., your button’s ng-click is wired to the function). Then, make sure you're calling the method on the correct object (this.server or $scope.server in older widget syntax). Using var c = this; at the top of your client script and then c.server.update() is a common practice. If you accidentally call server.update() without the context (c. or $scope.), it won’t work.

  2. input is undefined in Server Script: This indicates that the server script didn’t receive any input, which usually means the client call did not send data. If you used server.update() but input is empty on the server, check that you are modifying the c.data object on the client before calling update. Remember, server.update() sends c.data as input. For example, if you want to send a field value, it should be part of c.data (e.g., c.data.userComment = c.commentModel; c.server.update()). If using server.get() with a custom object, double-check that you passed the object correctly, e.g. c.server.get({id: someId}).

  3. Data Not Refreshing After Call: If you expect new data after a server.get() or server.update() but the widget UI doesn’t show changes, verify that your server script is populating the data object with the information you want to return. Only properties on the data object are sent back to the client. For example, if you perform a GlideRecord query in the server script, you must store the results in data (e.g., data.results = [...]). If you update a record and want to show a status message, set data.message = "Update successful" (and perhaps use that in your widget’s HTML). Failing to put values into data (or modifying only local variables) will result in the client not receiving those values.

  4. Partial Data or Missing Fields on Server: When using server.update(), all of c.data becomes input. If some expected field is missing in input, ensure that field was part of c.data on the client. If it was bound via an ng-model in your widget template, the model must tie to a property of c.data. Also, note that complex objects or functions on c.data might not serialize. Only simple data (strings, numbers, booleans, objects, arrays) are sent. For instance, if c.data had an object with cyclic references or non-JSON data, those might not send properly. Simplify or extract just the needed info into data properties.

  5. Unwanted Data Being Sent: Conversely, sometimes you might notice extra data coming through input when using server.update(), especially if your c.data has many properties (maybe from other parts of the widget). This could lead to performance issues or confusion. Troubleshooting this involves cleaning up c.data before calling update (remove any large lists not needed, or use server.get() with a specific object instead). Keep your data object lean – you can create specific objects to send via server.get() if you only need to transmit a few values.

  6. Server Script Running Twice or Conflicting: If you experience odd behavior like the server script logic executing in an unexpected order, review your if (input) conditions. A common mistake is forgetting to use else and accidentally running both the input-handling code and the default code. Ensure that when input is present, you don’t also execute the initial load logic that might overwrite your results. Proper use of if/else or distinct if checks for different flags can prevent this.

  7. Debugging Tips: Use gs.info() or gs.debug() in your server script to log messages to the server log (accessible via System Logs in ServiceNow) to verify what code path is running and what the values of input or data are. On the client side, you can use console.log to inspect c.data or the response from the promise. These debug statements can be a lifesaver when tracking down why data isn’t flowing as expected.


By following these steps, you can usually pinpoint where things went wrong and fix the script. The key is to methodically check that each part of the chain is doing its job: the client call is made correctly, the server receives the expected input, the server logic updates the data or database, and the results are passed back to the client UI.


Practical Examples and Use Cases


To solidify the concepts, let's look at a couple of practical scenarios where server.get() and server.update() would be used:


  • Example 1: Loading and Updating an Incident Record – Imagine you are building a custom Incident editor widget in Service Portal. When the widget is first added to the page, the Introduction server script (with no input) runs a query to get incident details (say, based on an incident number passed via widget option or URL parameter) and puts those details into the data object (e.g., data.incident = { number: "INC0010001", short_description: "Network issue", ... }). The client controller displays these details in a form. Now, if the user updates some fields and clicks a "Save" button, your client script will copy the modified values into c.data.incident (since the form is likely two-way bound, this might already be done) and call c.server.update(). The server script runs again, this time input.incident contains the updated data. In the server script, you detect if (input && input.incident), then use a GlideRecord to find that incident and update its fields (gr.setValue('short_description', input.incident.short_description) etc., followed by gr.update()). You might also set data.saveSuccess = true or data.message = "Incident updated successfully" in the data. After the server script finishes, the widget refreshes: the form could show a success message and the updated fields (perhaps reflecting any business rule changes that happened on save, if you re-query the record in the server script after saving). Here, server.get() wasn’t explicitly called by the client for initial load – the initial data was loaded by default – but you could also design it such that initial load uses server.get() if triggered by a user action (like selecting an incident from a list).


  • Example 2: Filter and Refresh a List – Consider a widget that shows a list of open tasks. On initial load, the server script (no input) might query open tasks and return a list in data.tasks. The client shows this list in a table. Now, suppose you have a filter dropdown for task priority on the client. When the user selects "High" and clicks a "Filter" button, you can call something like c.server.get({ priority: 'High' }). In the server script, you'll have input.priority == 'High', so you adjust your GlideRecord query to filter by that priority and return the filtered results in data.tasks. This is a read operation, so server.get() is appropriate. The widget will refresh to show only high priority tasks. No database update occurred here. If the widget also allowed editing each task’s state inline, you might use server.update() for the save action of each task after editing, sending the changed state or other fields.


  • Example 3: Multi-step Interaction – Some interactions might involve both methods. For instance, a wizard where step 1 uses server.get() to fetch some data based on user input, and step 2 uses server.update() to save final selections. Because you can use these calls as needed, the widget remains on the same page and provides a smooth UX, fetching and posting data in the background.


These examples highlight a common pattern: use server.get() for getting/fetching data (especially if triggered by a specific user action or needing specific parameters) and use server.update() for saving or sending a broad set of data back to the server. Both methods contribute to a richer user experience in ServiceNow portals by avoiding full page reloads and handling data asynchronously. As a developer, plan out what data you need to retrieve vs. what needs to be saved, and use the appropriate method for each part.


Alternative Approaches and Considerations


While server.get() and server.update() are the standard ways to handle client-server communication in Service Portal widgets, it’s worth noting a few alternative approaches or related methods:


  • server.refresh(): Service Portal also provides a server.refresh() method. This method simply re-runs the server script and refreshes the data without sending any additional input (it’s like telling the server "run again with the last known data"). It can be useful if you want to just refresh the widget’s data as-is (for example, after a record watcher detects a change in the database). Unlike server.get() or server.update(), you’re not explicitly providing new input or using current data – you’re just reloading. In many cases, developers use server.get() or update with a specific flag instead of refresh, but it’s good to know this exists.


  • GlideAjax and Script Includes: Prior to Service Portal (or outside of it, like on regular forms or in Global UI scripts), a common pattern for client-server communication is using GlideAjax calls to script includes. In a scoped widget, you could still use GlideAjax if needed, but server.get()/update() basically abstracts that for you. However, if you have a complex operation, you might create a Script Include (a server-side class with callable methods) and call it within your widget’s server script or via GlideAjax from the client. This is more manual, but sometimes necessary if you want to reuse server logic outside of the widget context.


  • Direct REST API Calls ($http): In some cases, developers might use AngularJS’s $http service within the widget to call a Scripted REST API or other endpoints to get or post data. This bypasses the widget’s built-in server script mechanism. While this can work, it requires handling authentication (in the case of calling your own instance’s APIs, you’d likely use a session token) and is usually more code. The c.server methods are simpler for most widget use cases since they automatically handle the request/response within the platform.


  • UI Actions and Form Submissions: If not using a Service Portal widget, say you are on a normal form in ServiceNow, you wouldn’t use server.update() or server.get(). Instead, you might use UI Actions (which run server-side code on button click) or client scripts with GlideAjax, etc. So context matters: the server. methods exist in the Service Portal widget framework. For ServiceNow developers, it’s important to choose the right method depending on environment: in Service Portal, these are preferred; outside, you have alternatives like GlideAjax or simply saving the form (which triggers Business Rules).


  • Performance Considerations: As an alternative consideration, if your widget is doing very frequent data refresh (like polling for changes), consider using ServiceNow’s Record Watch with $scope.$on('record.updated', ...) and spUtil, which can push updates from server to client. This avoids manually calling server.get() repeatedly. But this is a more advanced real-time update approach beyond the basic get/update methods.


In summary, while server.get() and server.update() are usually the easiest and most direct way to retrieve and update data in a widget, ServiceNow provides other tools depending on your needs. Advanced developers might mix these approaches, but it’s often best to start with the straightforward pattern that these methods offer.


Conclusion


In this article, we explored the difference between server.get() and server.update() in ServiceNow Service Portal server scripts. To recap the key insights:


  • server.get() is used for retrieving data from the server. It allows you to send a custom input object and is ideal for on-demand reads or refreshing data based on user input, without implicitly sending the entire widget state.

  • server.update() is used for sending data to the server (usually to save or update records). It automatically carries the widget’s current data to the server, making it convenient for form submissions or any operation where the user’s input needs to be persisted or processed on the server side.

  • Both methods re-run the widget's server script and update the client view with the results, but they differ in how they pass data and their typical use cases (get vs post/update semantics).

  • When using both in the same script, leverage the input object to distinguish the context (e.g., initial load vs subsequent call, or different actions) to ensure your script executes the right logic at the right time.

  • We also covered common pitfalls and troubleshooting steps – from ensuring your data flows correctly, to debugging tips when things don’t work as expected. Remember that proper handling of the data and input objects on server and client is crucial for success.

  • Alternative methods like GlideAjax or server.refresh() exist, but the server.get()/update() pattern is usually the most straightforward for widget development.


As actionable next steps, ServiceNow developers should practice implementing these methods in a safe development environment. Try creating a simple widget that uses server.get() to filter some records and server.update() to save changes, to reinforce understanding. Always test both the happy path and error conditions (e.g., what if the record isn’t found on get, or the update fails) and handle those in your script (perhaps by setting an error message in data for the client to display).


By mastering server.get() and server.update(), you’ll be able to build more dynamic and responsive ServiceNow applications, providing a better user experience in the Service Portal. Keep the distinctions and best practices discussed here in mind, and you'll implement these methods effectively and confidently in your future development work. Happy coding in ServiceNow!

Experiencing challenges with ServiceNow support?

Access professional, reliable assistance tailored to your needs—without breaking your budget.

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