The three ways to uninstall a Mac app, and what each leaves behind

Drag it to the Trash. Built in, free, and it removes the bundle. It removes nothing the app wrote outside itself: preferences, caches, containers, saved state, launch agents, installer receipts, and the entries under Privacy & Security in System Settings. Those last ones macOS gives you no button for. tccutil, the tool that clears them, resolves an app through LaunchServices, so once the bundle is in the Trash it answers "No such bundle identifier" and the grants sit in the permissions database forever. That is why apps you deleted last year are still listed under Accessibility.

The vendor's own uninstaller. When one ships - Adobe, Microsoft, most VPN clients - it is the right answer, because the vendor knows where it put things. Most apps ship none.

A dedicated uninstaller. AppCleaner has done this for free for years and is enough if what you want is the bundle plus the obvious ~/Library folders; Pearcleaner is the open-source take. Unroot is built around a narrower question: not what can we find, but what can we prove, and what can we put back. Everything below is in the shipping version.

Where it looks, and why every row says why

A scan reads 58 locations - the ones you would guess (Application Support, Preferences, Caches, Containers, Saved Application State) and the ones you would not (HTTPStorages, WebKit, Cookies, the per-user trees under /var/folders, the audio plug-in roots, QuickLook generators), plus /Library/LaunchDaemons, /Library/PrivilegedHelperTools, /var/db/receipts and /Users/Shared outside your home folder. Two are read specially: Application Support one level deeper, because the nested folder is what should be proposed rather than the vendor folder that would take every sibling product with it, and launch item plists on their Label and ProgramArguments, because vendors name the file after the daemon.

Then the matching, where an uninstaller either earns trust or destroys data. An exact bundle identifier is certain, and so is that identifier as a whole dot-delimited run, an app group the app declared in its own code signature, or a path in an installer receipt pkgutil can prove installed this bundle. A name match is merely possible, and is graded as such.

What is missing from that list is the point. Rules for the vendor prefix and for the signing team both existed and were both deleted: between them they matched 45 times across two live scans, every one another app's data, and never once a real leftover. Same developer is not same app. The strongest rule fires last - a file filed under another installed app's identifier belongs to that app - and every row shows the reason it matched, which is the difference between a list you trust and a list you take on faith.

Three tiers, and what starts ticked

The Unroot review screen listing every trace found for an app, grouped under Safe to remove with each row showing its path and the reason it matched
Every row carries the reason it matched, and the header carries the count in each of the three tiers.

Findings are graded safe to remove, worth a look, or sensitive, and the grading answers one question: how careful do you need to be about this row. Safe is reversible, inside your home folder, and certainly the app's. Worth a look is matched by name only, or shared with an app you still have. Sensitive is keychain entries, privileged helpers, system extensions and anything outside your home folder - the only tier that can produce the failure everyone is afraid of.

The counter-intuitive part is what arrives ticked, because it is not the safe tier. A row is ticked when the match is certain, not when it is reversible. Conflating those made the product dishonest: an app's license lives in the keychain, so leaving those rows unticked meant the default removal quietly left the app activated. A sensitive keychain row is ticked; a name-only match is not.

The same screen carries the other mode. Reset keeps the app and removes everything it stored, except the installer receipts, because pkgutil forgetting a package that is still installed breaks its own updater. Keychain entries stay in scope on purpose: a factory-fresh app is signed out.

Nothing is deleted

The Unroot removal report reading 11 of 11 removed, with the quarantine folder path in the Trash and an Undo button
One dated folder in the Trash, a manifest beside it, and Undo still on the table.

Removed items go into one dated folder inside your Trash - Unroot - Spectacle - 2026-08-21 11-01-33 - each in its own numbered slot, so com.vendor.app.plist from ~/Library/Preferences cannot silently overwrite the one from /Library/Preferences.

One folder rather than four hundred loose items is partly legibility and partly capability: Finder's Put Back only restores the first item of a batch, and there is no public API to restore programmatically, so an undo built on it would be a promise the system cannot keep. Beside the files sits unroot-manifest.json, a plain list of where every item came from. It is what Undo reads, and it stays readable even if Unroot itself is gone.

One part of a removal genuinely is permanent, and the footer counts it in red. A keychain entry is not a file, so it cannot be moved into a folder; deleting it signs the app out and takes any license it stored with it. The confirmation sheet names each one rather than counting them, because a number is not consent.

Undo that survives a crash

The manifest can only record what was observed to succeed, so it can only be written after the run - and a crash in between would leave moved files with no record of where they came from, which is precisely the promise it exists to keep. So before anything moves, a journal of every planned entry goes into the same folder, and a completed run deletes it. A journal with no manifest is therefore the signature of an interrupted removal, and the next launch rebuilds the manifest from it, keeping only the entries whose files are demonstrably sitting in their slots.

Undo is then a reverse replay. If something now occupies the original path - you reinstalled the app - the restore diverts to a numbered sibling instead of overwriting it, because undo must never destroy anything in order to succeed. Launch jobs are re-bootstrapped rather than just re-filed, since putting a plist back and leaving the daemon booted out would restore the files and quietly not the behavior. Both directions pass a policy that assumes everything upstream got it wrong: /System, the keychain directories, iCloud Drive and your Documents, Desktop, Downloads, Pictures, Movies and Music can never be an endpoint no matter what matched.

The one step undo does not put back is the permission reset, and the app says so on the row rather than in a footnote: privacy grants are reset, not restored. Each app asks again the next time it needs one.

None of that expires. Every removal Unroot has ever made stays on one screen with the space its folder is holding, so a removal from two months ago undoes exactly like the one from two minutes ago - and whether it still can be is settled by looking at the disk, not by a flag written at the time.

Keeping everything does mean a Trash full of quarantine folders. Emptying it is the normal answer; failing that, Unroot will delete one folder on request. That is the only place in the app that deletes anything, so it is fenced: three checks that the path really is one of its own, and an automatic sweep that stays off unless you turn it on.

The permission entries nobody can clear by hand

Before you remove anything, Unroot reads the permissions database - read-only, with the same Full Disk Access it needs to see ~/Library - and shows what the app was holding. Accessibility, Full Disk Access, Screen Recording, Input Monitoring, Automation and some thirty grant types in all are decoded by name. Almost nothing else shows you this, and it is the best argument there is for why the order of a removal matters.

Because it does. The reset has to run while the bundle is still on disk, so the bundle moves last, after the launch jobs are booted out and the keychain entries are gone. Removing it first is the one-way mistake, and it is why so many uninstalled apps still haunt System Settings.

Afterwards the report re-reads the database rather than assuming the tools worked. macOS is known to refuse some Full Disk Access resets, so it either says the grants are verified clear or names the one that survived and tells you to clear it by hand.

Running apps are dealt with first of all. Each is asked to quit, and if it refuses you get a decision rather than a silent force-quit: force it, or skip that app and leave every one of its files untouched.

Apps you deleted years ago, and what they left running

The Unroot leftovers sweep listing orphaned caches and logs grouped by bundle identifier, with only the safe rows ticked
The sweep lists identifier-shaped leftovers only, and ticks nothing but the caches and logs macOS rebuilds on demand.

The other half of a narrow matcher is that leftovers belonging to apps which are already gone have nowhere to turn up. So they get their own sweep, and it is deliberately conservative. It lists only identifier-shaped things - a name with at least three dot-separated segments and no spaces - because a folder named after a company could belong to anything, and guessing is how an uninstaller deletes something it should not have.

Only caches and logs arrive ticked. App data and settings do not, and the screen says why: some of what is listed is cache written by a framework inside an app you still use, which looks identical from the outside. The list is a starting point, not a verdict.

A leftover file is inert. A leftover launch agent is not, and it is why an app you removed years ago can still put a background item in System Settings that System Settings gives you no way to remove. So the same idea is pointed at launchd: one screen lists everything that starts without being asked - launch agents, daemons, and the login jobs apps register through SMAppService - and names the owner of each.

Only the ones whose program is missing can be selected in bulk, and that restraint is the design. A job like com.docker.vmnetd shares a vendor prefix with an app you still have; grading it as related rather than orphaned exists precisely to keep something live off a list headed "safe to remove". A job that still has a program to run is never an orphan, however abandoned its name looks.

What it deliberately does not do

It needs Full Disk Access, switched on by hand, because macOS offers no way for an app to ask for it; without it a scan still runs but covers only the locations outside your home folder, and says so rather than letting a short list pass for a clean one. Removing anything outside your home folder asks for your administrator password once.

Some jobs it refuses outright - Apple's own software, itself, and system extensions, which get a section headed "Unroot cannot remove these" with the exact place to do it yourself.

It does not sit in your menu bar, and nothing watches for you to drag an app to the Trash - Unroot scans when you open it and does nothing at all the rest of the time. The one resident piece is a Finder extension, and it stays off until you switch it on in System Settings -> Extensions -> Finder. After that, right-clicking an app offers to uninstall it. Where that lands is worth knowing, because macOS is not consistent about it: in ~/Applications it is a top-level item naming the app, and everywhere else - /Applications included, which is where most apps live - it sits in the Services submenu, under the plainer "Uninstall with Unroot". It removes nothing by itself. It hands the app your selection, and the same review screen opens.

It is also not a disk cleaner. It looks for the traces of one app you name rather than for things you could free up, and it never goes near another user's account.

And there is no Mac App Store version, because reading ~/Library, resetting permission entries and moving root-owned files are all impossible from inside a sandbox.

What it costs, and what else to look at

Unroot needs macOS 14 or later, runs on Apple Silicon and Intel, and takes about 10 MB. It is pay what you want with a suggested price of $4.99 - an amount that genuinely includes zero - and the license is permanent either way. The full specification is on the Unroot page.

If what you are chasing is disk space rather than one specific app, Sweep is the neighbor - it files the Downloads folder by rules you write and bins installers older than a month, covered feature by feature in sorting files automatically on a Mac. There is a survey of the rest in Mac utility apps.