Sublime Ads is a platform to allow you to manage and serve your very own ads in your own apps, on your websites, or other services using a simple API, or a lightweight drop-in JS script. You are in complete control on what you want to show, and how.
Everything is in one place and is easy to manage, no need to write your own custom solution. On top, Sublime Ads is privacy conscious to you and your users. Only taps/clicks will be registered for served ads and nothing else (can also be disabled per ad). I also don't use any tracking for the web application and other things, just like the internet is supposed to be.
Launched early 2021 as an MVP product to satisfy my very own needs as a developer with multiple apps and sites.
Last week I worked on finalising the password section for the web app. I thought I'll share some thought process behind the way I'm doing things.
When your first register for an account, on Sublime Ads, you will have a choice if you either want a magic link login or if you'd like to set your own password:
Magic links are one time links, sent to your registered email address that allow you to log into the site. They're only valid for 15 minutes and expire immediately once you've logged in.
Alternatively, if you don't want magic links, you can create a password of your choosing. Simple enough.
Password enforcement with a little bit of magic
When you create a password, you'll notice a lack of "this passwords needs to be at least 8 characters or longer, needs to contain a letter" blah blah blah.
No, you can't choose "password" or anything deemed insecure.
In fact, what I do, is check against the "have i been pwned" database to see if your password is secure.
"have i been pwned" (HIBP) is a popular service that allows you to look up any passwords that have previously been exposed in big hacks. It's a great indicator to see if your password is secure or not.
When you submit your password, the password is hashed. For example, the password "password" looks like this as a hash: 5f4dcc3b5aa765d61d8327deb882cf99
Now, I take the first five characters of the hash: 5f4dc
This hash is then sent to the HIBP API. The API then returns a number of entries with hashes that start with that exact hash.
With that list of entries I can now check, locally within the app itself, if the password you entered matches any of the items returned. In the case of the password "password" it will of course return results.
Just as a note, as you can see above, your password is never ever sent to HIBP.
So, if you try and enter a password that seems insecure and is in the HIBP database, the web app will tell you to choose another one.
I personally think that's a great compromise between strict enforcement and ease of use.
One-time passcodes
For anything going forward, I will make two-factor authentication mandatory for all my web apps that contain data of my users. This is for your and my protection.
On successful password create, either using magic links or a password, you will come up on the OTP screen - where you have to scan the code displayed on the screen.
Then I'll ask you to enter that code to proceed.
Your OTP code is used in various places throughout the app, for an extra layer of authentication.
Modern apps like 1Password all have this built in.
Password options after registration
In your settings, you'll be able to find the password module. It's quite simple and hopefully informative enough.
Human readable with clear options. In the screenshot above you can see that I'm using a password login on my local machine. That gives me several options. I can use magic links, or I can change my password.
If you have magic links enabled, you'll see the below:
One consistent option is to view your OTP QR code; the one you registered with. That's a special link, that will trigger an email to your verified email address. I didn't want to allow you to just get in that section without some sort of extra security step. Again this is a one-time link and expires within 15 minutes if not used.
Of note, the password section is disabled when your email address is not verified. That's most likely the case when you have just registered... and didn't click/tap on the verification email.
Changing or creating a password is similar to what you find when going through the registration steps.
Again I'll check against the HIBP database, as mentioned above. One extra step is to also enter your OTP code as I deem that a good security compromise.
Wording and design
In general I decided to use a bit more wording within the UI just to explain, clearly, what you have enabled or not. That includes any other aspects of the app too.
I'm constantly tweaking the wording too... I'm never happy.
On a side note again, the app can be localised easily as I've set it up correctly from the start, so I should be able to copy it across for any other language down the line.
On the design front, I kept away from too much clutter... not to cause too much eye strain. I think it's working so far and I'm happy with the results.
Closing thoughts
I understand that sometimes you may loose access to your devices and other things that include your authentication app.
I am planning on adding the ability to set up a recovery token, just in case you do loose access to your OTP code. Not 100% sure how I'll go about it yet as I need to make sure it's secure enough without my intervention.
However, I don't deem this necessary until after launch.
04:00 AM and I just finished the VAT logic for Sublime Ads. What a pain… but ultimately worth it. Works both ways, between Stripe and the web app itself. That was important for me.
As a business in the EU I have to make sure to charge relevant Tax/VAT/GST if subscribers are based in the EU. A bit of a pain to implement. Although super important, and I want to get it right.
Trying to display it nicely, if you are in the EU:
So yesterday was interesting. I spent all morning and afternoon integrating Paddle into Sublime Ads, but then it dawned on me it’s not really developer friendly and there is no way I can separate test orders with real orders. Turned out to be such a massive pain. I had to use my very own card, although with a free token. Eventually it just refused my card...
Then I figured out that all their invoice emails have click tracking and spy pixels. They’re using Postmark for sending emails, just like me. Click tracking is off by default… and that is how it should be kept.
I wanted to use Paddle because they act as a “Merchant of Record”, which is great for someone like me based in the EU. It means they are a reseller, as such, to my service/software. Which means they are responsible for accounting and declaring correct VAT and Tax collection with the tax man.
EU tax and VAT law is super complicated, heck I even have an accountant to do everything for me for my small client list. So having a service like Paddle would be great, as I don't have to deal with writing a program to generate correctly formatted invoices for my accounts.
Unfortunate that it didn't bring me developer happiness and also super unfortunate for a bad customer experience with the emails (tracking pixels and such).
So, what now you ask? Well, I'm using Stripe. They opened up to allow Polish based businesses to use the service last year.
I'm working on integrating it at the moment, with PROPER nice test payments and test cards - allowing me to trigger different scenarios.
On top, I decided to use their Checkout integration, which suits me super fine and I don't have to deal with extra implementation steps and headaches. As this is an MVP I'm building, I don't want to mess around. Stipe has super awesome developer tools, that work.
As you can guess, I was up for a very long time yesterday.
What works already:
Payments & subscribing
Changing card details
Cancelling
Cancelling everything when you delete your account
There are more things I need to integrate, especially for EU based customers, however I'm happy I got some of the basics done now - even though I died a little inside when I figured out Paddle just isn't there yet.
And if you're interested, here is the Stripe hosted checkout page:
I allow you to add your payment details at any time. So any trial days remaining will be passed to the payment screen without a fuss as long as you have more than 2 days remaining on your trial (it's a Stripe limitation, but I get it!).
As I'm EU based, I have to charge the correct VAT amounts for EU customers, so I will need to work on that next and make sure it all works as expected. Something I was hoping to avoid, but I'd rather do the work and get it right and not worry about shady business practices.
Whilst billing is super hard, I'm hoping I will have that section completed this week at some stage. Which means I can start work on the actual functional aspect of Sublime Ads... which are the ads.
One more screenshot of the Settings page for Sublime Ads. Fully functional, except password changing - working on it over the weekend. Super nice to work with Rails and Tailwind. It just works. Developer happiness!
Now that I finally announced Sublime Ads, I'll share some screenshot of the UI, specifically the Profile section in settings when you want to change your email.
Let’s talk about taking your mind off things. Last week I had the itch to start a long standing idea of mine. Not only to take my mind off things, but also to get out of my creative block with another project of mine.
Without further ado; Sublime Ads is a platform that allows you to host your very own ads within your apps, websites, or wherever else.
Think of it like the Overcast Ads platform that Marco built for his very own app, but for use for everyone - especially developers that want to have something like this, just like me. It can even be content creators or other creative folks - it really doesn’t matter.
Not only that, it is privacy focused from the start - from database encryption to only tracking (which can be disabled) taps/clicks on the ads. This data is just for your purpose, that you can communicate back to your potential advertisers. Apart from that, zero tracking. It’s built solely by me, has no funding and isn’t owned by a VC corporation!
The MVP challenge
There are many things I have planned, however my focus for the MVP (minimum viable product) are the total bare minimum features to make it useful for myself (and hopefully others).
Namely:
Upload ads with details
Categories for ads
Have a flexible API to get what I need via JSON, using an API key
A nice looking, and well working, web app
This is very bare and there are many things that I want to add, like a JavaScript drop-in for websites (that is privacy conscious and super lightweight!). However, the above gives me enough features that I need right now for my own things.
Achieving the above already is a full product that I would be happy to ship. Afterwards I can move where the puck is skating and play it by ear on what customers would like to see (like payment pages or Team accounts).
Timescales
I started last week and copied across the login and registration code that you can find on Picard.sh. Initially I teased at the idea of “one week” but it totally dawned on me that it’s way too short! I’m already obsessing over small details, which I’m totally trying to avoid now and writing down every single detail that I don’t need for the MVP. Although, I want to make sure it looks good at the same time.
It took me approximately a week to work on the Settings page, as there is a lot there to manage your account. So gauging from that, I want to say roughly one week for each section. That means the “Ads” screens, “Categories” screens and a basic homepage/dashboard.
That gives me 2 - 4 weeks to launch this. Which I think is a good balance between everything that is going, client work and other commitments.
I think that is a reasonable timescale to say the least.
Testing
Initially I want to open it as a beta, for a few people to try and give feedback on. Even if you’re not interested in the product itself, but you feel like giving it a try and have a keen eye for things.
Just like Gluon, I envision Sublime Ads to be built in similar light with help from the user base and community.
So, 2 - 3 weeks… and I hope I can start inviting!
Another project?
Yes, I’m aware I wanted to have another web app project out the door already. However I’ve been busy with client work and then immediately fell into creative block on the project. Not only that, it dawned on me that Picard.sh is a very complex project. We’re all in a very complex life change at the moment and the thought of having to work through Picard, with many unknowns and super complexity, would just not sit well right now.
Saying that, it’s not all wasted. I already took most of the Login and Registration logic from Picard and am using it in Sublime Ads.
With Sublime Ads being built out, I’m hoping to use the general design and transplant that back into Picard. So in a way I’m working on both projects at the same time. Sublime Ads gives me a more immediate remedy of something I want, whilst also giving me the direction and drive I need for Picard.
Technicals
Sublime Ads is built with Ruby on Rails using your classic server side HTML rendering (like it’s supposed to be), with a bit of tiny JS sprinkled on top for niceness. At this point there is no JS outside of the out-the-box that you get with Rails. The front-end is built on Tailwind CSS. I can only recommend it because it gives me flexibility and speed - not to mention cross browser peace of mind. Payments will be handled via Paddle, just to make it easier for me as I don’t want to deal with the headache that is accounting and tax/VAT/GST!
Find out more
Enough reading. You can find the Sublime Ads website here and you can sign up for a beta invite if you want to give it a try when it’s ready (even if you just want to tell me how bad it is!). Don’t worry, no third-party email list and zero marketing. It’s all handled in-house by myself.
There is also my usual dedicated development blog, which you can find here. That will be updated regularly… and you can see a few posts there already.
More updates soon with juicy screenshots.
I’m going to announce my little side project a little later today, doesn’t mean you can’t go to my website and get a good overview of what it is. I’ve been working on the web app all week and have loads of blog posts to share already.
I’ll announce more stuff tomorrow… but here is a little screenshot of the settings page for my little MVP web app.
Just casually working on something 🤪👨💻
I was puzzled why my code was throwing an error when I tried to access a new model for the logged in user. I typed `.erb` instead of `.rb` at the end of the filename… I guess I’m tired and should go to bed.
I feel like creating an MVP web app this week. As in… work on basic features that I wrote down, write the code, do the frontend and ship. One week. Think I should do it? I would naturally blog about it.
Just to keep my mind busy, I’ll be announcing yet another personal project that I’m working on. Hope to share more next week. It’ll be a web application. Aimed mainly at developers, creators and small businesses that have their own apps and sites.