The Dakota Coin LED Metals Sign
While I was a student at South Dakota Mines, I worked at Dakota Coin, a small coin shop in downtown Rapid City. I was a part-time student and spent most of my days at the shop. During COVID, the pace at the shop slowed down, so I built a scrolling LED sign to display live gold and silver prices. If you’ve driven through downtown Rapid City, there’s a good chance you’ve seen it.
That small shop project slowly evolved into one of my longest-running production systems. What began as a Raspberry Pi scraping a website and running an LED array eventually turned into a small distributed system, then a paid-API-backed service, then a Dockerized home-hosted API, and finally a nearly compute-less Cloudflare Workers and R2 setup.
The First Prototype
The original version was built around a single large 16x32 LED matrix driven by a Raspberry Pi. The Pi ran a script that scraped metals prices from a well-known market website, generated an image from that data, and then passed the image to another script that scrolled it across the LED sign.
It worked.
It was also janky as hell.
At the same time, Dakota Coin had a large 50-inch TV in the store that displayed a live metals price website. When that site went down, we had a hard time finding a better replacement, so I wrote a Python program that ran on a laptop attached to the TV. It scraped the same source as the LED sign and displayed the data locally.
That worked too, right up until our IP got blocked.
Turns out, when multiple devices in the same building scrape the same website every few minutes, the website eventually notices.
The First "Cloud" Version
To fix that, I built a PHP-based system hosted on my Domain.com account.
Instead of every display scraping the metals site directly, I moved the scraping to a single server-side process. A Raspberry Pi at my house called a protected endpoint on a cron schedule. That endpoint ran PHP code, scraped the metals prices, and wrote the latest values into a JSON file.
From there, I built a simple API for the LED sign to call. I also created metalsmarketdisplay.com, a website that displayed the same live prices. The page refreshed itself every five minutes, giving the shop TV a simple always-on display.
At that point, the system had become a tiny distributed cloud service. One process fetched the data, one server hosted it, the LED sign consumed it, and the website displayed it.
It was crude, but it worked. More importantly, it kept working after I moved out of town.
That was the first time I built something for a business that just quietly ran for years.
Replacing the Scraper
Eventually, the scraper broke while I was out of town.
By then, I was making more money than I had as a college student, so instead of duct-taping the scraper back together, I replaced it with a real paid metals API. It was cleaner, more reliable, and much less "please don't ban me."
While I was doing that upgrade, I also switched from writing a JSON file to storing the data in MySQL. It came with the hosting plan, so I figured I might as well use it.
That version ran for a while too. Until I had a falling out with Domain.com.
They were charging me for domains I had turned off, bumping things into higher tiers without making it clear, and generally giving off strong "ancient billing system and bad sales tactics" energy. Their tooling felt old, clunky, and weirdly predatory.
By that point, I had several years of software experience and a much better idea of how I wanted to run things.
So I rebuilt it again.
The Docker Era
The next version ran as a Docker container on my home server.
The backend was a small service that pulled live metals data from the paid API using a Python script. Since I only had a limited number of API calls per month, the system fetched the data once, stored it as a JSON file, and served that cached data through a tiny Go server running in the same container. I exposed the service using a Cloudflare Tunnel.
I also rewrote the website in Blazor WebAssembly and deployed it to Azure Static Web Apps. This was a big upgrade over the old PHP page. Instead of refreshing the entire page every five minutes, the site could fetch new data dynamically and update the UI in place.
This version was much cleaner. But it still had one huge problem: my apartment internet was now part of the production architecture.
And my ISP sucked.
When my home internet went down, the API went down. When the API went down, the LED sign and website stopped updating. Hosting a production service out of an apartment is cool right up until you are relying on it during business hours. It is especially bad when your apartment complex has signed an exclusivity deal with Bluepeak.
So it was time for another rebuild.
The Cloudflare Version
In June 2025, I rebuilt the system again. This time, I used Cloudflare Workers and R2. The backend became dramatically simpler.
A cron-triggered Worker runs every five minutes. It pulls the current prices for silver, gold, platinum, and palladium from the paid API. Then it writes the results to R2 blob storage.
There is no database.
There is no always-running server.
There is no home internet connection holding the whole thing hostage.
The Worker writes a "current" blob with the latest prices and another blob containing a rolling week of historical values for charts. The public API is really just R2 serving those blobs directly.
The best part is that Cloudflare lets you hide that implementation detail cleanly. The blobs do not need
file extensions. I set the content type and cache headers when writting the blobs, route api.metalsmarketdisplay.com to the storage, and the outside world sees what looks like a
normal API.
In reality, most requests are just retrieving static objects from Cloudflare's edge.
This strategy was so effective, cost-saving, and simple that I ended up moving nearly all of my other websites into Cloudflare. For small- to medium-sized websites and services, edge compute hits a sweet spot: low cost, low maintenance, high availability, and very little infrastructure to babysit. It can also work well as a front door for larger systems. I really cannot recommend it enough.
The Current Frontend
I rewrote the frontend again too, this time in Svelte.
The site uses a static adapter and is deployed to Cloudflare. It is extremely lightweight, fast, and simple. The frontend fetches the current metals data and chart history from the R2-backed API, then updates the display dynamically.
This is the fastest and simplest version the site has ever had.
The API is effectively compute-less for readers. The site itself is static. The Worker only wakes up every five minutes to refresh the data.
The whole thing uses a tiny fraction of my free Cloudflare resources. Not "tiny" in the hand-wavy marketing sense. I mean around 0.288% of the free tier.
That is not a typo. That is the actual number.
Updating the LED Sign and Shop Display
The LED sign only needed small changes for the final upgrade.
Originally, it had its own dedicated endpoint with a custom data shape. In the Cloudflare version, I merged
that into the main current endpoint, along with the historical endpoints used by the website
charts.
Once the backend and frontend were upgraded, I also replaced the old laptop connected to the shop TV.
That laptop had been running an ancient version of Ubuntu for years. If it shut down or lost the page, someone at the shop had to mess with it to get the display working again. So I replaced it with an old Raspberry Pi 4.
I configured the Pi in kiosk mode, pointed it at the metals display site, and added a few quality-of-life improvements like automatic nightly reboots. Now the shop display boots directly into the site and does its job without anyone needing to know or care what is running underneath.
What I Like About This Project
This project is still one of my favorites because it shows my growth as a developer in a very concrete way.
The first version was a student project: scrape a page, generate an image, and scroll it across an LED board.
The second version centralized the scraping and turned it into a crude API.
The third version replaced scraping with a real paid data source and introduced a database.
The fourth version containerized the API and used Cloudflare Tunnel.
The current version uses Workers, R2, static hosting, edge caching, and a frontend that is faster and simpler than anything before it.
Every version solved the biggest problem with the version before it. That is basically software engineering in miniature. Build the thing. Watch it fail in a specific and annoying way. Then make it less stupid.
This project also became a simple place where I can test infrastructure ideas in a real environment. It has just enough moving pieces to resemble a larger distributed application, without requiring me to migrate a huge amount of complex code. It is the perfect testbed.
I was lucky to have a boss who took a gamble and let me build this system in the first place. He paid for the hardware, gave me time to work on it, and trusted me to figure it out. I was happy to build it, and I am still happy to keep it running. Thanks, Lou.
The Dakota Coin LED sign has been running in some form for years now. It started as a COVID-era project at a coin shop and turned into a real production system that serves live metals data to an in-store LED sign, a shop TV display, and a public website.