How I made a low-code app to distribute App Store offer codes
I was focused on developing new features for my side project Amicu. During a break, I saw this tweet.
Do you have an app with a Black Friday sale on at the moment? @bryandubno is putting a list together, and it's very likely going to be in this weeks @iOSDevWeekly. 🚀 https://t.co/JjUYeaSMDn
— Dave Verwer (@daveverwer) November 25, 2020
And I realized I forgot about all the promotions at this time. As of writing this my app has 5 customers and made around $100 in revenue. It might not sound like much, but the first money on the internet feels special. As a developer, it's easy to neglect the marketing side, but especially in the beginning, it's important to use every opportunity that comes.
But how can I offer a discount on the App Store?
You can set up introductory offers in App Store Connect. But my app UI wouldn't correctly show the discounted price. There was not enough time to make changes in the app and wait for the review. Even though review times are better nowadays it would be a risk. It would be a bad experience if my app is listed and the update isn't live.
I remembered the new App Store offer codes Apple recently launched. You can do all sorts of campaigns with them. And it's configurable in App Store Connect. With a limit of 10 active offer campaigns per subscription and 150.000 codes per app per quarter. The biggest limitation is that it only works on iOS and iPadOS 14.
The codes are redeemed in the App Store and optionally in the app. So you don't need to update your app. All you need is a working observer for the payment queue in the app and optionally App Store server notifications. Thankfully, this is all handled by RevenueCat automatically. The notifications require a one-time configuration in App Store Connect and the RevenueCat dashboard.
I set up my offer code with a 60% discount for the first year. Clicked create offer codes and then you get a big text file with 500 or more comma-separated codes. Users can redeem them with this URL:
https://apps.apple.com/redeem?ctx=offercodes&id=<appid>&code=<code>
But how do I get a unique code for every person interested?
I could only enter a generic code in the Airtable form linked by @bryandubno. I could publish a site with all codes, but then users would need to find a valid one and mark it as redeemed. That's a pretty bad user experience.
I searched for tools to distribute unique codes. I found integrated tools in website builders, but I don't want that. I also found some feature-rich SAAS. They come with all sorts of privacy-invading tracking and integrations to many platforms (but not the App Store?). And they're not as affordable.
Privacy is one of the USPs of Amicu. And users plus customers told me they appreciate it. I didn't feel like signing up and fighting with SAAS tools designed for e-commerce. There were no guarantees it would even work in the end.
My next idea was to put the codes in Airtable. And they have a new scripting feature. I quickly developed a script and attached it to a button. The script found a valid code and updated the row as redeemed. It worked well enough. But when I shared this table for everyone to get their codes the button was disabled. Airtable allows scripting only for logged in users. Do I want users to signup to Airtable to redeem a code? No.
I searched a bit more and found Tokens 2. A macOS app for promo codes. It looked promising. Unfortunately, their friendly and fast support told me that they're still working on offer codes.
The final solution
So I tried the Airtable approach in Google Sheets. I made a table with all codes and added a script. I already used Google App Script a few times for small tools so this was easy. But I noticed in the script editor you can deploy your Google Sheets script as a web app. Making a Ruby on Rails app with a database was another option. But I wasn't sure if I could deliver a good-enough experience in a short time. And running a rails app plus database seemed like too much for only distributing codes.
I never tried the Google Script Web App feature before. But with some experimenting, I found that you can even deploy basic websites for free with custom HTML, CSS, and JS. And connect it to a Google Sheet. It's powerful and the quotas (quotas) are good enough for an indie app unless you end up on the top of HackerNews.
You can also easily embed the web app as an iframe on your app landing page. The custom HTML and CSS allow custom branding or e.g. collecting emails in a form. You can do your business logic in JavaScript to validate codes. For example, it's possible to have different codes like CYBERSALE50 and CYBERSALE25. You just map them to a specific sheet for the corresponding offer code campaign.
It took some time to figure out permissions, iframe security, and configure everything. But it works. It's highly customizable. Free to host with a Gmail account. And with a paid G Suite account you get bigger quotas. But for an indie app, it should be fine. I will also use this to distribute special offers for users, who provide feedback.
You can add columns for additional data.
Completely customizable form and website with your HTML, CSS, and JS code.
Try the demo version.
Get your own unique code distribution tool
FAQ
Why don't you open-source this for free?
Edit: It's open source now, but you can still buy it to support my work.
It took time to make this. And my indie projects don't make enough money yet to pay the bills. I follow the Basecamp advice to sell my by products. But feel free to develop a tool yourself. If you're an indie dev from a lower-income country contact me for a discount or free version.
Why should I pay money for this?
You save the time I invested. And you get a customizable solution with no running costs for a one-time fee. How much is that worth to you? With only a few offer codes converting it will pay for itself. And with the GitHub repo, you get updates without additional costs.
Does this only work for App Store offer codes?
It should work for distributing any kind of unique codes. Only the URL has to be changed.