FSEvents (.fseventsd): macOS File System Change Log
Per-volume gzip logs written by fseventsd that record created, modified, renamed and deleted paths, often the only trace of a removed file.
- Location
- /System/Volumes/Data/.fseventsd/
- Proves
- Which paths were created, changed, renamed or deleted on a volume, in event order
- Timestamps
- None per record; estimate from log file mtime and dated paths
- Access
- root; Full Disk Access on a live system
- Retention
- Rolling, purged by fseventsd (months observed, varies)
- Collection
- UAC, mac_apt, Disk image, ditto
Tools
Compare all toolsWhat it is
The fseventsd daemon keeps a persistent journal of file system changes so that applications (Time Machine, Spotlight, sync clients) can ask "what changed under this folder since event X". Each writable volume it tracks gets a hidden .fseventsd folder holding gzip-compressed log files. Each record is a path, a 64-bit event ID and a flag mask, and newer formats add a node ID.
For an investigator this is a path-level history of the volume: files that were created and deleted in /private/tmp, an archive that briefly existed in ~/Downloads, a LaunchAgent plist that was written and later removed, or the contents of a USB stick. The in-depth FSEvents guide covers the format in detail; this page is the quick reference.
Where it lives
| macOS | Path | Notes |
|---|---|---|
| 10.15 Catalina and later | /System/Volumes/Data/.fseventsd/ | The Data volume holds user activity; paths inside are relative to the Data volume root |
| 10.14 and earlier | /.fseventsd/ | Single boot volume |
| Any, external or removable volume | /Volumes/<name>/.fseventsd/ | Travels with the drive |
Inside the folder:
- Log files with 16-digit hexadecimal names derived from event IDs, so they sort in event order.
fseventsd-uuid: identifies the event stream for that volume. A new UUID means the history was reset.no_log(optional): an empty file that tellsfseventsdnot to log the volume.
Protection: the folder is root-owned. On a live system the collecting process also needs Full Disk Access. mac_apt additionally checks /private/var/db/fseventsd as an alternative location.
What it proves
- A file or folder with a given name existed at a path on that volume, even after deletion.
- The kind of change: created, modified, renamed or moved, removed, permissions or ownership changed, extended attribute added or removed (for example
com.apple.quarantinebeing stripped). - The relative order of changes on a volume (event IDs increase monotonically).
- That a removable volume was written on a Mac, and which paths were touched on it.
It does not prove:
- An exact time. Records carry no timestamp.
- Which user or process made the change.
- File content. Pair it with APFS snapshots, Time Machine or carving.
- Activity on read-only mounts or network shares, which are not logged.
Key fields
| Field | Meaning |
|---|---|
Page magic 1SLD | Version 1 page: path, event ID (8 bytes), flags (4 bytes) |
Page magic 2SLD | Version 2 page (macOS 10.13 High Sierra onward): adds node ID (8 bytes) |
Page magic 3SLD | Version 3 page (macOS 14 Sonoma onward): adds a further 4-byte field, decoded as a user ID (fs_uid) by FSEventsParser and left as unknown by mac_apt |
| Path | Null-terminated path relative to the volume root, as it was when logged |
| Event ID | 64-bit counter per volume; ordering only |
| Flags | Bitmask of change type and object type |
| Node ID | File system object ID (on APFS, the inode number); links a file across renames |
Common flag names reported by parsers: Created, Removed, Renamed (mac_apt: RenamedOrMoved), Modified, InodeMetaMod, PermissionChange, ExtendedAttrModified / ExtendedAttrRemoved (mac_apt: XAttrModified / XAttrRemoved), FinderInfoMod, FolderCreated, Exchange, ItemCloned, LastHardLinkRemoved, Mount, Unmount, EndOfTransaction, plus object types such as FileEvent, FolderEvent, SymbolicLink, HardLink. The on-disk bit values differ from Apple's public FSEventStreamEventFlags API constants, so trust a parser that decodes the on-disk layout.
Timestamps
There are none inside records. Estimate time from:
- Log file modification time. A file is written when
fseventsdflushes, so its mtime is an upper bound for its records and the previous file's mtime is a rough lower bound. - Dated paths. Paths with dates in their names (rotated logs, snapshot names, diagnostic reports) appearing as
Createdanchor nearby event IDs. FSEventsParser uses this to fill itsapprox_dates_plus_minus_one_daycolumn. - Correlation. A real timestamp from another artifact for one path (APFS birth time, a quarantine event, a Unified Log entry) dates its neighbours.
Always report FSEvents times as a range and name the anchor used.
Retention
No fixed period. fseventsd purges older log files on its own, and history depends on volume activity and space. CrowdStrike has reported events around four months old on typical systems; busy volumes may keep much less. A changed fseventsd-uuid or a volume reformat starts a new history. Collect early and preserve file mtimes.
Collection
Copy the entire folder and keep modification times (they are your only clock):
# Live, as root, from a terminal with Full Disk Access
sudo ditto /System/Volumes/Data/.fseventsd /Volumes/CASE/MBP01/fseventsd
sudo ls -lT /System/Volumes/Data/.fseventsd > /Volumes/CASE/MBP01/fseventsd_listing.txt
- UAC: the
ir_triageandfullprofiles include thefiles/logs/macos.yamlartifact, which collects/.fseventsdand/System/Volumes/*/.fseventsd. - mac_apt: the
FSEVENTSplugin reads the folder directly from an E01, DMG, raw or mounted image. - Aftermath: not collected by default; add the folder with
--collect-dirs. - Removable media: image the drive or copy its
.fseventsdwith the same care.
Parsing
FSEventsParser (handles 1SLD, 2SLD and 3SLD) writes a SQLite database plus TSV reports:
python3 FSEParser_V4.1.py -s /cases/MBP01/fseventsd -t folder -o /cases/MBP01/out -c MBP01
-- FSEventsParser schema: deleted items under a user's Downloads
SELECT id_hex, fullpath, type, flags, approx_dates_plus_minus_one_day, source, source_modified_time
FROM fsevents_sorted_by_event_id
WHERE fullpath LIKE 'Users/%/Downloads/%' AND flags LIKE '%Removed;%'
ORDER BY id;
mac_apt parses the same data from an image, with a SourceModDate column for each record:
python3 mac_apt.py -o /cases/MBP01/mac_apt E01 /cases/MBP01.E01 FSEVENTS
FSEvents Parser decodes a .fseventsd folder (or a UAC, Aftermath or Velociraptor collection) in the browser, with decoded flags, time windows, rename pairs and CSV or Timesketch export; nothing is uploaded.
Investigator tips
- Pair
Renamedrecords by node ID (version 2 and later) to follow a file through renames and moves. ExtendedAttrRemovedon a freshly downloaded app bundle can mean the quarantine attribute was stripped. Check quarantine events.- Watch
Library/LaunchAgentsandLibrary/LaunchDaemonspaths for short-lived persistence; see launch agents and daemons. - A
no_logfile or a recentfseventsd-uuidcan be deliberate anti-forensics, or just a volume formatted elsewhere. Check the Unified Logs and APFS timestamps of those files. - On the internal Data volume, new
Volumes/<name>paths show a volume was mounted. Combine with the drive's own.fseventsdand USB device evidence. - Coalescing: one record can combine
Created;Modified;Removed. You cannot recover the exact order inside a single record. - Parsed output easily exceeds a million rows. Filter by path first (
Users/*/Downloads,private/tmp,Users/Shared,Library/LaunchAgents), then widen. - Deduplicate before reporting: FSEventsParser does not deduplicate, and carved gzip files can repeat records.