Features
Video and audio embeds
Turn YouTube, Vimeo and Spotify links into safe players, with the preview card, activateEmbeds, server checks and CSP settings.
@viveeditor/ext-embed turns YouTube, Vimeo and Spotify links into players. The saved HTML never keeps the address it was given; it stores only the provider and the video id, and every player address is rebuilt from them. This page covers setup, loading players on the published page, and the server and Content Security Policy settings.
Setup
import { Editor } from '@viveeditor/core'
import { Embed } from '@viveeditor/ext-embed'
import '@viveeditor/ext-embed/style.css'
const editor = await Editor.create(document.querySelector('#editor'), {
extensions: [Embed.configure({ providers: ['youtube', 'vimeo'], facade: true })],
})
The one-script build already includes the extension with all three providers.
| Option | Default | Description |
|---|---|---|
providers |
['youtube', 'vimeo', 'spotify'] |
The enabled providers. |
facade |
false |
With true, the saved HTML holds a link instead of a player. |
pasteToEmbed |
true |
Turns a link pasted on an empty line into a player. |
maxEmbeds |
50 |
The maximum number of players in one document. |
labels |
English | Labels for the play button and for unsupported content. |
Add a video
- Paste just the link on an empty line. It turns into a player; one undo turns it back into a link.
- Press the video button in the toolbar or the “Video” entry in the
/menu. Enter the link and a title in the panel; screen readers announce that title. - In code, use
editor.commands.insertEmbed(url)to insert andeditor.commands.setEmbedTitle(title)to change the title.
Inside the editor a card stands in for the player, with the provider name, the title and a play button. Nothing loads from the provider until play is pressed.
Supported links
| Provider | Accepted links | Player address |
|---|---|---|
| YouTube | youtube.com/watch?v=…, youtu.be/…, /shorts/, /live/ and /embed/ addresses; start time from t or start |
www.youtube-nocookie.com |
| Vimeo | vimeo.com/…, addresses with the private key of unlisted videos, player.vimeo.com/video/…; start time from #t= |
player.vimeo.com, with dnt=1 |
| Spotify | Track, album, playlist, episode, show and artist addresses on open.spotify.com |
open.spotify.com/embed |
Links are parsed as addresses and the host name is compared exactly. Short links and redirects are never followed, and nothing is requested from the provider.
Saved HTML
The player is always rebuilt from the provider and id; sandbox, allow and referrerpolicy are fixed and never read from the content. The saved HTML holds a div[data-embed] wrapper in one of two forms:
facade: false(default): the wrapper holds the playeriframe. The player loads from the provider when the reader opens the page.facade: true: the wrapper holds a link to the video’s page at the provider. The player loads when the reader clicks.
When you save as Word or Markdown, players are written as links.
Publish facade output
On the page that shows content saved with facade: true, call activateEmbeds(). Clicking the link replaces it with the player and starts playback:
import { activateEmbeds } from '@viveeditor/ext-embed/activate'
activateEmbeds(document.querySelector('article'), { providers: ['youtube', 'vimeo'] })
The first argument is the root element to search (the whole document if left out), and providers lists the allowed providers. The player address is built from the provider and id on the wrapper, never from the link’s href. Without activateEmbeds, the link opens the video on the provider’s site.
On the server
- Clean the HTML on the server too, but never allow every
iframe. Passembeds: trueto@viveeditor/sanitize; players are rebuilt from the provider and id. See Server sanitizing. - With your own sanitizer, rebuild players from
div[data-embed], or accept only addresses for whichisAllowedEmbedSrc()returnstrue.
import { isAllowedEmbedSrc } from '@viveeditor/ext-embed'
const allowed = isAllowedEmbedSrc(src, ['youtube', 'vimeo'])
isAllowedEmbedSrc checks that the address is exactly the player address the editor builds. In the same package, matchEmbedUrl(url) reads the provider and id from a link, and buildEmbedSrc(attrs) builds the player address. None of the three needs a browser DOM.
Content Security Policy and privacy
- List only the providers you enabled in your CSP
frame-src. With all three:frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://open.spotify.com. - A player loads content and cookies from the provider. Tell readers about it where your consent rules require it; facade output loads the player only after a click.
Referrer-Policy
A page-wide Referrer-Policy: no-referrer stops YouTube players from working. This is why players are built with strict-origin-when-cross-origin.
For the other CSP settings, see Security and CSP.
Why does the video not load right away in the editor?
Inside the editor a card stands in for the player. Nothing loads from the provider until someone presses play, which protects the writer's privacy and keeps the page light.
Can I embed videos from other sites?
No. Only YouTube, Vimeo and Spotify are supported. Other links are not turned into players, and the panel lists the supported providers.
My page sends Referrer-Policy no-referrer. Why does YouTube not work?
YouTube rejects embedded players that arrive without a Referer. A page-wide no-referrer policy stops YouTube players from working.