9th September, 2021

How to embed audio from Anchor.fm on your WordPress.com blog

In lieu of a sane way to embed an Anchor.fm audio player into your WordPress.com-hosted blog, here's a solution that gives you something your listeners can hear.

After doing some research for an upcoming course on turning a blog into a podcast, I discovered that, contrary to what I’d assumed, you can’t embed the Anchor audio player for an episode into a blog post hosted on WordPress.com.

That’s because Anchor’s website isn’t configured correctly, and WordPress.com doesn’t allow you to paste arbitrary pieces of HTML code into its CMS for fear of that code getting hijacked (the latter is sane, the former is due to Anchor mostly being a toy, rather than a serious podcast hosting service).

The problem

As I mentioned, WordPress doesn’t want you posting “arbitrary HTML”. That means unchecked code that deviates from simple things like <p> paragraph tags, <ul> bulleted lists, <b> bold text, <a> links and so on.

If you want to embed content from sites like YouTube, you need to paste in code that looks like this:

<iframe width="560" height="315" src="https://www.youtube.com/embed/zTL4T_NVGhY" allowfullscreen></iframe>

That’s fine if the CMS knows the content is coming from YouTube. But if it’s a site the CMS doesn’t recognise, it will assume the code could be hijacked. What this means is that right now the code is legit, but if the hosting service goes out-of-business and someone else buys the domain, they can inject all sorts of malware, bitcoin mining code and other nastiness where that video player used to be. (Again, this isn’t a problem for big players like YouTube and Vimeo, but it does happen to smaller sites.)

So 10+ years ago, a group of developers came up with the oEmbed standard, whereby the URL to a piece of content can be turned into the code necessary to embed it. So CMSs maintained a list of known services that could be trusted, so if you pasted the URL to something from, say, Instagram, into a content block, the CMS would say “I know that’s an Instagram image; let me ask Instagram for the embed code”.

So far so good. But for whatever reason, Anchor isn’t in the approved list. Or it might be, I don’t know… as I said the problem lies at Anchor’s door; this is all just background context for fun. This is fun, right?

But that’s OK, since built into the oEmbed standard is the ability for discovery. This means that any URL in the world can declare its support for oEmbed, via a <meta> tag near the top of the webpage for an embeddable resource.

When I ran my old podcast hosting company, I implemented this across all episode pages, so that any CMS like WordPress, would know how to turn a seemingly arbitrary URL into a beautiful interactive audio player, with the podcast artwork and subscription buttons. Now because the CMS doesn’t know it can trust the resource, it can make changes to the <iframe> code to add extra security, effectively sandboxing the player so it can’t interact with any user data like cookies.

It’s stuff like this that gets me excited about the web, like when other apps and services like Slack, WhatsApp, and Notion started reading the <meta> tags used to tell Twitter and Facebook more about a webpage, thus making our links look much nicer when embedded into a message or a note.

oEmbed is a wonderful standard that opens up possibilities for a richer web experience, while keeping users safer and not just blindly trusting everything.

Anchor actually provides an oEmbed endpoint, so WordPress.com need not have any special rules to approve it. Except, certainly right now – and seemingly for a long time – the code Anchor generates is misconfigured.

Thanks CORS, I hate you too

CORS (cross-origin resource sharing) is a thing browser vendors and web developers cooked up to try and improve the way information is shared and security is handled across websites. It’s super-common for content from one website to include content from others, even if that content is invisible. If you’ve eve installed a Facebook “pixel” or some Google Analytics code, you’re pulling in resources from another website into yours. CORS is a set of instructions between those websites that sets out what can be linked to or shared from where.

What this means is if I try and embed the audio player using the oEmbed method (of creating an “embed” block in WordPress, or simply pasting the URL of the episode’s webpage), instead of seeing a pretty Anchor audio player, I see a blank void, and if I check my browser’s developer console I see this error:

Access to fetch at 'https://anchor.fm/api/compliance/region' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

This is nerd for “Anchor haven’t configured the player correctly. They haven’t told us which bits of content we’re allowed to pull into your website, so we’re just going to abandon the whole job.”

You’ll see a message like that in the developer console of any modern browser. (Actually, Firefox likes to make a point of being different so it shows the player, but gives a 404 error for no good reason.)

(CORS is a good solution to a knotty problem… it can just be an opaque pain in the bum sometimes, hence the snarky section heading.)

The solution

I’ve not been able to find a real solution to the problem that would enable the Anchor player to be embedded on a WordPress.com blog post. I investigated the <iframe> code the oEmbed service generates (which is perfectly fine and in working order), and even visited the URL to the player itself in my browser, and tried embedding that into the post. Nothing doing.