What is oEmbed?

A simple, open protocol that lets any website display rich previews of URLs — videos, images, tweets, and more — without scraping or custom integrations.

The problem oEmbed solves

Imagine you're building a blog, CMS, or chat app. A user pastes a YouTube link. You want to show the embedded video, not just a raw URL. But YouTube has its own embed format. So does Vimeo. And Spotify. And Flickr. And hundreds of other services.

Without a standard, you'd need custom code for every provider. oEmbed eliminates that. It gives every provider a single, predictable API that any consumer can call to get embed information for a URL.

How it works

The oEmbed protocol defines two roles: a provider (the site that hosts content, like YouTube) and a consumer (the site that wants to embed it, like WordPress). The flow is simple:

1
User pastes a URL

A consumer encounters a URL, e.g. from user input or a feed.

2
Consumer calls the API

The consumer sends an HTTP GET to the provider's oEmbed endpoint with the URL as a parameter.

3
Provider returns embed data

The provider responds with JSON (or XML) containing titles, thumbnails, and embed HTML.

# Example: fetching oEmbed data for a YouTube video
GET https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ&format=json
{
  "type": "video",
  "version": "1.0",
  "title": "Rick Astley - Never Gonna Give You Up",
  "author_name": "Rick Astley",
  "author_url": "https://www.youtube.com/@RickAstleyYT",
  "provider_name": "YouTube",
  "provider_url": "https://www.youtube.com/",
  "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
  "thumbnail_width": 480,
  "thumbnail_height": 360,
  "html": "<iframe src=\"https://www.youtube.com/embed/dQw4w9WgXcQ\" ...></iframe>",
  "width": 200,
  "height": 113
}

The four response types

Every oEmbed response has a type field. The type determines which additional fields are available and how the consumer should render the content.

photo

A static image. The consumer displays it directly using the provided URL and dimensions.

Required: url, width, height

video

A playable video. The response includes an HTML snippet (usually an iframe) the consumer can embed directly.

Required: html, width, height

rich

Generic rich content (tweets, posts, maps, etc.). Like video, it provides an HTML snippet for embedding.

Required: html, width, height

link

A simple link with metadata. No embed HTML — the consumer renders a card or link preview using the title and thumbnail.

No type-specific required fields

Response fields

All oEmbed responses share a set of common fields. Only type and version are always required. Everything else is optional (unless the type demands it).

Field Type Description
type string required One of: photo, video, rich, link
version string required Always "1.0"
title string Title of the resource
author_name string Name of the content author
author_url string URL of the author's profile
provider_name string Name of the provider (e.g. "YouTube")
provider_url string URL of the provider's homepage
thumbnail_url string URL of a thumbnail image
thumbnail_width number Width of the thumbnail in pixels
thumbnail_height number Height of the thumbnail in pixels
html string HTML embed snippet (required for video and rich types)
width number Width in pixels (required for photo, video, rich)
height number Height in pixels (required for photo, video, rich)
url string Source URL of the image (required for photo type)

Discovery

How does a consumer know which endpoint to call? There are two mechanisms:

1. Provider registry

A central list of known providers, their endpoints, and the URL patterns they support. The consumer checks the URL against registered schemes (e.g. https://www.youtube.com/watch?v=*). This is the most common approach and what services like our provider directory catalog.

2. Link-tag discovery

Providers can also embed a <link> tag in their HTML pages that points to the oEmbed endpoint. The consumer fetches the page, finds the tag, and follows it.

<link
  rel="alternate"
  type="application/json+oembed"
  href="https://example.com/oembed?url=https://example.com/post/123"
  title="My Post Title"
/>

You can test both mechanisms using our Discovery Checker.

Request parameters

When a consumer calls a provider's oEmbed endpoint, it sends these query parameters:

Parameter Required Description
url required The URL to retrieve embed information for
maxwidth optional Maximum width of the embed in pixels
maxheight optional Maximum height of the embed in pixels
format optional Response format: "json" or "xml" (default varies by provider)

Implementing oEmbed

Consumer
  1. 1. When you encounter a URL, check it against the provider registry to find a matching endpoint.
  2. 2. If no match, optionally fetch the page and look for <link> discovery tags.
  3. 3. Send a GET request to the endpoint with the URL (and optional maxwidth/maxheight).
  4. 4. Parse the JSON response and render based on the type field.
  5. 5. Cache the response — oEmbed data rarely changes.
Provider
  1. 1. Create an endpoint (e.g. /oembed) that accepts a url query parameter.
  2. 2. Validate the URL belongs to your domain and maps to real content.
  3. 3. Return a JSON response with the required fields for your content type.
  4. 4. Add <link> discovery tags to your HTML pages.
  5. 5. Register your provider in the official oEmbed registry.

Security considerations

  • ! Sanitize HTML. The html field can contain arbitrary markup. Always sanitize or sandbox it (e.g. in an iframe with restricted permissions).
  • ! Validate URLs. Ensure returned URLs use HTTPS and point to expected domains. Don't blindly trust provider responses.
  • ! Respect maxwidth/maxheight. As a provider, honor dimension constraints. As a consumer, always set them to prevent oversized embeds.
  • ! Use allowlists. Only fetch oEmbed data from known, trusted providers to prevent SSRF and data exfiltration.

Try it yourself

Use our developer tools to see oEmbed in action.