BLOG - Auditing Record Field Changes

TausifAhmedS
Tera Contributor

 

Tracking record changes is essential for maintaining transparency, audit readiness, and operational control in ServiceNow. Although the Activity Formatter helps track field updates, it requires manually reviewing each record, which can be time-consuming when monitoring multiple changes.

 

Implementing proactive notifications or centralized tracking improves visibility, enhances audit efficiency, and ensures that critical user and group record updates are quickly communicated to the right stakeholders.

 

The sys_audit table in ServiceNow stores audit history for record updates across the platform. While it provides complete tracking of field-level changes, it can become cluttered since it captures both relevant and non-relevant modifications. This makes it difficult to quickly identify meaningful changes, especially when monitoring specific records such as users or groups.

 

Use Case: Proactive Visibility of User & Group Record Changes

User and group record changes directly impact access control, security, and governance. Relying on manual audits to track these changes can lead to delays and oversight risks.

 

Real-time notifications provide instant visibility into administrative updates, improving accountability, compliance, and operational transparency.

To implement this solution, we focus on two primary tables where most administrative changes occur:

  • User Table – sys_user

  • Group Table – sys_user_group

To track field-level modifications and notify stakeholders, the approach is as follows:

 

User Details:

Event : 

  • Create a Event for User Details Update (for example : kap.user.contact.update). 
  • To create a event navigate to All > Platform Analytics Administration > Data Collector > Event Registry.  
  • Select the Table : User[sys_user]

Business Rule :

  • Create a Before Business Rule.
  • To create business rule navigate to All > System Definition > Business Rule.
  • Select table as 'User[sys_user]'.

Screenshot 2026-02-05 at 7.14.42 PM.png

 

 Here, the Business Rule is configured to trigger only for selected fields instead of monitoring all fields. Certain fields, such as Last Login, are updated frequently during normal system usage and do not require governance-level tracking. Monitoring such fields would generate unnecessary notifications.

 

    var gru = GlideScriptRecordUtil.get(current);
    var changedFields = gru.getChangedFieldNames(); // Java List
    gs.info(changedFields);
    // Convert Java List to JS Array
    gs.include('j2js');
    changedFields = j2js(changedFields);
    gs.info(changedFields);

    // Fields you want to track
    var allowedFields = [
        'user_name',
        'email',
        'first_name',
        'last_name',
        'department',
        'manager',
        'active',
        'locked_out',
        'password_needs_reset',
        'location'
    ];

    // Filter only allowed + changed fields
    var finalFields = [];

    for (var i = 0; i < changedFields.length; i++) {
        if (allowedFields.indexOf(changedFields[i]) > -1) {
            finalFields.push(changedFields[i]);
        }
    }
    var table = "user";

    // Build parm2 JSON
    var payload = {
        type: table,
        updatedBy: gs.getUserDisplayName(),
    };

    // Send event only if relevant fields changed
    if (finalFields.length > 0) {
        gs.eventQueue(
            "kap.user.contact.update",
            current,
            finalFields, // parm1
            JSON.stringify(payload) // parm2 (JSON)
        );
    }

This implementation leverages GlideScriptRecordUtil to dynamically detect modified fields, eliminating the need to manually check each field using hardcoded conditions. The getChangedFieldNames() method returns the list of updated fields as a Java List, which cannot be directly handled using standard JavaScript operations. To address this, the j2js utility is used to convert the Java List into a JavaScript array, enabling easy iteration and filtering. This approach improves performance, avoids repetitive current.<field>.changes() checks, and results in a more scalable and maintainable change-tracking solution. The detected field changes are then passed as event parameters and rendered dynamically within the email script.

 

Screenshot 2026-02-05 at 7.26.36 PM.png

 Here, the above info message logs defines the use of the j2js utility as you can find the without j2js its Java Array and after use of j2js we get javascript parsable array.

 

 

Email Script : 

  • Create a Email Script.
  • To create email script navigate to All > System Notification > Email > Notification Email Scripts.
    if (!event || !event.parm1 || !event.parm2) {
        template.print("Update details are unavailable.");
        return;
    }

    var fields = event.parm1.split(',');
    var data = JSON.parse(event.parm2);

    var subject = data.type === "user" ?
        "User Details Updated: " + current.name :
        "Group Details Updated: " + current.name;

    var bodyStart = data.type === "user" ?
        "user/contact" :
        "group";

    email.setSubject(subject);

    template.print(
        '<p>This is to inform you that updates have been made to the ' +
        bodyStart + ' <b>' + current.name +
        '</b>. Please find the details below:</p>'
    );

    template.print('<p>');
    for (var i = 0; i < fields.length; i++) {
        var field = fields[i];

        if (!current.isValidField(field)) {
            continue;
        }

        var fieldLabel = current[field].getLabel();
        var fieldVal = current[field].getDisplayValue();

        template.print(
            '<b>' + fieldLabel + ':</b> ' + fieldVal + '<br/>'
        );
    }

    template.print(
        '<b>Updated By:</b> ' + data.updatedBy
    );
    template.print('</p>');

Here, I am using the same email script to both the user and group notifications as in the parm 2 i am sending the table name so modify the content accordingly.

 

Notification :

  • Create a Notification
  • To create a notification navigate to All > System Notification > Email > Notifications.

Screenshot 2026-02-05 at 7.17.49 PM.png 

 

Screenshot 2026-02-05 at 3.53.29 PM.png

 User Details Update Notification

 

Group Details :

Event : 

  • Create a Event for User Details Update (for example : kap.group.details.update). 
  • Select the Table : Group[sys_user_group]

Business Rule :

  • Create a Before Business Rule.
  • Select table as 'Group[sys_user_group]'.

Screenshot 2026-02-05 at 11.21.39 PM.png  

 

    var gru = GlideScriptRecordUtil.get(current);
    var changedFields = gru.getChangedFieldNames(); // Java List

    // Convert Java List to JS Array
    gs.include('j2js');
    changedFields = j2js(changedFields);

    // Fields you want to track
    var allowedFields = [
        'name',
        'email',
        'manager',
        'active'
    ];

    // Filter only allowed + changed fields
    var finalFields = [];

    for (var i = 0; i < changedFields.length; i++) {
        if (allowedFields.indexOf(changedFields[i]) > -1) {
            finalFields.push(changedFields[i]);
        }
    }
    var table = "group";
    
    // Build parm2 JSON
    var payload = {
        type: table,
        updatedBy: gs.getUserDisplayName(),
    };

    // Send event only if relevant fields changed
    if (finalFields.length > 0) {
        gs.eventQueue(
            "kap.group.details.update",
            current,
            finalFields, // parm1
            JSON.stringify(payload) // parm2 (JSON)
        );
    }

 

 

Email Script : 

  • Create a Email Script, if you need. As I am using the same email script for both.

 

Notification :

  • Create a Notification.

Screenshot 2026-02-05 at 7.17.18 PM.png

 

 

 

Screenshot 2026-02-05 at 7.09.35 PM.png

 Group Details Update Notification

 

Note: This implementation is not limited to user and group records. The same approach can be extended to other tables where field-level change tracking and notification visibility are required.

This article helped me a lot: Click Here 👈

 

If you found this Blog helpful, please mark it as Helpful 👍.

 

Regards,

Tausif

0 REPLIES 0