Where's the command?
It's the app's own executable. Once AppSheriff is in your Applications folder, it's here:
/Applications/AppSheriff.app/Contents/MacOS/AppSheriff
When you run it with one of the flags below, it prints its result and exits without opening a window. To type less,
add an alias to ~/.zshrc. The examples on this page assume it:
alias AppSheriff="/Applications/AppSheriff.app/Contents/MacOS/AppSheriff" Which commands are there?
| Command | What it does | Prints |
|---|---|---|
--list-devices | Lists iPhones and iPads on USB, and booted Simulators | JSON |
--list <id> [--system] | Lists the apps on one device, with their sizes | JSON |
--delete <id> <bundleID> | Deletes one app and its data | One line |
--dump <id> <file.json> | Saves everything AppSheriff read about every app to a file | One line |
--activate <key> | Unlocks AppSheriff on this Mac with your license key | One line |
<id> is a device's UDID, from --list-devices. The free download runs
--list-devices and --activate; --list, --delete and
--dump need the license: $10, once, no subscription.
How do I list devices?
--list-devices prints a JSON array with one entry for each iPhone or iPad connected by USB and each booted
Simulator. Use an entry's id with every other command.
AppSheriff --list-devices
[
{
"id" : "02A237DE-8659-45A8-B6BF-D16D08C34D3F",
"kind" : "simulator",
"model" : "Simulator",
"name" : "Maya's iPhone",
"osVersion" : "iOS 27.0"
},
{
"id" : "581ED9DC-E5C1-4DB2-B349-0FEC2B5B56E9",
"kind" : "simulator",
"model" : "Simulator",
"name" : "iPhone 18 Pro",
"osVersion" : "iOS 27.0"
}
] id: the device's UDID.name: the name the device goes by.kind:usbfor an iPhone or iPad on the cable,simulatorfor a Simulator.model: the hardware identifier a USB device reports, orSimulator.osVersion: for exampleiOS 27.0oriPadOS 27.0.
A phone must be unlocked and trusted (tap Trust on the phone) before AppSheriff can read its apps. Simulators that aren't booted aren't listed.
How do I list the apps on a device?
AppSheriff --list 02A237DE-8659-45A8-B6BF-D16D08C34D3F --list prints a JSON array with one object per app: what the device reports about it, what it declares it
can do, and its size, measured on the device. It lists the apps you installed; add --system to include
iOS's own apps too.
Measuring is the slow part on a phone: about 75 seconds for 300 apps on an iPhone 16 Pro Max. --list
doesn't ask the App Store anything, so it prints no statuses such as Abandoned or Not on App Store; the app works those
out.
[
{
"build" : "3.1.2",
"bundleID" : "com.example.flashlightdeluxe",
"capabilities" : {
"backgroundModes" : [
"location",
"audio",
"fetch",
"remote-notification"
],
"deviceFamilies" : [
1
],
"fileSharing" : false,
"hasEntitlements" : false,
"privacyPrompts" : [
{
"purpose" : "camera",
"reason" : "The camera flash powers the light."
},
{
"purpose" : "microphone",
"reason" : "Strobe mode reacts to music."
},
{
"purpose" : "contacts",
"reason" : "Find friends who use Flashlight Deluxe."
},
{
"detail" : "always",
"purpose" : "location",
"reason" : "Your location helps us show deals near you."
},
{
"purpose" : "tracking",
"reason" : "Allow tracking to keep Flashlight Deluxe free."
}
],
"transportSecurity" : {
"allowsArbitraryLoads" : true,
"allowsArbitraryLoadsForMedia" : false,
"allowsArbitraryLoadsInWebContent" : false,
"exceptionDomainCount" : 0
},
"urlSchemes" : [
"flashdeluxe"
]
},
"containerPath" : "…\/Data\/Application\/EBF4331B-…",
"displayName" : "Flashlight Deluxe",
"installedOn" : "2026-09-23T21:33:46Z",
"isAppClip" : false,
"isHidden" : false,
"isOffloaded" : false,
"isRemovable" : true,
"path" : "…\/Bundle\/Application\/7D211D0B-…\/FlashlightDeluxe.app",
"rawAttributes" : {
"ApplicationType" : "User",
"CFBundleIdentifier" : "com.example.flashlightdeluxe",
"CFBundleShortVersionString" : "3.1.2",
"IsRemovable" : "1"
},
"sizes" : {
"dynamicBytes" : 6295552,
"staticBytes" : 18956288
},
"type" : "user",
"version" : "3.1.2"
}
] | Field | What it holds |
|---|---|
bundleID , displayName , version , build | Who the app is, as the device reports it. |
type | "user" for apps you installed, "system" for iOS's own (with --system). |
sizes.staticBytes | The app itself, measured on the device. |
sizes.dynamicBytes | Its documents and data. |
isOffloaded , isRemovable , isHidden , isAppClip | State flags. |
capabilities | What the app declares: privacyPrompts (each with its purpose and the developer's reason text), backgroundModes, urlSchemes, appGroups, iCloudServices, deviceFamilies, fileSharing, and transportSecurity for plain-HTTP exceptions. |
iTunes | Phones only, from the purchase record: purchaseDate, releaseDate, itemID, externalVersionID, storefrontID, storefrontCountry. |
installedOn , lastUsed | Simulators only. iOS doesn't give a Mac these dates for a phone. |
path , containerPath | Where the app and its data live on the device. |
rawAttributes | The attributes as the device returned them, as text. See the privacy note under --dump. |
Fields without a value are left out. Keys are sorted, dates are ISO 8601, and slashes in paths come out escaped
(\/), which any JSON parser reads back as /.
How do I delete an app?
AppSheriff --delete 02A237DE-8659-45A8-B6BF-D16D08C34D3F com.example.oldbuild
Uninstalled com.example.oldbuild from Maya's iPhone It deletes one app per run and prints one line once the device confirms. To delete several, run it once for each bundle ID.
How do I save a diagnostic dump?
AppSheriff --dump 02A237DE-8659-45A8-B6BF-D16D08C34D3F ~/Desktop/apps.json --dump writes the same JSON as --list --system, iOS's own apps included, to the file you
name, then prints how many apps it wrote. It doesn't measure sizes; use --list for those.
What the dump leaves out
On a phone, rawAttributes holds the attributes the phone's app-listing service
(installation_proxy) returned, written out as text, with one exception that matters for privacy.
iTunesMetadata carries the purchaser's Apple ID, name and account ID (DSID), so AppSheriff replaces it with
its key names:
"iTunesMetadata" : "present (parsed); keys: …"
Its non-personal fields (the purchase and release dates, the App Store IDs of the app and its version, and the
storefront) are kept under iTunes. Entitlements and app group containers are summarized in
capabilities instead, and environment variables are left out. --list applies the same rules.
On a Simulator, rawAttributes holds what simctl listapps reports.
How do I unlock AppSheriff from the Terminal?
AppSheriff --activate <key> --activate checks your license key on your Mac, with no server involved, stores it, and prints who the copy
is licensed to. It unlocks the app as well as the command line.
How do I use it with Simulators?
Every booted Simulator appears in --list-devices with kind set to simulator, so
the same commands clear out test devices. Simulators also report installedOn and lastUsed for
each app, which phones don't.
This script finds the first booted Simulator, deletes a test build and checks it's gone. It stops with an error if there's no booted Simulator or the app is still there. Scripts don't read your aliases, so it uses the full path:
#!/bin/zsh
# Delete a test build from the first booted Simulator, then make sure it's gone.
set -euo pipefail
APPSHERIFF=/Applications/AppSheriff.app/Contents/MacOS/AppSheriff
BUNDLE=com.example.oldbuild
UDID=$("$APPSHERIFF" --list-devices | jq -r 'map(select(.kind == "simulator"))[0].id')
[[ "$UDID" != null ]] || { echo "No booted Simulator" >&2; exit 1; }
"$APPSHERIFF" --delete "$UDID" "$BUNDLE"
"$APPSHERIFF" --list "$UDID" | jq -e --arg b "$BUNDLE" 'all(.[]; .bundleID != $b)' > /dev/null
echo "$BUNDLE is gone from $UDID" A few one-liners with jq:
AppSheriff --list 02A237DE-8659-45A8-B6BF-D16D08C34D3F | jq -r 'sort_by((.sizes.staticBytes // 0) + (.sizes.dynamicBytes // 0)) | reverse | .[:5][] | .displayName' AppSheriff --list 02A237DE-8659-45A8-B6BF-D16D08C34D3F | jq -r '.[] | select(any(.capabilities.privacyPrompts[]?; .purpose == "camera")) | .displayName' AppSheriff --list 02A237DE-8659-45A8-B6BF-D16D08C34D3F | jq -r '.[] | "\(.bundleID)\t\(.version)"' What do the exit codes mean?
| Code | Meaning |
|---|---|
| 0 | Done. |
| 1 |
Something failed, and the reason is on standard error. No such device: <id> means that ID
isn't connected or booted. Other messages come straight from Apple's MobileDevice framework and usually mean the
phone is locked, not trusted yet, or was unplugged.
|
| 2 | This copy isn't unlocked, so --list, --delete and --dump won't run. |