Vincent Ritter

< back to projects

Sublime Ads

A privacy focused ad management service for your apps, websites and others.

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.

Launching as an MVP product, very soon, to satisfy my very own needs as a developer with multiple apps and sites.

Visit the website here.

Project posts

The billing section is now complete on Sublime Ads, which means I can move onto Ads and Categories 🥳 I’ll be doing a longer blog post about billing a little later in the week.

Added a dedicated “Cancel” section for Sublime Ads. It’s important!

Ooo, didn’t know you can delete ALL of your test data in Stripe:

I worked on invoices last night for Sublime Ads. Just finished the styling part too. Billing has been a long road, but it’s there now!

One of the details in Sublime Ads are the subtle wording changes throughout the app, for example: depending if you had a paid subscription, or if you’re still within the trial period, the wording differs when you cancel:

"Your subscription is active but will be cancelled on May, 11th 2020. No payment will be taken.” turns into:

"Your subscription is active but will be cancelled at the end of current billing cycle, on May, 11th 2020.”

Hoping to keep this trend up as I go. So far so good.

Knowing me, I’ll change most of the wording even more as I go. I kinda like that part.

Some more UI details for Sublime Ads when you have cancelled your subscription:

It will remain active until the last day of the billing cycle and you can resume any time. If you’re navigating around, you’ll see this in the header:

Clicking on that will take you to billing.

I was thinking about pricing for Sublime Ads… I’m going to have just one plan, to keep it simple, which then increases in price over the course of time. Everyone that subscribes will always be locked into the price when they signed up. I think that’s fair.

I spent much of all week on getting Stripe integrated into Sublime Ads. I didn’t want to use a third-party gem. It’s great to learn the Stripe ways.

I don’t have the invoices ready yet, but here we go - happy that I got that far. Of course I’ll be changing wording etc.

Sublime Ads - Password logic and design choices

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:

Sublime Ads - Choosing, and then changing, payment providers.

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:

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.

Introducing my short MVP project challenge, Sublime Ads.

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).


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).


I started last week and copied across the login and registration code that you can find on 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.


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 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.


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.