WordPress oEmbed makes embedding external content extremely convenient.
Paste a supported URL into the editor and WordPress can automatically turn it into rich content such as:
- YouTube videos;
- Vimeo videos;
- social posts;
- audio;
- images;
- other supported external media.
For many websites, that is useful functionality.
For others, the entire oEmbed system is unnecessary.
A site that never embeds third-party content may still expose oEmbed discovery links, support WordPress’s embed endpoints and retain related embed functionality that the project simply does not use.
Disabling oEmbed can therefore make sense as part of a deliberate WordPress cleanup.
But there is an important complication:
removing one oEmbed feature
≠
disabling the entire oEmbed system
WordPress oEmbed includes several separate layers.
This guide explains what they are, how to disable them safely, what each PHP snippet actually removes and what you should test before disabling oEmbed on a production site.
What is oEmbed?
oEmbed is a protocol that allows one website to ask another service for the HTML required to represent a URL as embedded content.
The official WordPress oEmbed documentation describes WordPress as the consumer and services such as video platforms as providers.
The simplified flow is:
URL pasted into WordPress
↓
WordPress identifies provider
↓
WordPress requests oEmbed data
↓
provider returns embed information
↓
WordPress stores/renders embed HTML
This avoids requiring editors to manually copy iframe HTML from every external service.
A simple example
An editor might paste:
https://www.youtube.com/watch?v=example
Instead of displaying the URL as plain text, WordPress can resolve the provider and render an embedded player.
That is the basic purpose of WordPress oEmbed.
WordPress is both an oEmbed consumer and provider
This distinction is essential before disabling anything.
WordPress can act as an oEmbed consumer.
your WordPress site
↓
requests embed information
↓
external provider
But WordPress can also expose its own content so other sites can embed eligible WordPress posts.
external website
↓
requests embed information
↓
your WordPress site
Those are different directions of communication.
Disabling oEmbed is therefore not one switch
The WordPress embed architecture includes several pieces:
- default embed handlers;
- oEmbed provider resolution;
- provider discovery;
- oEmbed caching;
- oEmbed REST API routes;
- oEmbed discovery links in the document head;
- WordPress post embedding;
- the
wp-embedJavaScript used by WordPress post embeds.
Removing one component does not necessarily remove the others.
Why would you disable oEmbed?
Possible reasons include:
- the site never embeds external content;
- the site uses only locally hosted media;
- external embeds are prohibited by project policy;
- you want fewer unnecessary frontend features;
- you want to reduce unused WordPress discovery output;
- you want tighter control over external providers;
- you use custom embed components instead of WordPress oEmbed;
- you want to reduce unnecessary third-party integrations.
None of these automatically means every WordPress site should disable oEmbed.
Do not disable oEmbed just because WordPress has it
Unused functionality can reasonably be removed.
Useful functionality should not be removed merely because a performance checklist says:
disable everything
If editors regularly embed:
- videos;
- podcasts;
- social content;
- other external media;
then oEmbed may be part of the site’s publishing workflow.
Audit actual usage first.
oEmbed itself is not the same as a heavy third-party embed
This is another important distinction.
The oEmbed system helps WordPress discover and generate embed markup.
The resulting external player or widget may then load:
- JavaScript;
- CSS;
- images;
- fonts;
- tracking resources;
- API calls;
- media.
Those frontend resources are often much more significant for performance than WordPress’s oEmbed resolution mechanism itself.
See Why Third-Party Embeds Slow Down WordPress for that side of the architecture.
Disabling oEmbed does not automatically remove existing iframe HTML
Suppose a page contains:
<iframe
src="https://external.example/embed/123"
></iframe>
That iframe does not need WordPress oEmbed to work.
It is already explicit HTML.
Therefore:
WordPress oEmbed disabled
≠
all external embeds removed
Raw iframes can also come from:
- Custom HTML blocks;
- shortcodes;
- page builders;
- plugins;
- theme templates;
- custom fields.
Start by auditing how your site uses embeds
Before changing Core behavior, inspect:
- posts;
- pages;
- custom post types;
- widgets;
- block templates;
- reusable patterns;
- page-builder templates;
- shortcodes;
- theme code;
- plugin settings.
Search for common providers and iframe markup.
Check the frontend too
Database content does not tell the entire story.
A plugin may dynamically generate an embed even if no provider URL appears directly in post content.
Inspect rendered HTML and browser network activity.
For a broader third-party audit, see WordPress Privacy and Third-Party Requests.
Method 1: disable oEmbed discovery for unknown providers
WordPress can inspect a URL for oEmbed discovery links when the provider is not already resolved through its known provider system.
The relevant filter is:
embed_oembed_discover
The official WordPress hook documentation confirms that this filter controls whether WordPress inspects a URL for discoverable oEmbed link tags.
You can disable that discovery with:
add_filter( 'embed_oembed_discover', '__return_false' );
What this actually changes
This prevents WordPress from performing oEmbed discovery for otherwise undiscovered providers.
It does not mean:
all oEmbed support disabled
Known providers and other parts of the embed system can still exist.
Discovery and provider support are separate concepts
WordPress maintains provider information and can also discover provider endpoints from eligible URLs.
The official WP_oEmbed::discover() documentation shows that discovery inspects a remote document for oEmbed provider links.
Disabling discovery therefore narrows resolution behavior.
It does not dismantle WordPress’s entire embed architecture.
Method 2: prevent WordPress’s default embed handlers from loading
WordPress exposes the:
load_default_embeds
filter.
The official wp_maybe_load_embeds() documentation states that returning a false value prevents the default embed handlers from loading.
You can use:
add_filter( 'load_default_embeds', '__return_false' );
This disables default handlers, not every oEmbed mechanism
The function registers default handlers including support for specific media URL patterns.
Again:
default handlers disabled
≠
entire embed subsystem removed
This is why isolated snippets need to be understood individually rather than copied as a mysterious collection of incantations.
Method 3: remove oEmbed discovery links from the WordPress head
On eligible singular content, WordPress can advertise oEmbed endpoints using discovery links in the document head.
They can look conceptually like:
<link
rel="alternate"
type="application/json+oembed"
href="..."
/>
and, when XML support is available:
<link
rel="alternate"
type="text/xml+oembed"
href="..."
/>
The official wp_oembed_add_discovery_links() documentation describes this output.
WordPress 6.9 changed the priority of oEmbed discovery output
This matters if you are using old cleanup snippets.
Since WordPress 6.9, wp_oembed_add_discovery_links() runs first at:
wp_head priority 4
with a compatibility fallback involving its historical priority 10 behavior.
The change helps discovery links appear sufficiently early in the HTML document for consumers that inspect only an initial portion of the response.
This means code written around older assumptions about priority 10 should be reviewed rather than blindly reused.
The same version-awareness issue appears in WordPress Head Tags You Can Safely Remove.
Removing the discovery output safely
A straightforward way to suppress the rendered discovery markup is to filter the generated output:
add_filter( 'oembed_discovery_links', '__return_empty_string' );
This removes the discovery link HTML without pretending that the underlying oEmbed endpoint has disappeared.
Removing discovery links is not disabling oEmbed
This distinction deserves its own rule:
remove discovery
≠
disable endpoint
≠
disable consumer
≠
disable provider
Removing discovery markup merely stops eligible pages from advertising those endpoints in that location.
The underlying functionality can remain reachable when its URL is already known.
This is the same architectural distinction explained for other WordPress discovery systems in Disable RSS Feeds vs Remove Feed Links.
WordPress exposes an oEmbed REST API endpoint
WordPress registers oEmbed routes through its REST API infrastructure.
The official WP_oEmbed_Controller::register_routes() documentation shows the routes registered under:
oembed/1.0
including the public embed route and the proxy functionality used for provider requests.
The public oEmbed route serves WordPress content as embeddable data
Conceptually:
external consumer
↓
your WordPress REST API
↓
oEmbed response
↓
iframe/embed representation
This is WordPress acting as an oEmbed provider.
The proxy route serves a different purpose
The oEmbed controller also includes proxy functionality used in WordPress’s embedding workflow.
Its permission model differs from the public embed response route.
Do not treat every route under:
/wp-json/oembed/1.0/
as if it performs the same operation.
Do not disable the entire REST API just to remove oEmbed
This would be a disproportionate solution.
WordPress REST functionality can be used by:
- the Block Editor;
- plugins;
- themes;
- custom applications;
- administrative interfaces;
- integrations.
See What Depends on the WordPress REST API before making broad REST changes.
If the goal is:
disable oEmbed
target oEmbed.
Do not solve it with:
disable unrelated API infrastructure too
Removing the oEmbed REST routes requires deliberate route-level control
A complete oEmbed shutdown may also remove the oEmbed REST routes rather than disabling the REST API globally.
This should be handled at the route-registration level or through a maintained implementation that understands the current WordPress embed subsystem.
Route-level modifications deserve careful testing because editor and plugin functionality can depend on the proxy side of oEmbed.
WordPress also loads the wp-embed script for post embeds
WordPress includes JavaScript associated with its post-embedding system.
The relevant handle is commonly:
wp-embed
The current WordPress embed code includes logic such as wp_oembed_add_host_js() and wp_maybe_enqueue_oembed_host_js() for communication with WordPress post-embed iframes.
This is separate from the external provider’s own JavaScript.
What wp-embed does not mean
Removing:
wp-embed
does not magically remove:
- YouTube’s player JavaScript;
- Vimeo resources;
- map SDKs;
- social widgets;
- raw iframe content.
Those resources belong to their respective providers.
Dequeueing wp-embed
If your implementation has confirmed that the WordPress embed script is unnecessary, it can be dequeued:
add_action(
'wp_enqueue_scripts',
function () {
wp_dequeue_script( 'wp-embed' );
},
100
);
For the general WordPress asset-loading model, see wp_enqueue_scripts Explained.
Do not use dequeueing as your entire oEmbed strategy
This:
wp_dequeue_script( 'wp-embed' );
only targets a script.
It does not necessarily remove:
- provider resolution;
- oEmbed discovery;
- REST routes;
- discovery links;
- cached embed HTML;
- existing third-party iframes.
A practical partial-disable configuration
If your goal is primarily to stop automatic discovery and remove frontend oEmbed discovery advertising, a narrow configuration can look like:
/**
* Disable automatic oEmbed provider discovery.
*/
add_filter( 'embed_oembed_discover', '__return_false' );
/**
* Prevent WordPress's default embed handlers from loading.
*/
add_filter( 'load_default_embeds', '__return_false' );
/**
* Remove oEmbed discovery links from the document head.
*/
add_filter( 'oembed_discovery_links', '__return_empty_string' );
/**
* Remove the WordPress post-embed frontend script
* when the site does not require it.
*/
add_action(
'wp_enqueue_scripts',
function () {
wp_dequeue_script( 'wp-embed' );
},
100
);
This is still not a complete oEmbed shutdown
The snippet above intentionally demonstrates separate controls.
It should not be described as:
WordPress oEmbed no longer exists
because the REST API routes and other embed internals require separate consideration.
Why complete oEmbed snippets are more complicated
A truly broad disable implementation may need to account for:
- consumer-side URL embedding;
- provider discovery;
- default embed handlers;
- REST oEmbed routes;
- head discovery links;
- WordPress post-embed JavaScript;
- editor-side behavior;
- existing cached embeds;
- provider-specific exceptions.
That is why a maintained module is often safer than a pile of unrelated snippets copied from several different WordPress eras.
Existing oEmbed cache can survive configuration changes
WordPress caches resolved embed HTML.
The WP_Embed documentation shows that WordPress stores oEmbed results so the provider does not need to be queried every time content renders.
Depending on context, cached data may exist as post metadata or oEmbed cache content.
Changing provider behavior does not necessarily erase old cached results
This means:
disable future discovery
↓
old cached embed
may still exist
Do not interpret a cached result as proof that your new filter failed.
Do not blindly delete all post metadata to clear embed caches
WordPress posts can contain metadata from:
- SEO plugins;
- page builders;
- custom fields;
- WooCommerce;
- themes;
- plugins;
- Core.
Cache cleanup should target embed-related data specifically.
What happens to old embedded content after disabling oEmbed?
The answer depends on how that content is stored.
Raw iframe HTML
It can continue working because the iframe does not require oEmbed resolution.
Previously resolved embed markup
Cached HTML may continue rendering until it is regenerated or removed.
Plain provider URLs
If WordPress no longer resolves them as embeds, they may fall back to ordinary links or text depending on the content format and rendering path.
Embed blocks
Behavior should be tested individually because the editor and frontend may still contain provider-specific or cached embed data.
What happens to new embeds?
If you completely disable the relevant consumer-side oEmbed behavior, editors should no longer expect:
paste supported URL
↓
automatic rich embed
The content may instead remain:
- a URL;
- a normal link;
- an unsupported embed block;
- custom markup if another plugin handles it.
Page builders can bypass WordPress oEmbed
A builder may offer its own:
- YouTube element;
- Vimeo element;
- map element;
- social widget;
- iframe widget.
Those components may generate provider markup independently.
Therefore a successful WordPress oEmbed disable does not prove that the site has no external embed functionality.
Plugins can also implement their own provider integrations
Examples include:
- video-gallery plugins;
- social-feed plugins;
- map plugins;
- booking systems;
- review widgets;
- podcast players.
Audit those separately.
Disabling oEmbed does not automatically improve Core Web Vitals
If the page does not contain embeds, removing unused embed functionality may provide modest cleanup.
If the page contains a manually inserted 2 MB third-party video player, disabling Core oEmbed while leaving that iframe intact does not make the player lightweight.
Performance improvements depend on what actual resources disappear.
See Reducing WordPress Front-End Page Weight for a broader performance audit.
Removing discovery markup provides only a small performance saving
An oEmbed discovery link is a small piece of HTML.
Removing it can make the document cleaner.
It should not be marketed as a major frontend optimization.
The larger gains occur when a configuration prevents:
- unnecessary scripts;
- unnecessary third-party requests;
- unused embeds;
- heavy external players.
Privacy is a separate reason to review embeds
A third-party iframe can connect the visitor’s browser directly to an external provider.
This may expose connection and request information before the visitor interacts with the embed.
The exact behavior depends on the provider.
See WordPress oEmbed Privacy and Security, Explained for the privacy and trust implications.
Disabling oEmbed does not guarantee zero third-party requests
A WordPress site may still contact external services for:
- fonts;
- analytics;
- avatars;
- CDNs;
- maps;
- CAPTCHA;
- advertising;
- payment providers;
- chat systems;
- plugin APIs.
oEmbed is only one category of external communication.
Security benefits should not be exaggerated
Reducing unused functionality can reduce unnecessary attack surface and integration complexity.
But:
disable oEmbed
≠
secure WordPress
WordPress security still depends on:
- Core updates;
- plugin updates;
- theme updates;
- authentication;
- authorization;
- server configuration;
- secure custom code;
- backup and recovery practices.
WordPress already applies security restrictions to oEmbed discovery
The official WordPress oEmbed documentation explains that discovered content is restricted and sanitized, with stronger limitations applied to rich HTML and video content.
This is important because the correct argument for disabling oEmbed is not:
WordPress embeds arbitrary malicious HTML
from every URL
That would misrepresent the current system.
The more accurate argument is:
unused external-content functionality
may be unnecessary for this project
Can you keep only selected providers?
Yes, and this is often better than an all-or-nothing configuration.
For example:
YouTube
→ required
Vimeo
→ required
everything else
→ unnecessary
WordPress exposes provider-level functions including:
wp_oembed_add_provider()
wp_oembed_remove_provider()
The official oEmbed handbook documents provider registration and removal.
Provider-level control is useful for controlled publishing environments
An agency or editorial team may deliberately support only a known set of providers.
This creates a clearer architecture:
approved provider
→ supported
unknown provider
→ not automatically discovered
That can be easier to audit than allowing arbitrary discovery behavior.
Do not assume provider removal blocks raw HTML
If an editor with sufficient permissions inserts an iframe manually, removing an oEmbed provider does not necessarily remove that iframe.
Provider resolution and HTML permissions are different systems.
How TheOneWP handles oEmbed disabling
If you want to disable WordPress embed functionality without maintaining a collection of version-sensitive snippets, TheOneWP Disable Embeds provides a dedicated module for the task.
The module is intentionally broader than simply removing a discovery tag.
It targets WordPress embed scripts, discovery links and related embed behavior while providing controls for retaining providers the site still needs.
Why selective provider retention matters
A real project may have requirements such as:
YouTube
→ needed
Vimeo
→ needed
other automatic embeds
→ unnecessary
That is different from:
disable every possible embed
A modular configuration lets the site reduce unnecessary functionality without destroying useful editorial workflows.
Do not combine several oEmbed-disable solutions
Avoid running:
- a custom functions.php snippet;
- a dedicated embed-disabling plugin;
- a performance plugin with embed removal;
- another optimization module;
all against the same subsystem.
Multiple implementations can make debugging difficult because one tool may remove a hook that another expects to modify.
Choose one owner for the configuration
Prefer:
one maintained implementation
↓
documented configuration
↓
tested behavior
instead of:
five snippets
+
three plugins
+
nobody remembers why
Where should custom oEmbed code live?
If you implement the configuration manually, avoid putting important site behavior into a parent theme that may later be replaced.
Better locations include:
- a small site-specific plugin;
- a controlled must-use plugin;
- a maintained snippet-management system.
This keeps site functionality separate from presentation.
Test on staging first
Embed behavior can affect existing content in ways that are easy to miss.
Use a staging environment before changing production.
See WordPress Staging Site Best Practices.
Test existing content before disabling anything
Create a list of pages containing:
- video embeds;
- social embeds;
- audio;
- maps;
- WordPress post embeds;
- custom provider integrations.
Record their current behavior.
Then test new content creation
After changing oEmbed configuration:
- Create a test post.
- Paste a supported provider URL.
- Try an Embed block.
- Try any approved providers.
- Try a provider that should now be disabled.
- Preview the frontend.
- Inspect the resulting HTML.
Inspect the page head
Search rendered source for:
application/json+oembed
text/xml+oembed
If discovery output was intentionally removed, those links should no longer appear where Core would normally emit them.
Remember the WordPress 6.9 behavior
Do not audit only the historical:
wp_head priority 10
assumption.
Current WordPress runs the oEmbed discovery output earlier at priority 4, with backward-compatibility handling around the original hook behavior.
This is precisely why old snippets deserve testing after WordPress Core changes.
Inspect the REST API routes
If your implementation claims to disable the provider side of WordPress oEmbed, verify the relevant:
/wp-json/oembed/1.0/
routes rather than assuming they disappeared because the document head looks cleaner.
Inspect frontend scripts
Check whether:
wp-embed
is still present where you expect it to be removed.
Use the browser Network panel and rendered page source.
For more systematic JavaScript auditing, see How to Remove Unused WordPress Scripts.
Inspect actual external requests
If the goal includes privacy or performance, inspect the Network panel for:
- YouTube;
- Vimeo;
- social platforms;
- maps;
- other embed providers.
A clean WordPress head does not prove that the page makes no third-party connections.
Clear caches before deciding whether the change worked
After changing embed behavior, clear relevant:
- page cache;
- CDN cache;
- browser cache where appropriate;
- application-level caches involved in rendered output.
Also remember that WordPress can retain cached oEmbed data independently of normal page caching.
Test logged-in and logged-out views
The editor, authenticated frontend and anonymous frontend can load different assets and execute different code paths.
Test both:
logged-in administrator
+
anonymous visitor
Test mobile too
External players may behave differently on:
- mobile browsers;
- touch interfaces;
- smaller viewports;
- slower networks.
Do not validate embed changes only on a desktop development machine.
Common mistake: removing only wp-embed
This:
wp_dequeue_script( 'wp-embed' );
is not a complete oEmbed disable.
It removes one asset from one part of the architecture.
Common mistake: removing only discovery links
This:
add_filter(
'oembed_discovery_links',
'__return_empty_string'
);
removes discovery markup.
It does not disable:
- provider resolution;
- the REST endpoint;
- existing embeds;
- raw iframes.
Common mistake: disabling the entire REST API
Do not disable an infrastructure layer used throughout modern WordPress merely because one REST namespace is unwanted.
Target the relevant functionality instead.
Common mistake: expecting existing iframe embeds to disappear
Explicit iframe HTML is independent from automatic oEmbed resolution.
Audit existing content separately.
Common mistake: assuming oEmbed removal is a major speed optimization
If no embeds are present, removing unused Core functionality can be sensible cleanup.
But the largest frontend savings usually come from eliminating or delaying actual heavy third-party resources.
A single video iframe can outweigh many small WordPress cleanup changes.
Common mistake: disabling oEmbed without telling editors
If the editorial team currently expects:
paste URL
→ rich embed
changing that behavior without documentation creates confusion.
Document:
- which providers remain supported;
- which providers are disabled;
- how videos should now be inserted;
- whether custom embed blocks should be used instead.
Common mistake: testing only newly created content
Historical posts may contain:
- cached oEmbed data;
- legacy embed markup;
- old shortcodes;
- provider URLs;
- raw iframes.
Test representative older content as well.
Should you disable oEmbed on every WordPress site?
No.
Keep it when:
- editors regularly use embeds;
- supported external content is part of the site’s purpose;
- the publishing convenience is valuable;
- the frontend implementation is already optimized appropriately.
Disable or restrict it when
- the site never uses external embeds;
- only selected providers should be allowed;
- the site uses a custom embed architecture;
- third-party media is intentionally prohibited;
- you want to remove unused embed infrastructure;
- the editorial workflow does not depend on automatic URL embedding.
Sometimes optimizing embeds is better than disabling oEmbed
If the problem is:
YouTube player is heavy
the best solution may be:
lightweight local preview
↓
user clicks
↓
YouTube iframe loads
rather than:
remove WordPress oEmbed completely
The two approaches solve different problems.
Quick reference: what each change does
embed_oembed_discover = false
→ disables automatic provider discovery
load_default_embeds = false
→ prevents default embed handlers loading
oembed_discovery_links = empty
→ removes oEmbed discovery markup from head
dequeue wp-embed
→ removes WordPress post-embed frontend script
remove oEmbed REST routes
→ disables WordPress oEmbed API endpoints
remove provider
→ removes support for selected provider patterns
remove raw iframe
→ removes that specific external embed
Complete oEmbed audit checklist
- Identify whether the site actually uses oEmbed.
- Search historical posts and pages.
- Check Embed blocks.
- Check Custom HTML blocks.
- Check shortcodes.
- Check page builders.
- Check plugin-generated embeds.
- Check theme templates.
- Identify required providers.
- Identify providers that can be removed.
- Decide whether automatic discovery is required.
- Decide whether default embed handlers are required.
- Decide whether WordPress content needs to remain externally embeddable.
- Review oEmbed REST routes.
- Review oEmbed discovery links.
- Review
wp-embed. - Do not confuse discovery removal with functionality removal.
- Do not disable the entire REST API unnecessarily.
- Check existing cached embed output.
- Check raw iframes separately.
- Audit third-party network requests.
- Measure actual performance changes.
- Review privacy implications.
- Test new editor behavior.
- Test old content.
- Test logged-in users.
- Test anonymous visitors.
- Test desktop.
- Test mobile.
- Clear caches.
- Document the final configuration.
- Re-test after major WordPress updates.
Related guides
- WordPress oEmbed Privacy and Security, Explained
- Why Third-Party Embeds Slow Down WordPress
- WordPress Privacy and Third-Party Requests
- WordPress Head Tags You Can Safely Remove
- What Depends on the WordPress REST API
- How to Remove Unused WordPress Scripts
Final recommendation
Do not treat WordPress oEmbed as one feature controlled by one hook.
The system includes several separate responsibilities:
consume external embeds
+
discover providers
+
cache embed responses
+
advertise your content
+
serve oEmbed REST responses
+
support WordPress post embeds
+
load related frontend JavaScript
If your site uses none of those capabilities, disabling the system can be a reasonable cleanup.
If the site still needs selected providers, a selective configuration is usually better than destroying the entire workflow.
Most importantly, identify the problem you are actually trying to solve.
If the goal is cleaner document markup, remove unnecessary discovery output.
If the goal is to prevent unknown-provider discovery, disable discovery.
If the goal is to stop WordPress content from being advertised and served as oEmbed content, address the provider side and its REST endpoints.
If the goal is frontend performance, measure the actual external embeds. The expensive part is often the provider’s iframe and JavaScript rather than WordPress’s oEmbed resolver.
If the goal is privacy, inspect which third parties the visitor’s browser contacts and when those connections occur.
And if the project does not need the embed subsystem at all, disable it deliberately using one maintained implementation such as TheOneWP Disable Embeds rather than accumulating unrelated snippets written for different generations of WordPress.
The useful principle is:
remove the functionality
you do not need
preserve the functionality
you deliberately use
verify both claims
in the rendered site

