# `ReqEmbed`
[🔗](https://github.com/leandrocp/req_embed/blob/v0.3.14/lib/req_embed.ex#L1)

[Req](https://hex.pm/packages/req) plugin for [oEmbed](https://oembed.com).

## Features

* **Auto-Discovery**: Finds oEmbed endpoints via HTML link tags ([oEmbed discovery](https://oembed.com/#section4))
* **350+ Providers**: YouTube, Twitter, Instagram, and [more](https://github.com/leandrocp/req_embed/blob/main/priv/providers.json)
* **Content Types**: Video, Photo, Rich media, and Link embeds
* **Phoenix Ready**: HEEx component and HTML helpers
* **Customizable**: CSS classes, responsive design, and embed options

## Installation

Add `:req_embed` dependency:

```elixir
def deps do
  [
    {:req_embed, "~> 0.2"}
  ]
end
```

Or use [Igniter](https://hexdocs.pm/igniter):

```sh
mix igniter.install req_embed
```

## Usage

req_embed can be used directly as a Req plugin, or as a Phoenix component to render oEmbed content in HEEx templates.

### Intro

Watch this [ElixirCasts episode](https://elixircasts.io/reqembed) that covers all the features listed below.

<a href="https://elixircasts.io/reqembed">
  <img src="https://raw.githubusercontent.com/leandrocp/req_embed/refs/heads/main/assets/elixir_casts.png" width="512" alt="ElixirCasts Episode 196" />
</a>

### Req Plugin

```elixir
req = Req.new() |> ReqEmbed.attach()

Req.get!(req, url: "https://www.youtube.com/watch?v=XfELJU1mRMg").body
#=>
# %ReqEmbed.Video{
#   type: "video",
#   version: "1.0",
#   title: "Rick Astley - Never Gonna Give You Up (Official Music Video)",
#   author_name: "Supirorguy508",
#   author_url: "https://www.youtube.com/@supirorguy5086",
#   provider_name: "YouTube",
#   provider_url: "https://www.youtube.com/",
#   cache_age: nil,
#   thumbnail_url: "https://i.ytimg.com/vi/XfELJU1mRMg/hqdefault.jpg",
#   thumbnail_width: 480,
#   thumbnail_height: 360,
#   html: "<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/XfELJU1mRMg?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=\"Rick Astley - Never Gonna Give You Up (Official Music Video)\"></iframe>",
#   width: 200,
#   height: 113
# }
```

When successful, the response body will contain either one of the following structs representing the oEmbed type:

  - `ReqEmbed.Link`
  - `ReqEmbed.Photo`
  - `ReqEmbed.Rich`
  - `ReqEmbed.Video`

Provider-specific response fields are preserved in the struct's `:extra` map.

### Phoenix Component

Use [ReqEmbed.embed/1](https://hexdocs.pm/req_embed/ReqEmbed.html#embed/1) to display oEmbed content in HEEx templates:

```heex
<ReqEmbed.embed url="https://www.youtube.com/watch?v=XfELJU1mRMg" class="aspect-video" />
```

Renders:

```html
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" class="aspect-video" frameborder="0" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/XfELJU1mRMg?feature=oembed" title="Rick Astley - Never Gonna Give You Up (Official Music Video)"></iframe>
```

Note that `:phoenix_live_view` is required to use the component, it's not a direct dependency.

### Raw HTML

Or alternatively use [ReqEmbed.html/2](https://hexdocs.pm/req_embed/ReqEmbed.html#html/2) to get the oEmbed content as HTML:

```elixir
ReqEmbed.html("https://www.youtube.com/watch?v=XfELJU1mRMg")
# <iframe width="200" height="113" src="https://www.youtube.com/embed/XfELJU1mRMg?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="Rick Astley - Never Gonna Give You Up (Official Music Video)"></iframe>
```

Wrap it in a `{:safe, html}` tuple or call `Phoenix.HTML.raw/1` to render it in Phoenix templates.

# `attach`

```elixir
@spec attach(Req.Request.t(), keyword()) :: Req.Request.t()
```

Attach the oEmbed plugin into Req.

## Options

  * `:query` (`t:map/0`) (optional, default: `%{}`) - The query parameters to be sent to the oEmbed endpoint,
    like `:maxwidth`, `:maxheight`, and others supported by the provider.
    The parameters `:url` and `:format` are managed by the plugin, you can't override them.
    See section [2.2 Consumer Request](https://oembed.com/#section2) for more info.

  * `:discover` (`t:boolean/0`) (optional, default: `true`) - When enabled, it will first attempt to auto-discover
    the oEmbed endpoint by looking for the link tag in the HTML response. If no link tag is found, it will
    fallback to searching for a known provider endpoint. When disabled, it will skip the HTML parsing step
    and only use the known provider endpoints.

## Examples

    iex> req = Req.new() |> ReqEmbed.attach()
    iex> Req.get!(req, url: "https://x.com/ThinkingElixir/status/1848702455313318251").body
    %ReqEmbed.Rich{
      type: "rich",
      version: "1.0",
      author_name: "ThinkingElixir",
      author_url: "https://x.com/ThinkingElixir",
      html: "<blockquote class="twitter-tweet"><p lang="en" dir="ltr">News includes upcoming Elixir v1.18 ...
      ...
    }

  Supports redirects too:

    iex> req = Req.new() |> ReqEmbed.attach()
    iex> Req.get!(req, url: "https://flic.kr/p/SHA4VC").body
    %ReqEmbed.Photo{
      type: "photo",
      version: "1.0",
      title: "Above the cloud",
      author_name: "tomms",
      author_url: "https://www.flickr.com/photos/tomms/",
      thumbnail_url: "https://live.staticflickr.com/665/33288461746_67348617ea_q.jpg",
      url: "https://live.staticflickr.com/665/33288461746_67348617ea_b.jpg",
      ...
    }

# `embed`

Phoenix Component to render oEmbed content.

Requires [phoenix_live_view](https://hex.pm/packages/phoenix_live_view) to be installed,
otherwise you can use `html/2` directly. This component is essentially a wrapper for `html/2`.

## Examples

    <ReqEmbed.embed url="https://www.youtube.com/watch?v=XfELJU1mRMg" />

    <ReqEmbed.embed
      url="https://x.com/josevalim/status/1793946517390458957"
      class={@embed_class}
    />

    <ReqEmbed.embed
      url="https://www.flickr.com/photos/example/123456789"
      include_caption={true}
    />

## Attributes

  * `url` (`t:String.t/0`) (required) - URL of the resource to be embedded.
  * `class` (`t:String.t/0`) (optional) - CSS class to be added into the `<iframe>` tag. Note that when used, it removes both `width` and `height` attributes.
  * `include_caption` (`t:boolean/0`) (optional, default: `true`) - When enabled, it will include the photo title in `<figcaption>`.

# `html`

Render the oEmbed content as HTML.

## Options

  * `:class` (`t:String.t/0`) (optional, default: `nil`) - CSS class to be added into the `<iframe>` tag, if used it removes both `width` and `height` attributes.
  * `:include_caption` (`t:boolean/0`) (optional, default: `true`) - When enabled, it will include the photo title in `<figcaption>`.

## Examples

    iex> ReqEmbed.html("https://www.youtube.com/watch?v=XfELJU1mRMg")
    <iframe width="200" height="113" src="https://www.youtube.com/embed/XfELJU1mRMg?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="Rick Astley - Never Gonna Give You Up (Official Music Video)"></iframe>

Replace the `width` and `height` attributes with a CSS class:

    iex> ReqEmbed.html("https://www.youtube.com/watch?v=XfELJU1mRMg", class: "aspect-video")
    <iframe class="aspect-video" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" frameborder="0" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/XfELJU1mRMg?feature=oembed" title="Rick Astley - Never Gonna Give You Up (Official Music Video)"></iframe>

Wrap it in a `{:safe, html}` tuple or call `Phoenix.HTML.raw/1` to render it in Phoenix templates.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
