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 REPLY 1

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.