Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# AuditFieldChangeNotifier
### Description
A ServiceNow Script Include that audits changes to specific fields and sends real-time notifications to Slack or Microsoft Teams using a webhook.
It helps teams monitor important updates like priority or assignment changes without needing to check the platform.
---
### 🔧 Features
- Monitors field-level changes on any table
- Sends rich notifications to Slack/Teams
- Easy to configure via system properties
- Can be reused across multiple tables via Business Rules
---
### 🧩 How to Use
1. **Create a System Property**
- Name: `x_custom.audit_notifier.webhook_url`
- Value: Your Slack or Teams webhook URL
2. **Create a Script Include**
- Name: `AuditFieldChangeNotifier`
- Paste the provided Script Include code
3. **Create a Business Rule**
- Table: e.g. `incident`
- When: `after update`
- Add this script:
```js
(function executeRule(current, previous) {
var notifier = new AuditFieldChangeNotifier();
notifier.notifyOnFieldChange(current, previous, ['priority', 'state', 'assigned_to']);
})(current, previous);
```
4. **Test It**
- Update one of the watched fields.
- A message should appear in your Slack/Teams channel like:
```
🛠️ ServiceNow — Field Update Notification
Record: Incident INC0010001
Description: Unable to access VPN
• priority changed from 4 - Low → 2 - High
• assigned_to changed from John → Alex
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Script Include: AuditFieldChangeNotifier
* Description: Sends Slack/Teams notifications when specific fields change on configured tables.
* Usable in: Business Rule (after update)
*/
var AuditFieldChangeNotifier = Class.create();
AuditFieldChangeNotifier.prototype = {
initialize: function () {
// Slack or Teams webhook URL (store in sys_properties for security)
this.webhookUrl = gs.getProperty('x_custom.audit_notifier.webhook_url', '');
// Default app name
this.appName = gs.getProperty('x_custom.audit_notifier.app_name', 'ServiceNow');
},
/**
* Send notification if the specified fields have changed
* @param {GlideRecord} current - Current record
* @param {GlideRecord} previous - Previous record
* @param {Array} fieldsToWatch - Array of field names to monitor
*/
notifyOnFieldChange: function (current, previous, fieldsToWatch) {
try {
if (!this.webhookUrl) {
gs.warn('[AuditFieldChangeNotifier] Webhook URL not configured.');
return;
}
var changes = [];
fieldsToWatch.forEach(function (field) {
if (current[field] + '' !== previous[field] + '') {
changes.push({
field: field,
oldValue: previous[field] + '',
newValue: current[field] + ''
});
}
});
if (changes.length === 0)
return; // No relevant field changed
var payload = this._buildPayload(current, changes);
this._sendWebhook(payload);
} catch (e) {
gs.error('[AuditFieldChangeNotifier] Error: ' + e.message);
}
},
/**
* Build payload for Slack/Teams message
*/
_buildPayload: function (current, changes) {
var shortDesc = current.short_description ? current.short_description + '' : '(No short description)';
var tableName = current.getTableName();
var recordUrl = gs.getProperty('glide.servlet.uri') + tableName + '.do?sys_id=' + current.sys_id;
var changeLines = changes.map(function (c) {
return `• *${c.field}* changed from _${c.oldValue}_ → *${c.newValue}*`;
}).join('\n');
return JSON.stringify({
text: `🛠️ *${this.appName}* — Field Update Notification\n\n*Record:* <${recordUrl}|${tableName}> \n*Description:* ${shortDesc}\n\n${changeLines}\n\n_Updated by ${gs.getUserDisplayName()}_`
});
},
/**
* Send payload to webhook
*/
_sendWebhook: function (payload) {
var r = new sn_ws.RESTMessageV2();
r.setEndpoint(this.webhookUrl);
r.setHttpMethod('POST');
r.setRequestHeader('Content-Type', 'application/json');
r.setRequestBody(payload);
var response = r.execute();
if (response.getStatusCode() >= 400)
gs.error('[AuditFieldChangeNotifier] Webhook error: ' + response.getBody());
},
type: 'AuditFieldChangeNotifier'
};
Loading