It was March 2020, I was in New England when covid quarantine had just begun and I found myself much more homebound. In these situations I'm not one to just do nothing. I always have some sort of project or hobby to keep me busy, be it taking and editing photos, writing detailed blog posts, or coding something.
I had always wanted to learn iOS development, so this felt like the perfect opportunity. I was particularly keen to learn SwiftUI to build my designs natively. Years back I had dabbled with writing an Objective-C app, but it never quite filled me with joy, to say the least. As a designer, I've spent the last decade getting good with prototyping tools and frameworks to mimic realistic, interactive mobile prototypes. Building it myself was the natural next step to give me even more control over the experience, and get even deeper into the craft.
I started learning Swift and SwiftUI basics with courses like Design+Code, and Hacking with Swift. But I knew myself—I learn best with a project of my own. I knew exactly what I wanted to build: a better stock portfolio tracker. The stock market had taken a plunge with covid and I was doing dozens of trades per week with everything on sale. It would be fun to have a simple app of my own to track the performance of my trades instead of dealing with the subpar sites and apps from my stockbrokers.
Little did I know this project would consume my nights and weekends for over two years, often spending 10-20 hours a week on it. I built a ton of functionality, sweat all the details, wrote a comprehensive node backend for it, created an LLC for it, and managed an active Testflight. I was learning Swift and SwiftUI along the way, so I was often redesigning and rebuilding as I went.
Eventually, I decided to stop pursuing it. I'll get into the why a bit later. This post is for me to document Stocketa. I designed and built a lot that I'm proud of and want to have somewhere to archive it before I pull the plug.
is was Stocketa
Stocketa was a simple portfolio tracker designed with care. It came out of my frustration of having to check the clunky apps and sites that my brokers had just to get a glimpse at how my investments were doing. I'm a casual investor and don't need much from a tool like this but I had assets in various places, and I just wanted one easy and well-designed place to check them. I wanted to see real per-transaction gain/loss info, based on my own cost basis.
While there are tons of apps, brokers, and neobanks that address this, nothing quite felt like what I wanted. There were several types of solutions in this space:
First off, there are simple stock apps like Apple Stocks that let you see stock charts, news, and more. They have good data and don't require any accounts to use. However, they offer no functionality to log your holdings and track your gains/losses.
There are lots of broker apps (e.g., Robinhood) that let you trade and track your holdings, but they only let you see your holdings from them, not from any other financial services you might use.
Then there's a whole category of what I'd call advanced stock services like TradingView (and several that have since died or pivoted over the years), but they're not mobile-first or as elegant as I wanted.
There are broader investment advisor services like Personal Capital. While they do often have some aggregator functionality to link up your other accounts, they're not that powerful for diving into individual assets, aren't particularly well-designed, and are primarily focused on upselling you on their own investment advising services (seriously, I used to get endless 8am calls from Personal Capital).
And there are lots of smaller apps on the App Store where you can track your holdings but the design and UX leaves a lot to be desired. I've tried most of them.
From a design perspective, I generally found that financial apps bias towards density when displaying your assets. They assume you have tons of stocks and prioritize a list view where you have to tap in to a detail view to see more info. I found myself constantly tapping in, manipulating a chart or looking at some basic stats, then swiping back and repeating all that for several stocks. It was not easy or the kind of at a glance info I wanted.
That left me with my challenge. I wanted a simple portfolio tracker aimed at the casual investor. It didn't have to do it all, but it should aim to do a few things well. An app just for me.
I was more than thrilled to be working on a new app from scratch. After years of working at large companies with rigid design systems and gobs of stakeholders for every little design decision, I was yearning for some creative freedom. Freedom from process, freedom from typical design constraints. I would be in full control, designing and building it myself. It was my side project after all.
I had gotten tired of designing for traditional mobile apps. You know the type.. you add a tab bar, a typical navigation stack, page header and the app already feels significantly basic, muted, and limited out of the gate.
This was my place to have fun. I wanted to go custom and toss out whatever components the system gives you for free. And I knew that by having to figure out how to build various UI components from scratch, I'd learn a lot along the way. Almost all of Stocketa's UI is custom.
I will say that going custom is almost always the absolutely wrong thing to do 99% of the time. The operating system you're working in—be it iOS, Android, macOS—has invested a ton in a highly-considered suite of components. They're remarkably accessible, well-tested, and work on a variety of devices.
It's absolutely no small feat to consider creating a custom component for your app. However, when going custom does make sense and you're okay with the added scope and responsibility, the app becomes your canvas to do whatever you want and make it yours.
The first area where custom made sense for me was general app navigation. When I got started, I knew I wanted this app to have minimal app chrome. I didn't want a standard tab bar and header taking up space. I wasn't going to require much navigation: most things would just live inside the stock cards from the home timeline.
The app would be focused around showing more with less. Personally, I only cared about tracking a few stocks, but I hated the work of constantly having to tap in to see a detail view, or interact with the chart. As such, the main scroll view needed to be more immersive and not get occluded by unnecessary app chrome.
It started with app navigation, custom stock cards, sheets, and more. Needless to say, I spent a lot of time on the details with everything being custom. Below are a few examples:
Designing and building
I started with the basics: getting a scroll view of stock cards working, adding charts, and hooking it up to a database for persistence (initially Core Data before moving to Firebase). Then I added the requisite network calls and polling to update the stock card from a financial data provider. I started with IEX as the data provider as they had a decent API, reasonable pricing, and allowed commercial use, which would be required for a consumer app like this to go on the App Store.
One of the initial key decisions with Stocketa was that I wanted to track stock transactions in a comprehensive way. Simply logging the number of shares you had for each stock was not going to cut it. This ended up being a significant amount of work to do properly, but it was necessary:
For each stock sale or purchase I wanted to be able to display not only the total gain/loss, but per-transaction gain/loss so you could tell if an individual transaction was a good trade.
When it comes to stock sales, I needed to know the cost basis method (FIFO, LIFO, et cetera) so I could correctly calculate and display the realized and unrealized gains on a particular transaction. When selling shares, I also needed to know from which previous transaction or transactions the shares would be sold so I could get the correct cost basis and accurately calculate the gain/loss based on the cost basis method.
And then there was dealing with stock splits, which seems simple at first glance but ended up being quite a bit of work to build in a robust way: not simply altering previous transactions. They should be automatically applied for new splits, but also able to be manually applied if you didn't log split-adjusted transactions.
At some point I gave it a name: Stocketa. In Greek you might say "marketa" (Μαρκέτα, though αγορά might be a more proper word) when referring to a market, so this was like coalescing Stock and Market with that in mind.
When I was interviewing for a new job in 2021, I created these slides as part of my presentation after talking about my work at Twitter for the previous 9 years. These weren't all of Stocketa slides, and there was a lot of additional talking points I had for each slide, but you get the idea.
A note about SwiftUI
I kept designing, building.. and then redesigning and rebuilding. One of the side effects of learning Swift and SwiftUI as I was building this was that I was constantly redoing specific pages and parts of the app as I went. I continually found better ways to build things, and similarly I would continually refine designs. About a year or so into building Stocketa I wrote about my experience with SwiftUI. Much of that still rings true.
SwiftUI has come a long way since iOS 13. It's more performant, there's more parity in available components and functionality compared with UIKit, and you get more control over things. And with iOS 17, you get some goodies like shaders, keyframes, scroll transitions, and more.
There's still a gap between the types of things you can do with AppKit and UIKit, but SwiftUI is undeniably a powerful tool that's dramatically more approachable. And not just a coding tool; it's a great design tool. Designers can quickly lay things out, hook up interactions, and get a real feel for a design using a native tool.
Almost all of Stocketa's UI is built with SwiftUI. There were only a few occasions when I found it necessary to use UIKit to achieve some goal.1 None of this would have been possible, or drawn me to take a closer look into building iOS apps, if it hadn't been for SwiftUI.
What I built
I used the app daily and continued pouring time into every feature and detail to meet my high quality bar. While I initially planned for this to be a simple to build app that would not require a backend, or even any user accounts, that did not last for long. I quickly realized I needed my own backend to unlock a few things.
At first, this was so I didn't have to include the API key for my financial data provider inside the app for security reasons—I wouldn't want someone to find it and start running up my bill by abusing it. I created a backend proxy for the API with rate-limiting and throttling. Then, I wanted to have it be authenticated with user accounts, so I added Sign In With Apple along with a stock data caching system so that I only had to fetch stats for a stock once with a certain time period (depending on the particular stat that was either seconds, 24 hours, or weekly) regardless of however many user accounts needed that stock info. The main goal with that was to also reduce my costs associated with financial data API usage.
By this point I really started enjoying the speed at which I could update endpoints and business logic entirely on the backend. I started moving logic I had in the app to the backend. Stocketa was starting to come together.
Even though this was just a solo project, I used Linear to keep track of tasks, ideas, features, customer feedback, and milestones.
I had prioritized lists of things to build and bugs to fix. I was using—and loving—Linear for this. Here's a list of most of the things I built for Stocketa:
I ran a small TestFlight alpha with close friends, then increasingly I added more people. At one point I was up to around 1,000 people. That was the most I wanted to allow. I received lots of feedback from overall great first impressions (below), to general feature requests, and of course lots of bug reports.
Already the app is filling a need for me in its personal approach to tracking investments: no pushing for sales, no integrations with brokers and no unnecessary permissions. Brilliant.
Simply amazed at the SwiftUI work you’ve poured into this app. So beautiful. The onboarding alone is a masterclass in attention to detail. Bravo.
love it, this feels so polished and slick already... really great use of SwiftUI
Just got the invite, added my stocks... the animations are beautiful, design is clean and precise... it’s all around beautiful. Congrats!
F**k, man. This app is incredible. You’re building all of this on your own?
Dude. This app is f**king beautiful. Really great job. Just imported shares - super easy.
This NUX is insane. The particles when you add a stock. Gives me the happy brain chemicals..
I had thousands on a waiting list but there were API and hosting costs associated with the increased usage that I didn't want to bear yet, as well as a huge increase in support and customer feedback that took a lot of time to manage. You start to hear the same types of feedback, and it just becomes a chore to manage that many emails. That good news was that something was resonating and people cared enough to go through the work to send in bug reports and feature requests.
At some point early in feature development I took a break to focus on the website. At first I wanted a simple landing page to build interest, and collect emails for a waitlist so I could keep people in the loop. And I didn't want to spend that much time on it.
There was nothing fancy or particularly special about this initial page. It was just something quick I wanted to get out the door. And now, a while later, there's a lot I hate about this early design. The background texture was too strong, the headline alignment feels odd with the phone.. but I digress.
In that initial design I did start playing with some wave-related elements—a loose reference to stock market charts going up and down. And then to add to that, I built a few mini stock cards gently hovering in place (thanks to
offset-path CSS along with 2 keyframe animations) in the background. Each stock card had an SVG line chart—loosely based on that stock's actual performance around the time—that would animate on page load. I ended up keeping a version of these mini stock cards on the latest version of the website, and then on an onboarding screen inside the app.
The original inspiration for these random floating stock cards was from my now out-of-date work page where I highlighted projects with some large cards, each with their own intro animation based on the project. One of them was for my work on Twitter Video, where video clip thumbnails would fan out from the phone on hover (shown below).
In early 2021 I ended up getting around to designing and building out the first complete homepage for Stocketa. I had enough functionality and features built that it felt worthy of investing some time into showcasing them on the site.
Lots of app websites at the time (and still now) had the typical hero section on their homepage: some app screenshot in a phone frame off to one side, with accompanying header and subtitle text adjacent. Nothing wrong with that, but I wanted something a bit more engaging. I wasn't entirely interested in optimizing for conversion, and cramming a lot in above the page fold.
I thought it would be nice to try to do something where the 3D phone frame was angled and then began to change position on scroll while a brief teaser video of the app functionality played. Apple had done something similar in recent years with product pages, such as the first-generation AirPods Pro. They used over 100 frames of the AirPods that would progress as you scrolled:
There's a lot of ways to achieve an effect like this. One route route is using Lottie and essentially converting each frame of your video or animation to a base64-encoded string in a json file for the Lottie web player to manage. It's not a flawless solution, however, and can incur some large file sizes depending on what you're doing. It's best for vector micro-animations, not large devices with complex visual content. I also didn't want to incur the cost of that large initial json download blocking the very first thing you see on the site.
<canvas> along with an offscreenCanvas for performance. I used Rotato to import my short Stocketa screencast, create a 3D phone video, and then create a PNG sequence of frames. I wasn't super pleased with the quality—the phone frame didn't look super realistic and had some rough pixelated edges—but it was good enough compared to doing it all by hand with other design tools.
And finally, as for the rest of the content on this site I went with a basic feature card approach, sometimes called a "bento box" layout; particularly when varying card sizes are used. This is a layout that I've grown to like a bit less over the years as it has become very common.
A year later, it was time for another redesign. Stocketa had more functionality, and a lot more refinements. I had more to share, and I had grown tired of the 3D phone frame interaction. It was neat but it was just there for show; it wasn't the best way to show off parts of the app as it scrolled off screen. It was also a pain to update the frame sequences. I essentially just wanted to take screenshots of the real app from the iOS simulator and upload them.
Separately, I didn't want a super long page with a lot of repetitive modules and screenshots. I wanted a skimmable feature list. I began to wonder if I could get away with just a single phone frame on the site that showed everything.
I eventually landed on a two pane approach: the device frame was always in view, fixed on the right side, while the scrollable left side contained the feature list. The trade-off with this design was that it would require hovering over each feature item to be able to update the screenshot shown in the device frame. I figured an interesting compromise to that would be having the phones stack up and away on scroll. Almost like the old Apple Time Machine backup UI.
I built several versions of this and found that it didn't feel great. There wasn't much scroll distance so if you scrolled at a normal or fast pace, you'd see a bunch of phones flicker by you as the animations tried to keep up. It was too busy and hectic, not to mention a lot of state management to deal with jumping between your current scroll-based position screenshot to a hover-based screenshot if you hovered over a feature list item. I ended up simplifying a bit and only having the scroll-based UI manage just a few states: the intro phone frame, the first feature screenshot, and then a final animation at the bottom of the page.
After sorting out the core interactions, I had to figure out how to deal with mobile and tablet interactions. The fix two-pane layout made this a bit of a challenge. I ended up turning the header into a carousel of device frames you could scroll through.
And then finally, I added a few small bits of polish ✨:
Hero title text gradient changes based on scroll
The icon accent color and background circle color change based on scroll
When hovering over any feature list item, there is a subtle background color change created by an overlaid gradient. SVG-created noise/grain is also overlaid on top of the background.
When hovering over any feature list item, or when you're reached the end of the page, there's a subtle icon particle emitter that floats up icons from the bottom. Each feature used a different icon for this.
Overall I liked this design, but looking back at almost a year later, the gradient text and background colors feel a bit too much for my taste now.
Eventually it became clear that the quality of financial data Stocketa relied on was not cutting it. The first provider I used, IEX, would sometimes have charts outdated, inaccurate prices (especially for less frequently traded assets on the IEX exchange), and lacked data for OTC markets (they required you sign a pricey license directly with OTC), as well as significantly limited data for Nasdaq-listed stocks (even basic things like pre-market and after-hours data). The last straw was when IEX dropped mutual fund data entirely, all without any advance notice.
I later used another provider that allowed commercial use that didn't charge too much ($100/month) but I had even more problems with their data and reliability. Endpoints were even returning old and incorrect data, and even once alerted to issues, their team would not only ignore the bugs but claim they didn't exist. I couldn't ship Stocketa with unreliable financial data to people that would be paying me for a quality app.
I also could not get certain types of data with paid APIs. I had to build a scraping engine on my backend that would visit a few sites to get the data I needed for less updated data like dividend yield, earnings dates, and even for OEF data (other providers would be more than a day delayed for this at times).
Needless to say, this was all frustrating. It was a hassle, hard to maintain, and unreliable. At the same time, my backend continued getting more involved to deal with more and more of the intricacies of dealing with stocks. Things like dealing with companies merging or stock tickers renaming.
Starting out I thought getting access to a stock market data API would be the easy part. I quickly learned about the world of market data feeds, SIPs (Securities Information Processor), and vendor agreements.
Quality market data exists, it's just not made for indie app developers. It's very expensive. Several leading U.S. market data providers have commercial use data pricing starting at $2,000 per month. And that's not for everything, if you need things like index data or options data, there's more charges ahead.
I spoke with one of these providers last year, trying to get them to understand how small app developers need affordable commercial use data. They presented a startup-focused plan that they were pitching for $499/month in addition to a per-MAU fee. Even that I would still consider very expensive for my needs, and it seems like that may have fallen by the wayside and is no longer promoted on their website.
I could spend months developing Stocketa, incurring that monthly API cost until I went live (or risk getting shutdown if I tried to use a cheaper non-commercial plan during the TestFlight phase) then not make enough money to cover costs on the App Store and have to shut it down shortly after anyways.
Overall, it feels like no one in this cares to cater to the developer and startup crowd, or they believe there's not much money for them to pursue there. This was the same case with Plaid when I briefly looked into getting access to their investments API to automatically sync holdings data. They required some sort of minimum length contract.
Why I stopped working on Stocketa
When I started this project, I really began to wonder why where weren't any great indie apps focused on stocks like this. Just simple, well-designed apps to help the casual investor keep track of their investments. Well I think I was starting to get my answer: getting quality financial data, even just for the United States, is a nightmare. You can only get it if you have a lot of money to invest in your project. And good luck if you really want a great API with comprehensive international data.
I can't help but draw parallels to what happened recently with the Twitter and Reddit APIs. The risk of running your project or business solely on top of another company's API, no matter how reliable you think they may be, is extremely high.
Stocketa was always meant to be a side project—never a real business. For it to be a real business, I would need to keep adding functionality and introducing more ways to make money. I couldn't just have a simple and elegant little app tracking your stocks. It would have to do more, like dipping into financial advice services, or offering stock trading. That's a hyper-competitive space lined with massive companies. That would mean a busier, cluttered app. The exact reason why I started Stocketa was because of all those cluttered apps.
I decided to stop working on Stocketa for a few reasons:
Data: As mentioned above, all the expenses and challenges associated with acquiring reliable, affordable, and high-quality financial data that would make it feasible to release this as a reasonably priced subscription-based app.
Support: The associated investment in customer support. Based on how people were using my TestFlight, it was going to be a significant investment to keep up with support, emails, maintenance, and ongoing feature development. However, part of this was likely due to complexity incurred from having to fix or skirt around unreliable data. There were lots of things I wanted to keep improving and refining with the app and that wouldn't end any time soon.
If I were to release and charge for Stocketa, I would feel especially on the hook to resolve issues in a timely manner and that's not something I can accomodate now because of the next point.
Time: And most importantly, I've found something more worthy of my complete focus and attention: Rewind AI. I sunk a lot of nights and weekends into Stocketa over the years. It consumed every spare moment, even taking over my occasional time writing blog posts here when I had something to share. That was something I really missed. Now, I would much rather be focusing my creative thinking time on how I can improve and grow Rewind.
I originally started working on Stocketa with one goal: to learn Swift and SwiftUI my way with a project that was interesting to me. At the time that was scratching my own itch of keeping track of my investments. While it turned into a much larger and unshipped project, I learned a ton about native iOS development and was able to push myself creatively.
These days I'm happiest investing my design, product and development time into Rewind AI, where my SwiftUI knowledge learned with Stocketa has been tremendously helpful.
1 I only had to go down to UIKit a few times. One time for things like custom text fields for more control over interactions, styling, text input, and formatting. Another to use a CollectionView for drag-to-reorder stocks. A third time for creating particle emitters in a few places, like confetti effects, as well as one area where I have some twinkling stars in a night illustration when the stock market is closed. And one last time to get more control over gestures. I needed to get a location when a long press begins and SwiftUI LongPressGesture() didn't provide that, so I used UILongPressGestureRecognizer instead.