Almost every WordPress site starts with video the same way. You drag the file into the Media Library, drop a Video block into the post, and publish. For a two minute clip on a quiet page, that is a complete answer, and it costs nothing beyond the disk you already pay for.
The size ceiling is where it stops. Your host caps uploads somewhere between 8 MB and a few hundred megabytes, and WordPress prints that number on the Media screen under "Maximum upload file size". A phone recording of a workshop passes it inside the first few minutes of footage.
There are four routes onto a WordPress page and they are not interchangeable. Each decides who serves the bytes, who owns the audience, and what a visitor on a slow connection sees. This guide walks all four with the markup each produces, then shows you how to read a page's source and tell which route it already uses.
TL;DR
Four routes put video on a WordPress page. A Media Library upload is free and native, and it dies at your host's upload ceiling. An oEmbed hands the video host your branding, your recommendations, your analytics and the takedown switch. A hand written `<video>` tag gives you full control of the markup and one bitrate for everyone. A hosted plugin keeps the editing workflow and moves storage, transcoding and delivery off your server. Any page tells you which route it uses if you read its source.
Four routes, and the question that decides between them
The routes differ on one thing: who serves the bytes to the visitor. Settle that and the rest follows, because the same answer decides who owns the audience and whose bandwidth bill grows with your traffic.
| Route | Who serves the video | Right when | Where it stops |
|---|---|---|---|
| Media Library upload | Your web host | A short clip on a quiet page | The upload ceiling, and one bitrate for everyone |
| oEmbed from a video host | The video host | A marketing clip that wants their reach | Their branding, their data, their takedown switch |
| Hand written <video> tag | Wherever the file sits | You need exact control of the markup | No quality switching, captions or access control |
| Hosted video plugin | A video platform | Video is the product, or the files are large | A new dependency and a new bill |
Two of these leave the file on your own server and two do not. That line is where your bandwidth bill stops scaling with your audience.
Route 1. Upload the file to the Media Library
Open the post, add a Video block, and either upload the file or pick one already in the library. WordPress writes it to wp-content/uploads, creates an attachment record, and renders a plain <video> element pointing at it. Nothing is transcoded. The MP4 a visitor downloads is the MP4 you uploaded.
For a short clip on a quiet page this is the right answer. It needs no account, no plugin and no configuration.
Four separate limits can stop the upload, and the failure message almost never names the one you hit. upload_max_filesize and post_max_size come from PHP. memory_limit ends the request part way through. The fourth is your host's own hard cap, which no php.ini edit will move. Why WordPress will not let you upload your video covers how to read the real limit and the four fixes ranked by how long each one lasts.
Even below the ceiling, the file travels through PHP on the way in and out through your origin on every play. A plugin that uploads in resumable 5 MB chunks from the browser skips that path, which is how the FastPix uploader takes a long lecture recording without anyone touching upload_max_filesize. Close the browser part way and a Resume upload action asks for the same file and continues.
Route 2. Paste a link and let WordPress embed it
Paste the URL of a YouTube or Vimeo video on its own line in the editor, with nothing else around it. WordPress recognises the host, calls its oEmbed endpoint, and renders an iframe in place of that line. No plugin, no upload, no storage cost.
Four things move to the video host the moment you do this.
- Their branding. The player carries their logo and their chrome, so a visitor knows whose page they are really watching.
- Their recommendations. The panel at the end sends people to other creators, off a page you paid to rank.
- Their analytics. Watch time and drop-off sit in their dashboard. Your own analytics see a page view and nothing more.
- Their takedown switch. A copyright claim, an age restriction or a closed account pulls the video from every page that embeds it, and a reader tells you first.
None of that is a cost when reach is the point. A product announcement or a conference talk benefits from living where people already search for video, and the embed puts one upload in both places for free. It turns into a cost when the video is the product rather than an advertisement for it: a paid course lesson, a client deliverable, a demo on a pricing page. Protecting video on WordPress covers what changes once a video has to stay behind a login.
Route 3. Write the HTML5 video tag yourself
Drop the markup into a Custom HTML block when you want attributes the Video block does not expose, or when the file lives somewhere WordPress knows nothing about.
<video
controls
playsinline
preload="metadata"
poster="/wp-content/uploads/2026/09/demo-poster.jpg"
width="1280">
<source src="/wp-content/uploads/2026/09/demo.mp4" type="video/mp4">
<source src="/wp-content/uploads/2026/09/demo.webm" type="video/webm">
</video>playsinline stops iOS throwing the video into full screen the moment it plays. preload="metadata" fetches the header rather than the file, so a page with three videos does not download all three. The two <source> elements are format fallbacks rather than quality levels, so the browser picks the first type it can decode and pulls that entire file.
One bitrate reaches every visitor. Someone on fibre and someone on hotel wifi receive identical bytes, and only one of them waits. Switching quality during playback needs several renditions behind a manifest, and no markup you write by hand produces that. ABR vs MBR sets out the difference.
Two more limits come with the route. The src is a public URL anyone can copy out of the page source and keep using, which signed URLs exist to fix. A video above the fold also delays first paint, so load it only when it scrolls into view. Lazy loading HTML videos covers the mechanism.
Route 4. Install a hosted plugin, then use the block or the shortcode
A hosted plugin keeps the part of the Media Library you want, which is that video lives inside WordPress, and moves storage, transcoding and delivery to something built for it. You place a video two ways, both rendering through the same code.
The block. Search the block inserter and pick the plugin's block. The FastPix Video block sits in the Media category next to Image and Audio. Choose a video, set the per embed options in the sidebar, and publish. The block saves a static poster and link into the post as a fallback, so a published page still shows something if the plugin is ever deactivated.
The shortcode. Use it in a widget, a template file, or anywhere the block editor is not available.
[fastpix id="playback_ID" poster="/wp-content/uploads/2026/09/cover.jpg" accentcolour="#6D22CD"]| Parameter | Default | What it does |
|---|---|---|
| id | required | The media ID, listed in FastPix > Videos |
| streamid | none | A live stream ID in place of a media ID |
| autoplay | false | Needs muted as well, because browsers block sound |
| controls | true | nocontrols is shorthand for off |
| lazyload | true | Loads the player only when it scrolls into view |
| poster | the thumbnail | Wins over thumbnailtime |
| transcript | false | Shows the transcript panel beside the player |
| aspectratio | the video's own | For example 16:9 |
Booleans take true or false, and a bare flag works as well, as in [fastpix id="abc123" autoplay muted]. Neither the block nor the shortcode rewrites your post content, because embeds render at view time. The full option list sits in the embed reference.
The cost is plain. You add an account, a bill and a dependency the site did not have. You get back a player you did not build and an origin that stops shipping video.
Read the page source and tell which route a page is on
Open a published page, view source, and search for five strings. Each route leaves a different fingerprint, and this works on a site somebody else built.
| Search the source for | Route in use | What you are looking at |
|---|---|---|
| wp-video-shortcode | Media Library, [[video] shortcode](https://fastpix.com/blog/wordpress-video-shortcode) | Core's player wrapping a <video> inside <div class="wp-video"> |
| wp-block-video | Media Library, Video block | The block editor's wrapper around a plain <video> |
| <iframe with a video host in src | oEmbed | The host's player. Your page supplies a frame and nothing else |
| A bare <video> with no WordPress class | Hand written HTML | Exactly what you typed, unmodified |
| A wrapper class you do not recognise from core | Hosted plugin | The plugin's own renderer, with the playback URL built at render time |
Two details are worth checking while the source is open. A <source src="..."> pointing at /wp-content/uploads/ means your own server is shipping the video, whatever else the page looks like. An .m3u8 or .mpd URL anywhere in the markup means the player is fetching a manifest, so the visitor gets quality switching rather than one file.
The same check audits a site you inherited. Search the database for youtube.com/embed and you have every page whose video can vanish without anyone at your company touching it. Search for wp-content/uploads with a video extension and you have the files your origin pays to deliver, which moving a Media Library off your server covers.
Upload one video and embed it on a real page
The cheapest way to find out whether route four earns its dependency is to push one file through it. Connect a workspace with the three step setup wizard, upload a video from the Add media screen, and drop the block into a draft post. Then view source on the preview and match the markup against the five markers above. If the video must not leak, read protecting playback before the page goes public. The free plan covers 10 videos, no card required.
Frequently Asked Questions (FAQs)
How do I add a video to WordPress without using YouTube?
Three routes avoid a third-party embed. Upload the file to the Media Library and place a Video block, which works until you reach your host's upload ceiling. Write an HTML5 <video> tag in a Custom HTML block, which serves one file at one bitrate. Or install a hosted plugin, which keeps video inside WordPress while storage, transcoding and delivery happen elsewhere.
Why does my video upload fail in WordPress?
Four separate limits can stop it and the error rarely says which one. upload_max_filesize and post_max_size come from PHP. memory_limit ends the request part way through. The fourth is the host's own hard cap, which no php.ini edit will move. WordPress prints the effective limit on the Media screen, and the upload size guide covers the four ways around it.
Can I upload a video larger than my host's limit?
Not through the Media Library, because every byte travels through PHP. A plugin that uploads in resumable chunks from the browser to a video platform never sends the file through PHP, so the limit stops applying.
What do I give up by embedding a video from a third-party host?
Four things move to the host. Their branding sits on the player. Their end-of-video panel recommends other creators and sends people off your site. Watch time and drop-off live in their dashboard rather than yours. And a copyright claim, age restriction or closed account removes the video from every page that embeds it.
Does the WordPress Video block support adaptive streaming?
No. It renders a plain <video> element pointing at the uploaded file. Multiple <source> elements are format fallbacks rather than quality levels, so the browser picks the first type it can decode and downloads that whole file. See ABR vs MBR.
How can I tell whether a WordPress page uses an embed or a self-hosted video?
View the page source and search for five markers. wp-video-shortcode is core's video shortcode. wp-block-video is the Media Library Video block. An <iframe> whose src points at a video host is an oEmbed. A bare <video> with no WordPress class is hand-written markup. A plugin's own wrapper class means a hosted plugin renders it.









