- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
How to Get Previous Field Value Outside a Business Rule in ServiceNow
Many times we get requirements to retrieve a record's previous field value — to trigger logic based on what changed, build a revert button, or process records in a scheduled job. Most developers instinctively reach for Business Rules (where the previous object is available), but what if that's not an option?
Many developers query the sys_audit table directly to get previous values. This is bad practice — sys_audit is one of the largest tables in any instance and direct queries can severely impact your instance's performance.
The good news? ServiceNow has a dedicated, officially supported API for exactly this: the HistoryWalker API. It works in both scoped and global applications.
The HistoryWalker API uses the audit/history tables to generate a historical version of an existing record — populating all field values as they existed at any point in the record's lifetime, without touching sys_audit directly.
snapshot
Instantiate via sn_hw.HistoryWalker. Always pass the walker type explicitly for predictable behaviour:
// Basic — uses system property default walker
var hw = new sn_hw.HistoryWalker('incident', current.getUniqueValue());
// Recommended — specify walker explicitly
var hw = new sn_hw.HistoryWalker(
'incident',
current.getUniqueValue(),
'CHECKPOINT' // AUDIT | CHECKPOINT | HISTORY | OFFLINE
);sys_history_set for low-update records, falls back to sys_audit for high-update ones. Chronologically accurate.sys_history_set. Good for most cases but can timeout for 10K+ update records.sys_audit directly. Least performant. Edge cases around glide.sys.audit_inserts.walkTo(0) and walkForward() are usable.com.snc.walker.default controls the default walker. New customers default to CHECKPOINT; upgraded customers default to HISTORY. Always specify explicitly in your code.
| Method | Description |
|---|---|
| walkTo(n) | Walk the record to a specific update number. Use 0 for initial state. |
| walkForward() | Move to the next update in chronological order. Returns true if successful. |
| walkBackward() | Move to the previous update. Returns true if successful. |
| getWalkedRecord() | Returns the GlideRecord at the current walked state. |
| getWalkedRecordCopy() | Returns a safe copy of the walked GlideRecord (recommended). |
| setAclEnabled(bool) | Toggle row-level ACL enforcement on/off. |
| setFieldAclEnabled(bool) | Toggle field-level ACL enforcement on/off. |
| setJournalFieldsEnabled(bool) | Enable retrieval of journal field history. |
Example 1 — Get previous field value in a Scheduled Job or Script Include
var gr = new GlideRecord('incident');
gr.get('your-sys-id-here');
var hw = new sn_hw.HistoryWalker(
gr.getTableName(),
gr.getUniqueValue(),
'CHECKPOINT'
);
// Walk to one update before the current state
hw.walkTo(gr.sys_mod_count - 1);
var prev = hw.getWalkedRecord();
gs.info('Previous state: ' + prev.state.getDisplayValue());
gs.info('Current state : ' + gr.state.getDisplayValue());Example 2 — Revert a record to its previous state
var hw = new sn_hw.HistoryWalker(
current.getTableName(),
current.getUniqueValue(),
'CHECKPOINT'
);
hw.setAclEnabled(false); // system-level revert
hw.walkTo(current.sys_mod_count - 1);
var prev = hw.getWalkedRecord();
current.state = prev.state;
current.assignment_group = prev.assignment_group;
current.assigned_to = prev.assigned_to;
current.update();
gs.info('Record reverted successfully.');Example 3 — Navigate the full history of a record
var hw = new sn_hw.HistoryWalker('incident', sysId, 'CHECKPOINT');
hw.walkTo(0); // start from the very beginning
do {
var rec = hw.getWalkedRecord();
gs.info(
'Update: ' + rec.sys_mod_count +
' | State: ' + rec.state.getDisplayValue() +
' | Assigned: ' + rec.assigned_to.getDisplayValue()
);
} while (hw.walkForward());- Always specify the walker type explicitly — never rely on the system property default
- Prefer CHECKPOINT for all new development — most accurate and performant
- Never query sys_audit directly — always use HistoryWalker
- Use
getWalkedRecordCopy()when comparing values to avoid mutation risks - For records with >1,000 updates, CHECKPOINT auto-switches to sys_audit — this is expected
- Available in both global and scoped apps via the
sn_hwnamespace - Only disable ACLs (
setAclEnabled(false)) in trusted background processes
The HistoryWalker API is documented in the ServiceNow Developer Portal under Server-side scripting APIs → HistoryWalker. Always verify against your specific release version.
Have you used the HistoryWalker API in your projects? Share your use case or questions in the comments — the ServiceNow community loves real-world stories!
- 175 Views
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
