The next version of Actual (0.0.138) implements basic tracking to help inform development, and I want to be completely transparent about how it works. Your privacy is still important.

Unlike most apps, Actual treats your data like its yours. It's literally a sqlite file on your hard drive, even on the web. Because this approach is so different than other apps, I need to think harder about everything I do. Most services out there just assume you're OK with handing over users' data. I am not.

A big example is sharing your data across devices. Instead of giving up and moving your data to the cloud, I built a custom syncing engine that supports end-to-end encryption. Your data is still local, but now it's able to be synced around. As a bonus, you don't have to worry about losing all your data if your computer breaks.

Another example is tracking. Since I don't know anything about your data, adding a bunch of tracking seems invasive, especially if I'm handing it over to a 3rd party. I want to respect your privacy, so I need to rethink the standard approach.

I've struggled reconciling this, to be honest, and I delayed figuring it out. Until now, all I had was some super basic metrics like how often the app opened and when a user subscribes/unsubscribes. I did this in a self-hosted instance (for improved privacy) of redash which let me write custom SQL queries against a single events table on my PostgreSQL server.

I really can't support a homemade version of tracking. There's too much work to do in the app itself, and I really need some more data to figure out just how the app is being used and how users are converting. This data could make the difference between Actual succeeding or not. I have to figure this out.

What I settled on: the next version of Actual (0.0.138) adds basic tracking using mixpanel. A few quick notes about this:

  • You can always opt-out in Settings > Global under Privacy. Turning off this setting completely removes any form of tracking.
  • We will never log anything related to your actual data, i.e. account balances, payee names, etc.
  • Right now, these are the only things logged:
    • When the app opens
    • When a user logs in
    • When a demo file is created
    • When a file is opened. We include the file size of the opened file in this event
  • We will likely add more events in the future, but they will always be general statistics about how the app is used, and never include actual data.

Tracking file sizes is a perfect example. It's very useful for me to know the various sizes of files being used with Actual. So far I've been guessing, and file sizes make a big impact on technical decisions. This data is also not very privacy-sensitive. It's a good tradeoff to track this data which will very much improve Actual, and doesn't really sacrifice any privacy.

This is the kind of data we will track, and we will never track or log anything related to your actual data.

Measuring success

Another really hard thing about lacking data is knowing whether a launch was successful or not. When I launched scheduled transactions, I had no data to know if people were using it.

This is hard on an emotional level too. After working so hard on a feature for months, it's really nice to actually see it in use. Even just tracking the number of schedules created would have been a nice boost of validation. The best part of building a product is knowing people are using it.

Having basic data not only informs where to invest in the future, but also provides a more emotional connection with users.

Anonymizing mixpanel

You still might be thinking "ok sure, you don't log my data but you're still giving me email and location to a 3rd party". Short answer is: we don't!

We intentionally avoid giving mixpanel your data. We never give them your email or location.

I have explicitly disabled IP-based location logging, so your location simply isn't in there.

I do need some sort of identifier representing your account. There is already a "user id", but the raw user id feels somewhat sensitive given that it's used in the login process. Instead, I generate a base64-encoded sha256 hash of your user id and give that to mixpanel.

Here's an example of how data looks in mixpanel. This is a list of events, note how your email or location is nowhere to be seen:

And here's how a specific user looks (I tweaked the user id for the screenshot just in case). Funnily, my base64-encoded sha256 hash breaks mixpanel's UI:

Mixpanel doesn't know anything about who you are. The only data in there is events grouped based on a distinct id that I control. This does mean I personally could reverse the hash and identify the user for these events, however that's ok since we never log anything from your data.

Again, you can always opt-out under Settings > Global.

I'm very excited about the quick feedback loop this will provide. In addition to improving the web version and other work, it's going to be easier and faster to develop Actual than ever before. I can't wait.