Today we are gonna learn why and how I built a podcast platform from scratch and decided to make it available to the public. Meet DueCast. 🎙

To start things off I’d like to precise that I’m not really a podcast enthusiast myself. Even though I might listen to one from time to time like Too Embarrassed To Ask by Recode; I am neither a hardcore user of podcasts nor a podcaster. Consequently, the world of podcasting was quite blurry for me. I had to learn a lot to get up to date with the subject. . . So why did I make DueCast? Well, follow me!

The problem

Let me paint a picture for you. The scene takes place, well, last week. We were talking on a group with some Internet-friends. Everything was fine. We were all joking about DueWork* and making play on words with the Due+Whatever pattern such as DueBénéfice (“some profit”, in French) or the very clever DueBonTravail (“some good work”, in French also). Anyway. To put on some context, many people on this group are customers of DueWork for their website hosting (DueHost) or mail service (DueMX).

Jokingly, someone, that coincidentally owns a podcast, told me the price he is paying each month to have his podcast hosted. I just stopped when I read “$12” in his message on Telegram. Twelve. Whole. Dollars. To host 30 MB of data, provide an RSS feed that is Apple Podcasts compliant and some not-really amazing web interfaces. I just couldn’t stand him paying this much so I told him he was being scammed . . . to what he simply replied:

"Just build a service to host my podcast that is cheaper than my actual provider and I’ll use it.”

As someone very close to me—VERY CLOSE as he shares this Ghost instance (yes, that’s to say)—very accurately pointed out to everyone else in the group: you don’t just say something to me. Why? Because if I can, if it’s smart and if I’m interested, I’ll do it.

Soooo . . . undeterred . . . the deadline being August 1st, day at which my client’s current contract renews, I started working.

Where to start: is there a choice?

Everybody has their habits. I do too. That’s why I didn’t ask myself many questions before starting up. I directly envisioned what tools I’d use to make this service run:

  • my own SSO (Single Sign On) service DueWork ID to authenticate users: saves me the trouble to do that in PHP and also benefits the end user that shares the same credentials across the whole DueWork ecosystem;
  • pure HTML at first and then Bootstrap or any other framework for the visuals and user-faced functions (HTML/CSS/JS): saves me the trouble of throwing myself off a cliff doing CSS;
  • PHP with Apache for the server side on DueHost: saves me nothing but it's here so I'm using it;
  • Composer for PHP: to make easy the importation of third-party libraries;
  • MySQL for the database: I'm not a fan, but again, it's already here and it saves me the trouble to install PostgreSQL;
  • my favorite IDEs from JetBrain (PHPStorm and DataGrip): saves me from using the horrendous phpMyAdmin and keeps me in the IntelliJ universe;
  • DueWork Git, an enterprise version of GitLab I self host: so that I control everything;
  • Stripe, a payment processor: to guarantee the security of the credit cards and to manage subscriptions;
  • and finally Pixelmator Pro for the graphics and the logos: yes, people, this is also important.

Now that you know the technical stuff, let’s get to what I actually made.

Being visible: the interfaces

Human interfaces . . . a whole concept. Design? That’s another one. Both of them are what constitutes the nightmares of hardcore developers that simply cannot see past the back end. Luckily, I am not one of them. I enjoy clear interfaces which go to the point but are also useful and beautiful.

Just because I won’t use a service that does not provide a correct user interface and/or experience and because the idea of starting a podcast is starting to maturate in my mind: I needed to do it right that for DueCast. . . Let’s see the results, shall we?

As you can see above, the homepage remains clear while still informing visitors sufficiently about what this service offers and redirecting them on appropriate pages if more information is needed.

Then, it’s time for the author’s page and the main podcast’s page. The first one is very simple and references some social media from the author, his or her name, a quick description and the list of all the owned podcasts. The second one is a little bit more complex and features in a JumboTron social links for the podcast, as well as the author, the RSS feed, the name of the podcast. Below it, two sections.

The section on the right is the one featuring the main podcast cover (because, yes, you can have a specific cover for a particular season, that’s a thing) and the description.

A podcast page example

The section on the left meanwhile contains the trailer of the podcast (if present) and a list of the episodes from the podcast, ordered by season, with a quick description and a play button. The latter button, once clicked, opens a sticky player on the bottom of the page. It’s not yet persistent between pages but I’ll see maybe later on how to make it work like that. For now, we’ll say it’s sufficient.

Each episode also has its own page. It displays the season cover (or the default podcast cover if no one is specified) and the full description for the episode as well as the play button.

An episode’s page—with the sticky player open

It’s important to note that each text section (being the podcast or episode description) fully supports Markdown as input method in the back end and is interpreted on the fly by PHP. This way, podcast owners can put emphasis on elements with ease.

Finally, as you can see above, are the about page and the pricing/join page. Both of those pages are still under construction but it gives you a sense of the simplicity and honesty I want to pass on to the users. . .

Being visible, in an other way: the RSS feed

That’s just the beauty of podcasts. You can listen to them pretty much anywhere. The only rule is that as long as you have a valid RSS feed, your podcast can be listened to.

Generally, to make it easier for future listeners, we add podcasts to popular libraries (apps/sites that distribute podcasts). Generally, you post your feed once or twice, at Apple most frequently, and every other services will pull it from the Apple Podcasts catalog and add it to their own.

An excerpt from the RSS feed of a test podcast I made (prototype)

Considering the dozens of podcast apps these days that can’t stop to pop out of nowhere, that’s at least something else to worry about. However, RSS is a strict markup language and most of these “final services” like Apple or Google Podcasts require specific tags for their own usage. Sometimes it can induce duplicates but those are required if you want your podcast to be processed correctly. . .

Everything is generated on the fly, at each request so that the information at the origin is always up to date. If an information is not available in the database (such as audio file duration), the functions behind the feed retrieve them and add them to the database to make future requests faster. Smart!

Being in the known: the analytics

Tracking an audio play is tricky. As a start of solution, I started by creating a page, a little like a proxy page. It acts as an intermediary between the mp3 files and the requests. This way I can query my database to insert all the necessary tracking information I collected and then serve the real mp3 file with a basic header redirection.

I wish it was that easy. But it wasn’t quite that easy. Remember the “tricky” part? Well, I quickly figured out even it is even more so when you need Apple to validate your RSS feed. The real hassle was that Apple makes a request with the HEAD method in order to get metadata on the file without having to download the latter entirely. What a great idea! (No, really, it is, though.)

A little description of the HEAD method, just so you know, because I didn’t

To solve this problem seen by feed validators as my server couldn’t serve HEAD requests (which it can do), I added a way to pull the local mp3 file on the server, on the same proxy page, and added headers from the polled audio file metadata. And wouldn’t you know it, it worked! Now you know. . .

I did NOT want to be collecting unnecessary data for analytics to work and be performant. That’s why, at each click or play of a podcast episode, the country is retrieved from the IP and only the name of the country is inputted in the database, along the episode special hash (its id), user agent and the timestamp. Nothing more. 🤓

Quite pleasing, no? It’s powerful yet simple and elegant. Like me. You can see everything that matters, at a glance, from the first page of your admin panel, for all your podcasts, at once. Neat!

The administration panel. No, the Studio!

Yes, I could have called it the admin panel, or the account manager. But no, I decided to give this section some voice (see what I did there?) and call it the DueCast Studio. From there, a podcaster owner can manage . . . well, his or her podcast, the individual episodes or seasons and learn about their audience with relevant analytics (for which you’ve already seen some images).

Everything is still a work in progress and subject to change with the input of the real end users: podcast authors that use the service regularly. . .

Naming scheme and navigation

For a podcasting platform, where the author will be sharing his or her content with the world, we want something coherent. I had two choices for URL formatting:

  1. Reserve some links for internal use (like /login or /studio) and let podcasts use the root space for their ID for a result resembling cast.duework.org/{my-podcast-id} or;
  2. Adopt the same schema as LinkedIn or Reddit and apply an intermediary (like /p/ or /u/) to get something this form: cast.duework.org/p/{my-podcast-id}.

I ended up using the second option because it is in my opinion clearer for the end user (and a little easier to implement, I'm not gonna lie).

To share content, users just need to follow those schemes on DueCast:
cast.duework.org/podcast/{my-podcast-id} or
cast.duework.org/p/{my-podcast-id}

cast.duework.org/episode/{sha256} or
cast.duework.org/e/{sha256}

...and so on for widget (embeddable content), listen (direct URL to the mp3) and author (self-explanatory).

Leveraging the power of Cloudflare®: caching and more

It is known by anybody close to me that I love what Cloudflare is doing and that I’ve been a client since the early days . . . or the days responsive websites weren’t a thing. Indeed, you can still check out a post I made in 2015 regarding the usage of Cloudflare with one.com.

Anyway, what’s Cloudflare? It’s a CDN, a DDoS mitigator, a WAF and more . . . all in the cloud, acting like a giant reverse proxy for your website. The goal is simple: focus on your origin and let Cloudflare’s edge handle security, caching and acceleration for you. It really is hardware in the cloud.

Can we please take a moment to appreciate my graphic design skills?

For DueCast especially, the problem was simple. The service is going to gradually handle more and more audio files and I plan to target a global audience. Relying on a single origin (DueWork infrastructure based in France) isn’t really efficient. The aforementioned origin is going to be handling every hit of the audio files and static content and, of course, serve dynamically generated pages.

Let’s make up a quick scenario. Imagine DueCast took off, I have 15 podcasters (what a take-off, are we flying a private jet or what?—shhhh, focus!) and each podcaster has on average 30 episodes. Each episode (mp3 encoded) is, on average again, roughly 15 MB. That already takes us to a staggering 6.59 GB of storage space. Now, I haven’t talked about the audience and performance just yet. Let’s say each podcaster, has, across each of their podcasts 1,000 plays per episode per month. Roll that mental calculus and . . . oh god. 6,592 GB. Almost 6.5 TB of bandwidth each month coming out of this infrastructure. That’s. That’s a lot.

Almost six point five terabytes of data transferred each month . . . just imagine!

I know it does not make real sense, but you get it. It can really become something uncontrollable in the end. Even more so when you have a limited bandwidth at your origin. I do not in France, but I think about other people, okay?

That’s where Cloudflare shines and help us reduce our imaginary bandwidth bill. Indeed, in lieu of serving all audio files and other static files from the origin (DueWork servers), each requested is served from the edge (Cloudflare servers). This would account for massive savings in bandwidth if I was subjected to them and is a game changer for latency. Why? Well, because of serving content from one origin in France, it is delivered by the closest region (understand here the Cloudflare server location) closer to the client. At - no - charge.

Excuse me, what?

You heard right. And I can’t believe this is still free! Well, I can. Cloudflare said it was—and still is—their philosophy and why they started the company: to protect small websites that can’t afford acceleration and protection from big names in the field. So, yeah. I am rocking the free tier of Cloudflare on 10+ websites and they are doing more than fine.

The final product

One week. That’s what it took for me to create a fully fledged podcast platform at the requirements of my client. We have, low monthly fee, CDN delivery, country and device analytics for each audio play, episode performance review, an admin panel that is responsive and beautiful, a simple yet elegant interface for the listener-side website, functional search for discovery . . . and more! Oh and I almost forgot this shiny widget that can be embedded anywhere basic HTML is supported:

I know, right! This is kind of amazing. I wouldn’t’ be honest if I told you that I’ve done similar things many times. Indeed, making an administration panel that works, with dynamic analytics nevertheless, is an achievement for me I did not foresee. I did play with PHP last year by making my own microblogging platform similar to Twitter but with an edit button. Do take it personally, Twitter.

In the end, the client that commissioned this work is more than happy with the results and impressed with the quality, feature set and just how fast I made it work. In truth, when you compare the flat monthly fee of €7.99 I fixed for DueCast to the one its previous provider—Ausha—exercised, which is $12, it just seems dishonest to me to make people pay for more. More so when you can put a price on processing and storage. I’ll see how the pricing evolves with time and clients but it should be quite enough.


· · ·

Don’t forget to check it out now and maybe consider subscribing if you are in the business of starting or moving your podcast! I am always learning, so if you have a suggestion, do not forget to shout it at me. Take care. 😄

*The name of the entity under which I operate the many services (including custom solutions) I offer to the public and that also syndicates my media activities. Learn more