Security & Verification
Last updated August 11, 2026
Comoji asks for Accessibility and Input Monitoring. Those are the two most invasive permissions macOS has, and “trust us, it’s all local” is not an answer. This page exists so you don’t have to take our word for it: below is every host the app can contact, what triggers each one, and the exact commands to watch Comoji on your own machine while you type.
The short version: your keystrokes never leave your Mac. Not to us, not to anyone. Comoji has no account, no telemetry, no analytics, and no crash reporter. The only network requests it makes are the four listed below, and none of them carries anything you type outside the GIF picker’s own search box.
Prefer a walkthrough? How to verify Comoji is local, step by step does this with screenshots and copy-paste commands.
What each permission is used for
macOS’s own permission prompt tells you which permission an app wants, never what the app does with it. So, precisely:
Input Monitoring
- Used for: a keyboard event tap that watches for a colon-prefixed token like
:liz. Characters accumulate in a small in-memory buffer that is discarded the moment the token ends (space, escape, a click elsewhere, or a match being accepted). - Never used for: recording, storing, or transmitting what you type. The buffer is never written to disk, never logged, and never sent anywhere. The app’s own test suite fails the build if any networking API or remote URL appears in the code that handles keystrokes.
- Not watched at all: secure (password) text fields, plus a built-in exclusion list covering password managers, terminals, and remote/VM clients — and any app or website you add yourself in Preferences › Privacy.
Accessibility
- Used for: asking macOS which text field has keyboard focus and where its caret is on screen, so the suggestion popup appears in the right place; and typing the chosen emoji back into that field (synthetic backspaces plus a brief clipboard paste, after which your previous clipboard is restored).
- Never used for: reading the contents of the field, your documents, your messages, or other windows.
The complete network surface
This is the whole list. If you ever see Comoji connect to a host that isn’t on it, that’s a bug and we want to hear about it at hello@comoji.io.
storage.googleapis.com
- What: The update feed (a Sparkle appcast) and the new version’s DMG. Both live in Comoji’s Firebase Storage bucket.
- When: The background update check and download, and the “Check for Updates…” menu item. Turn off “Keep Comoji up to date” in Preferences and it only happens when you ask.
- What’s in the request: A plain GET. Sparkle’s user agent carries the app name and the version you are on.
fonts.gstatic.com
- What: Sticker artwork — Google’s Noto Animated Emoji — for stickers that aren’t already bundled in the app.
- When: Picking a sticker that isn’t bundled, in the /sticker picker. Cached on your Mac after the first use, so it happens once per sticker.
- What’s in the request: A plain GET for one image file, named by its emoji codepoint.
api.giphy.com
- What: GIF search and trending results for the /gif picker.
- When: Opening /gif, and each search you type into that picker. Never automatic — no /gif, no request.
- What’s in the request: Only the text you type into the GIF picker’s search field, plus Comoji’s GIPHY API key. Nothing you type anywhere else on your Mac.
*.giphy.com
- What: The GIF files themselves, from GIPHY’s CDN (media0–media4.giphy.com).
- When: Displaying or inserting a GIF from results you already asked for.
- What’s in the request: A plain GET for the exact GIF URL the search results named.
Nothing else
No analytics endpoint, no telemetry, no error reporting, no license server, no account system. Install Comoji, never open /gif or /sticker, and turn off automatic update checks, and the app makes zero network requests for as long as it runs.
This list is not just a description of the app — it is a rule the app obeys. Not every URL is written into the source: the GIF files themselves are named by GIPHY’s search response. Every one of those fetches is checked against the list above before the request is made, and dropped if it doesn’t match. Redirects are checked the same way, so a server that answers “go here instead” can’t send us somewhere else either. Even a tampered or hijacked search response cannot make Comoji contact a host this page doesn’t name.
These hostnames also appear inside the app, but Comoji never fetches them — it hands the URL to macOS and your browser loads the page: www.comoji.io, www.mattsenter.com, www.stockcar.app, www.premail.pro, www.burly.click, www.beeready.buzz, www.highwire.news, www.seedmatrix.com.
How to check this yourself
Every command below is read-only and safe to run. Paste them into Terminal with Comoji running. (If you installed the dev build, the process is ComojiDev rather than Comoji.)
1. Watch its connections while you type
First confirm Comoji is actually running, and get its process ID:
pgrep -x ComojiYou should get back a number. If you get nothing back, Comoji is not running — it is a menu bar app, so check the menu bar rather than the Dock — and the commands below would report no connections whether or not it makes any. Get a PID first, or the rest of this proves nothing.
lsof lists the network sockets a process has open. Open Messages, type :fire and press Tab a few times, then run:
lsof -nP -i -a -p "$(pgrep -x Comoji)"Expect no output at all. No output means the process has no network connections open — that is the claim, tested directly.
To watch continuously while you use it, run this in a spare Terminal window and type in another app for a while:
while :; do
printf '%s ' "$(date +%T)"
lsof -nP -i -a -p "$(pgrep -x Comoji)" | tail -n +2 | awk '{print $9}' | paste -sd' ' -
echo
sleep 2
doneThe line stays empty no matter how much you type. Then open /gif and search for something: you’ll see api.giphy.com and a giphy.com CDN host appear, and only then.
2. Total bytes in and out
nettop shows cumulative traffic per process, so it catches anything short-lived that lsof might sample between:
nettop -P -p "$(pgrep -x Comoji)"Type for a few minutes with the GIF and sticker pickers untouched. The bytes_in and bytes_out columns stay at zero. Press q to quit.
3. Read the hostnames out of the shipped binary
A running process can only connect somewhere it knows about. You can pull the URLs straight out of the app you downloaded:
strings -a /Applications/Comoji.app/Contents/MacOS/Comoji \
| grep -Eo 'https?://[A-Za-z0-9._-]+' | sort -u
/usr/libexec/PlistBuddy -c 'Print :SUFeedURL' \
/Applications/Comoji.app/Contents/Info.plistTwo honest notes so this matches what you actually see. First, api.giphy.com is assembled from its hostname rather than stored as a full URL, so it won’t show up in that first list — search for it directly with strings -a … | grep -Eo '[a-z0-9.-]*giphy\.com' — that pattern matches hostnames only, so it won’t print the API key that also ships in the bundle. Second, the bundled Sparkle update framework carries its own documentation URLs (sparkle-project.org, andymatuschak.org) inside Contents/Frameworks/Sparkle.framework; those are strings in a third-party library, not hosts Comoji contacts.
4. Block it at the firewall and see what breaks
The strongest check is an outbound firewall. LuLu is free and open source; Little Snitch is the commercial standard. Set either to alert on every outbound connection, then deny everything from Comoji. Emoji autocomplete keeps working exactly as before, forever, because it never needed the network. The only things that stop working are the update check and remote sticker or GIF artwork.
5. Confirm the app is really ours and unmodified
Comoji is signed with an Apple Developer ID and notarized by Apple. These verify the copy on your disk hasn’t been tampered with:
codesign -dv --verbose=4 /Applications/Comoji.app
spctl -a -vvv -t exec /Applications/Comoji.app
codesign -d --entitlements - /Applications/Comoji.appWhat we have decided to do, and not do
The obvious question is why we don’t just open-source the whole thing. Here is where we actually stand, so you can judge the answer rather than guess at it. The full reasoning is recorded in the repository as an architecture decision record (docs/adr/0001-verifiable-local-processing.md).
- Done — publish the exact network surface. The list above, shown in the app under Preferences › Privacy as well, generated from the same declaration the app is compiled against — and enforced against it at runtime, so a URL handed to the app by someone else’s server still can’t reach an undisclosed host.
- Done — self-verification instructions. This page and the linked walkthrough.
- Done — enforce the claim in CI. Every pull request and every release runs the app’s test suite on a macOS runner (
.github/workflows/app-ci.yml, and again insiderelease.ymlbefore anything is signed). That suite scans the actual sources and fails if a host appears that this page doesn’t disclose, or if any networking API or remote URL appears in the code that handles keystrokes. A build that breaks either rule cannot be merged and cannot be released. - Declined for now — open-sourcing the input path only. Publishing just the event tap, token buffer, and matcher would be a real trust signal, and it is the part with no commercial value. We are not doing it yet for an honest reason rather than a good one: a published subset that isn’t provably the code in the notarized binary proves less than it appears to, and doing it properly means reproducible builds (below). We would rather ship the verification you can perform on the binary you actually downloaded first. This is revisitable, and the input path is the first thing we would publish.
- Declined for now — reproducible builds and a paid security review. Both are the highest-credibility options and both cost more than this project currently earns. Deferred, not dismissed: a paid third-party review with a published summary is the intended next step once revenue supports it, and it would be published here.
If you verify any of this and find something that contradicts what’s on this page, mail hello@comoji.io and we will correct the page or the app, whichever is wrong.
See also the Privacy Policy for what Comoji stores locally on your Mac.