Subscribe to access all episodes. View plans →

#196: ReqEmbed

Published April 14, 2025

ReqEmbed

ReqEmbed docs

oEmbed format

Follow along with the episode starter on GitHub


Here we have a Phoenix LiveView application that lists Elixir YouTube episodes or at least that’s what we want it to do. Right now we’re just displaying the title. There are a couple different ways we could update our application to display our videos, but luckily for us YouTube supports the oEmbed format. oEmbed makes it easy to embed content, like videos, images, or different media, from one website in another by simply providing a URL. Let’s embed our Elixir YouTube videos using oEmbed.

To make it even easier we’ll use ReqEmbed, which is a plugin for Req to resolve and display oEmbed resources and was created by Leandro Pereira.

Let’s grab the config from Hex. And then let’s open our application’s Mixfile and we’ll add req_embed.

mix.exs

...
defp deps do
[
...
{:req_embed, "~> 0.2.1"},
...
]
...

With that we can go to the command line and install it with mix deps.get.

$ mix deps.get
...
New:
  req 0.5.10
  req_embed 0.2.1

Now let’s use it to make a request. We’ll start an IEx session with our application.

We can call Req.new to return a new request struct, which we can then pipe into ReqEmbed.attach to attach the oEmbed plugin into Req. Then let’s call Req.get! passing in our request struct. and then the URL of the resource we want to fetch - this will be the link to the YouTube video we want to display. And great - it returned the ReqEmbed.Video type for our video - “Intro to GenServer”.

$ iex -S mix
> req = Req.new() |> ReqEmbed.attach()
> Req.get!(req, url: "https://www.youtube.com/watch?v=C9iqVCcLbdU")
%Req.Response{
  status: 200,
  ...
  body: %ReqEmbed.Video{
    type: "video",
    version: "1.0",
    title: "Intro to GenServer",
    author_name: "Elixir Casts",
    author_url: "https://www.youtube.com/@elixircasts2332",
    provider_name: "YouTube",
    provider_url: "https://www.youtube.com/",
    cache_age: nil,
    thumbnail_url: "https://i.ytimg.com/vi/C9iqVCcLbdU/hqdefault.jpg",
    thumbnail_width: 480,
    thumbnail_height: 360,
    html: "<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/C9iqVCcLbdU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen title=\"Intro to GenServer\"></iframe>",
    width: 200,
    height: 113
  },
  ...
}

Now that we know it’s working, let’s integrate with our application to embed our videos.

We want to display the videos on the EpisodeLive.Show template, so let’s open that. ReqEmbed comes with a Phoenix Component to render your oEmbed content. It does require LiveView, but since we’re already using it in our application that wont be a problem. Let’s go ahead and add the component, using the @episode.url.

Template path: lib/teacher_web/live/episode_live/show.html.heex

...
<ReqEmbed.embed url={@episode.url} />
...

With that added, let’s go back to the command line and start our server.

$ mix phx.server
...

Now for our video to be displayed we’ll need to add it so let’s go ahead and edit our Episode…adding the YouTube link.

And now when we go to the episode’s “show” page. Perfect, our episode is displayed! It is a little small here, so let’s add a little styling around the video and we’ll use the class attribute to add some CSS to the <iframe> tag.

Template path: lib/teacher_web/live/episode_live/show.html.heex

...
<div class="relative w-full aspect-video">
  <ReqEmbed.embed url={@episode.url} class="absolute inset-0 w-full h-full" />
</div>
...

If we go back to the browser and refresh the page. Great, this looks much better! Now what if we didn’t want to use the ReqEmbed component and just wanted to render the oEmbed content as HTML? We can do just that with the html function.

Let’s go back to the show.html.heex and we’ll call ReqEmbed.html passing in the episode.url and we can use the class option to keep our styles the same. Finally we’ll need to wrap this in a call to the Phoenix.HTML.raw function for it to render in our template.

Template path: lib/teacher_web/live/episode_live/show.html.heex

...
<div class="relative w-full aspect-video">
  <%= raw(ReqEmbed.html(@episode.url, class: "absolute inset-0 w-full h-full")) %>
</div>
...

And if we go back to the browser and refresh the page - it looks great! We can now embed and play our Elixir videos from YouTube!

© 2024 HEXMONSTER LLC