Expert guide
How to Track Who Changed What in Excel and Access
Audit logging for accountability—who changed which value, and when
Call us at +1 (385) 386-3860
Quick answer: create a dedicated audit store (Access table or Excel sheet), write a small VBA routine that records who, what, when, old value, and new value, then call that routine from form or worksheet change events. Protect the audit store and the VBA project so users cannot quietly clear history. For business-critical files, a fixed-scope Access consultant or Excel consultant can design logging that matches your risk—not a one-size DIY script.
Tracking who changed what is how you settle arguments about pricing edits, status flips, and “I never touched that record.” This tutorial shows practical audit logging patterns in Microsoft Access and Excel so you keep a usable history of inserts, updates, and deletes.
What an Effective Audit Log Must Capture
At minimum, each log row should answer:
Who
User identification (Windows login, app user ID, or credentials).
What
Which record, field, or cell was changed.
When
Timestamp of the change (date and time).
Old Value
The previous value before the change.
New Value
The new value after the change.
Action Type
Insert, Update, or Delete.
Part 1: Audit Logging in Access
Step 1: Create an Audit Table
Create a table to store audit log entries:
Create New Table
Create → Table Design.
Add Fields
AuditID (AutoNumber, Primary Key), TableName (Text, 50), RecordID (Text, 50), FieldName (Text, 50), OldValue (Long Text), NewValue (Long Text), UserName (Text, 50), ChangeDate (Date/Time), ActionType (Text, 10).
Set Defaults
Set ChangeDate default to Now() so new rows get a timestamp.
Save Table
Save as tblAuditLog (or a clear name your team will recognize).
Step 2: Create an Audit Function
Press Alt+F11, insert a new module, and add a function that writes one audit row. Example shape:
Function WriteAuditLog(TableName As String, RecordID As String, FieldName As String, OldValue As Variant, NewValue As Variant, ActionType As String)
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("tblAuditLog", dbOpenDynaset)
rs.AddNew
rs!TableName = TableName
rs!RecordID = RecordID
rs!FieldName = FieldName
rs!OldValue = OldValue
rs!NewValue = NewValue
rs!UserName = Environ("USERNAME")
rs!ChangeDate = Now()
rs!ActionType = ActionType
rs.Update
rs.Close
Set rs = Nothing
Set db = Nothing
End Function
Step 3: Call Audit Code From Forms
Prefer form events over table datasheet edits. Open the form in Design View and wire BeforeUpdate, BeforeInsert, and delete confirm events. Production Access forms are the right place to enforce logging because you control how people change data.
BeforeUpdate
Compare control values to OldValue and log field-level updates.
BeforeInsert
Log new record creation.
BeforeDelConfirm / delete handlers
Log the record identity before it disappears.
Example BeforeUpdate sketch:
Private Sub Form_BeforeUpdate(Cancel As Integer)
Dim ctl As Control
For Each ctl In Me.Controls
If ctl.ControlType = acTextBox Or ctl.ControlType = acComboBox Then
If Nz(ctl.Value) <> Nz(ctl.OldValue) Then
WriteAuditLog Me.RecordSource, Me!ID, ctl.Name, ctl.OldValue, ctl.Value, "UPDATE"
End If
End If
Next ctl
End Sub
Step 4: Protect the Audit Table
Hide from users
Hide tblAuditLog in Navigation Options.
Limit write paths
Staff should change data through forms, not by opening tables.
Protect VBA
Password-protect the VBA project so audit calls are harder to remove.
Part 2: Audit Logging in Excel
Step 1: Create an Audit Log Worksheet
Add New Sheet
Insert a sheet named AuditLog.
Create Headers
Row 1: Timestamp, User, Sheet, Cell, OldValue, NewValue, Action.
Hide Sheet
Right-click the sheet tab → Hide.
Protect Sheet
Review → Protect Sheet so casual edits cannot wipe history.
Step 2: Create a VBA Write Routine
Press Alt+F11, insert a module, and append one row per change:
Sub WriteExcelAuditLog(SheetName As String, CellAddress As String, OldValue As Variant, NewValue As Variant)
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("AuditLog")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1
ws.Cells(LastRow, 1) = Now()
ws.Cells(LastRow, 2) = Environ("USERNAME")
ws.Cells(LastRow, 3) = SheetName
ws.Cells(LastRow, 4) = CellAddress
ws.Cells(LastRow, 5) = OldValue
ws.Cells(LastRow, 6) = NewValue
ws.Cells(LastRow, 7) = "UPDATE"
End Sub
Step 3: Hook Worksheet_Change Carefully
Right-click the data sheet tab → View Code. Capture old values carefully: naive Undo patterns can recurse or fail on multi-cell edits. Start with single-cell ranges, disable events while you write the log, and re-enable them in an error handler.
Step 4: Protect Workbook Structure and VBA
Protect VBA Project
Tools → VBAProject Properties → Protection → Lock project for viewing.
Protect Workbook Structure
Review → Protect Workbook → Structure to block sheet deletion.
Protect Worksheets
Protect data sheets while allowing the edits your process needs.
Part 3: Accountability Features Worth Adding
Stronger User Identity
Environ("USERNAME") is a start. Shared Windows accounts and unlocked sessions blur history. For stronger accountability, store an application login or network identity in a session variable and write that value into every audit row.
Track Deletes in Access
Log the record key in a delete confirm handler before the row is gone. Capture enough field context that a reviewer can understand what was removed.
When Excel Logging Is Not Enough
Shared network workbooks, frequent multi-cell pastes, and people who disable macros will defeat sheet-based logs. Move critical data to Access or SQL Server with form-based entry, or ask an Excel consultant to redesign the control surface instead of bolting more VBA onto a fragile file.
Part 4: Querying and Reporting Audit Logs
Access: Filterable Audit Query
Create Query
Create → Query Design.
Add tblAuditLog
Select the fields reviewers need.
Add Criteria
Filter by user, date range, table name, or action type.
Optional report
Build a printable report for reviews or handoffs.
Excel: Pivot the Audit Sheet
Pivot Table
Summarize counts by user, sheet, or day.
Filters
Let reviewers narrow to a person or date window.
Archive
Move old rows to a separate workbook so the live log stays small.
Part 5: Keep the Log Trustworthy
Separate store when risk is high
Put audit rows in a locked Access backend or SQL Server table users cannot edit.
Backups
Include the audit store in the same backup routine as the live data.
Retention
Decide how long history must stay available for your industry and contracts—do not invent a retention rule you cannot keep.
Access to the log
Limit who can read audit history; curiosity browsing is not a review process.
Troubleshooting
Changes Are Not Logged
Confirm macros are enabled, event procedure names match Access/Excel expectations, the audit table or sheet exists, and WriteAuditLog runs when called alone from the Immediate window.
The File Got Slow
Index UserName and ChangeDate in Access, archive old rows, and avoid logging every keystroke-level noise. Log field saves, not intermediate typing.
Users Bypass the Log
They edited tables directly, broke VBA protection, or opened a copy without macros. Close direct table access, protect VBA, and treat macro-free copies as out of process.
Need Audit Logging Designed for Your Risk Level?
Excel Access Expert implements fixed-scope audit trails in Access and Excel for teams that need clear accountability—not generic security theater. For Access event-driven logging, see Access VBA macros development, or start with an MS Excel consultant review when the workbook already runs the business and a DIY log would be easy to disable.
FAQ
Excel & Access audit log FAQ
Accountability questions teams ask before they ship logging
Need a Fixed-Scope Audit Trail?
We design Access and Excel logging that fits how your team actually works—form events, protected stores, and review queries. You get a written scope and fixed price before billable work.
Request a written estimate →