Built something you're proud of? Tell the story. A quick G2 review of App Engine or Build Agent helps other developers see what's possible on ServiceNow. Share your experience.

Remove Values from History of a ticket once it has been closed

jonathangilbert
Mega Sage

HI All,

As part of our GDPR requirements it has been requested that information is removed form a ticket once the ticket has been closed. I have been able to overwrite Variables and field associated to a RITM and Ince, but I am having issues removing that data from the History of the ticket.

I have seen articles that advise to clear sys_history_line entries and then delete the sys_entry_set record, but as soon as I refresh the record, the data gets populated again. I appreciate that only admins can see the history, but as I said it has been asked that no Sensative details should remain linked to a ticket

 

Has anyone achived this scenrio before or ideas on how to accompish this. Thank you in adavnce

1 ACCEPTED SOLUTION

Naveen20
ServiceNow Employee

 The reason the history keeps repopulating after you clear sys_history_line is that the Activity Stream formatter regenerates those entries from the underlying audit table. You need to tackle multiple tables in the right order.

Tables - 

There are several places where field-level history persists beyond just the current record values:

sys_audit — This is the primary source of truth. The Activity formatter and History related list both pull from here. If you only delete sys_history_line but leave sys_audit intact, the platform rebuilds the history on the next page load.

sys_history_line — A denormalized/cache table that the History formatter reads. Deleting these alone won't stick because they regenerate from sys_audit.

sys_journal_field — Stores Comments, Work Notes, and other journal-type entries. These are separate from audit records and must be handled independently.

sys_audit_delete — If auditing of deletions is enabled, your cleanup operations themselves may leave traces here.

The Correct Deletion Sequence

The order matters. Here's the approach that should prevent repopulation:

Step 1 — Delete sys_audit records first

var ga = new GlideRecord('sys_audit');
ga.addQuery('documentkey', ritmSysId);
ga.addQuery('tablename', 'sc_req_item');
ga.deleteMultiple();

Step 2 — Then delete sys_history_line

var gh = new GlideRecord('sys_history_line');
gh.addQuery('set.id', ritmSysId);
gh.addQuery('set.table', 'sc_req_item');
gh.deleteMultiple();

Step 3 — Delete the sys_history_set parent records

var gs = new GlideRecord('sys_history_set');
gs.addQuery('id', ritmSysId);
gs.addQuery('table', 'sc_req_item');
gs.deleteMultiple();

Step 4 — Clear journal fields (comments/work notes)

var gj = new GlideRecord('sys_journal_field');
gj.addQuery('element_id', ritmSysId);
gj.addQuery('name', 'sc_req_item');
gj.deleteMultiple();

Step 5 — Optionally handle sys_audit_delete if your instance audits deletion events, since your cleanup itself creates audit trails.

Why It Was Repopulating

The regeneration you observed happens because ServiceNow's Activity formatter calls a processor that checks sys_audit and rebuilds sys_history_line if records are missing but audit entries still exist. By deleting sys_audit first, there's nothing left to regenerate from.

Additional Considerations

A few things worth keeping in mind for a production implementation:

Variable history lives in sc_item_option and sc_item_option_mtom for catalog variables, but you mentioned you've already handled those. Make sure you're also checking sys_audit entries where tablename = 'sc_item_option_mtom', since variable value changes are audited separately.

Attachments — if tickets have file attachments containing sensitive data, you'll want to clean sys_attachment and sys_attachment_doc as well.

Emails — inbound/outbound emails linked to the ticket in sys_email may also contain PII.

Automation approach — most teams implement this as a Scheduled Job or a Business Rule on state change to "Closed" (with an appropriate delay, e.g., 30 days after closure). A Flow Designer flow with a "Wait for Duration" step after closure works well too, and gives you better visibility into execution.

View solution in original post

2 REPLIES 2

Naveen20
ServiceNow Employee

 The reason the history keeps repopulating after you clear sys_history_line is that the Activity Stream formatter regenerates those entries from the underlying audit table. You need to tackle multiple tables in the right order.

Tables - 

There are several places where field-level history persists beyond just the current record values:

sys_audit — This is the primary source of truth. The Activity formatter and History related list both pull from here. If you only delete sys_history_line but leave sys_audit intact, the platform rebuilds the history on the next page load.

sys_history_line — A denormalized/cache table that the History formatter reads. Deleting these alone won't stick because they regenerate from sys_audit.

sys_journal_field — Stores Comments, Work Notes, and other journal-type entries. These are separate from audit records and must be handled independently.

sys_audit_delete — If auditing of deletions is enabled, your cleanup operations themselves may leave traces here.

The Correct Deletion Sequence

The order matters. Here's the approach that should prevent repopulation:

Step 1 — Delete sys_audit records first

var ga = new GlideRecord('sys_audit');
ga.addQuery('documentkey', ritmSysId);
ga.addQuery('tablename', 'sc_req_item');
ga.deleteMultiple();

Step 2 — Then delete sys_history_line

var gh = new GlideRecord('sys_history_line');
gh.addQuery('set.id', ritmSysId);
gh.addQuery('set.table', 'sc_req_item');
gh.deleteMultiple();

Step 3 — Delete the sys_history_set parent records

var gs = new GlideRecord('sys_history_set');
gs.addQuery('id', ritmSysId);
gs.addQuery('table', 'sc_req_item');
gs.deleteMultiple();

Step 4 — Clear journal fields (comments/work notes)

var gj = new GlideRecord('sys_journal_field');
gj.addQuery('element_id', ritmSysId);
gj.addQuery('name', 'sc_req_item');
gj.deleteMultiple();

Step 5 — Optionally handle sys_audit_delete if your instance audits deletion events, since your cleanup itself creates audit trails.

Why It Was Repopulating

The regeneration you observed happens because ServiceNow's Activity formatter calls a processor that checks sys_audit and rebuilds sys_history_line if records are missing but audit entries still exist. By deleting sys_audit first, there's nothing left to regenerate from.

Additional Considerations

A few things worth keeping in mind for a production implementation:

Variable history lives in sc_item_option and sc_item_option_mtom for catalog variables, but you mentioned you've already handled those. Make sure you're also checking sys_audit entries where tablename = 'sc_item_option_mtom', since variable value changes are audited separately.

Attachments — if tickets have file attachments containing sensitive data, you'll want to clean sys_attachment and sys_attachment_doc as well.

Emails — inbound/outbound emails linked to the ticket in sys_email may also contain PII.

Automation approach — most teams implement this as a Scheduled Job or a Business Rule on state change to "Closed" (with an appropriate delay, e.g., 30 days after closure). A Flow Designer flow with a "Wait for Duration" step after closure works well too, and gives you better visibility into execution.

jonathangilbert
Mega Sage

Hi Naveen,

Sorry for the delayed response, thankyou so much for this detailed resolution 🙂