Last updated: September 2, 2026
Overview
ControllerKeys is a macOS utility by Kevin Tang that maps game controllers to keyboard input, mouse input, macros, scripts, webhooks, OBS commands, and system actions.
The app is designed to keep your configuration local. ControllerKeys does not run a third-party analytics SDK, and never sends specific controller inputs, key codes, typed text, profile names or contents, app names, macros, scripts, quick text, URLs, license keys, controller serial numbers, or configuration as analytics. The app does send a small amount of pseudonymous usage data—described in Usage Analytics below—so its developer can understand activation, retention, and which app versions and Macs to support. It can be turned off in Settings.
Usage Analytics
Because ControllerKeys is a free download (through GitHub and Homebrew) with a 14-day trial and paid license, the app sends small pseudonymous events so its developer can understand how many installs become useful, where people get stuck, which features are broadly used, and which app and macOS versions to support.
What is sent:
- A random install identifier (a UUID generated on your Mac). It is not derived from your name, email, or Apple ID. It is removed when ControllerKeys preferences are deleted, including with
brew uninstall --zap. - App version and build, macOS version, and Mac type (Apple Silicon or Intel).
- Your system language/region (e.g.
en_US) and whether the app is in trial, expired, or licensed state. - Whether the app was installed via Homebrew or downloaded directly.
- One-time setup milestones: each onboarding stage reached; a coarse permission state; a completion-time range; an optional, broad use case you may select; first controller connected (coarse family such as Xbox, PlayStation, Nintendo, Steam, generic, Apple TV Remote, wearable, or hand tracking); first mapping ready (mapping kind and whether it was manually created or imported); and first configured action dispatched.
- Trial-welcome and paywall views, successful purchase-link opens, and whether a license activation succeeded or failed. Failed activations use only a coarse reason such as invalid key, revoked purchase, network, or server error; the license key is never sent.
- At most one aggregate usage summary for a day with activity: an action-count range (
1–5,6–25,26–100, or101+), broad categories used (keyboard, pointer, macro, automation, MIDI, profile control, or other), and whether any complex action was used. Exact counts and action details are not sent. - When you activate a license, the Gumroad sale ID. This links that installation to a purchase record. The analytics database stores purchase metadata such as price, country, and referrer, but not the buyer's name or email address.
What is not sent: your name, email, specific controller inputs, key codes, typed text, profile names or contents, app names, macro steps, scripts, quick text, URLs, controller identifiers, license keys, or other configuration. Approximate country is determined from your network connection at the server's edge. Your raw IP address is not stored. Usage-event rows do not store an IP hash. For Sparkle update checks only, the service stores a one-way salted IP hash used to roughly de-duplicate active installations.
Each event has a random event ID so retries cannot create duplicate records. If the analytics service is unavailable, up to 100 unsent events are kept in ControllerKeys preferences and retried with increasing delays. Turning analytics off deletes that pending queue.
Raw usage-event rows are retained for up to 120 days, and raw Sparkle update-check rows for up to 90 days. Aggregate reports may be retained longer. Purchase records are retained as business transaction records.
The app's automatic update check (via the Sparkle framework) can also include system information — app version, macOS version, preferred language, Mac model, CPU, and memory — at most weekly. This is Sparkle system profiling.
The analytics endpoint is operated by Kevin Tang and runs on Cloudflare. Turn usage events and Sparkle system profiling off in ControllerKeys → Settings → General → Privacy → "Share Usage Analytics". Update checks still contact the update server without the system profile, and license verification still contacts Gumroad.
Data Stored Locally
ControllerKeys stores app configuration on your Mac. This can include:
- Controller mappings, profiles, layers, chords, sequences, macros, scripts, and settings.
- Linked app and linked controller settings used for profile switching.
- On-screen keyboard settings, quick text, app shortcuts, website shortcuts, and command wheel settings.
- Profile snapshots and backups used for restore and undo behavior.
- Aggregate button/action counts, movement distances, and session totals used by local recommendations and Controller Wrapped.
Current app data is generally stored under ~/.config/controllerkeys/ and related macOS preference/storage locations. Older installs may still have migrated data under ~/.controllerkeys/ or ~/.xbox-controller-mapper/. If you export a profile, you choose where that exported file goes.
Permissions
ControllerKeys needs macOS Accessibility permission to simulate keyboard and mouse input system-wide. Some features may also require Input Monitoring or other macOS permissions depending on your settings and macOS version.
These permissions are used so the app can perform the mappings you configure. They do not give ControllerKeys a reason to upload your data, and the app does not use them for telemetry.
Network Activity
Apart from the usage analytics, update check, and license verification described above, ControllerKeys makes network requests only when a feature you use requires it, including:
- License verification: when you submit a license key, ControllerKeys sends it to Gumroad's license API and stores the successful result locally.
- Community profiles and controller database: when you browse/import community profiles or request a controller-database refresh, ControllerKeys fetches the data from GitHub.
- Website favicons: website shortcuts may fetch an icon from the destination website or Google's favicon service for display in ControllerKeys.
- Webhooks: if you configure a button, macro, chord, script, or profile to call a URL.
- OBS WebSocket: if you configure ControllerKeys to control OBS Studio.
- Mac-to-Mac controller handoff: if you pair two Macs running ControllerKeys. This is designed for local/private networks and uses authenticated relay frames.
- Community profiles or external imports: if you choose to fetch or import profile data from a URL or file.
- User scripts or shell commands: if you create scripts or commands that access the network.
For user-configured webhooks, scripts, shell commands, OBS commands, and imported profiles, you are choosing the endpoint or code path. Review third-party profiles before importing them.
Third-Party Services
ControllerKeys is sold through Gumroad. Gumroad handles purchases, payment processing, receipts, and related customer/payment data under Gumroad's own policies.
The pseudonymous app analytics and the app's update feed are served through Cloudflare, which processes the network request (including your IP address) in order to deliver the response and provide approximate location, under Cloudflare's own policies. App updates use the Sparkle framework.
The ControllerKeys website at kevintang.xyz may use Google Analytics to understand page traffic. That website analytics is separate from the macOS app itself.
Crash Reports, Support, and Feedback
If you email support, open a GitHub issue, post in Discord, or otherwise contact Kevin Tang, the information you provide in that message may be used to respond to you and improve the app.
Please do not send private profile files, secrets, API keys, webhook tokens, or shell commands containing credentials unless you have reviewed and intentionally redacted them.
Profile Sharing and Imports
ControllerKeys profiles can be exported and shared. Exported profiles may include mappings, macros, scripts, shell commands, webhook URLs, OBS commands, app identifiers, quick text, and other settings you configured.
Before sharing a profile, review it for private text, commands, URLs, tokens, or app-specific information. Before importing a profile from someone else, review any code-execution surfaces such as shell commands, JavaScript scripts, webhook follow-up commands, and URLs.
Children's Privacy
ControllerKeys is not directed to children under 13, and Kevin Tang does not knowingly collect personal information from children through ControllerKeys.
Changes
This policy may be updated from time to time. The latest version will be posted on this page with the updated date above.
Contact
Questions about this privacy policy can be sent to martini-doubler7g@icloud.com.