The problem with third-party script tags
Adding a third-party tool to a website has traditionally meant dropping a <script> tag into your HTML. That simple act forces browsers to connect to another server, fetch and execute more JavaScript, and — most critically — hand over complete control of your page to code you can't inspect. Minified scripts are effectively unreadable, so website owners have no way to verify what those scripts actually do, whether they're hijacking users, stealing credentials, mining cryptocurrency, or exfiltrating PII.
Managed Components change this model. Each component is built around a permissions system, similar to how mobile apps work. As a website owner, you explicitly decide whether a component can connect to a remote server, use cookies, execute code, or inject widgets into your pages. If a permission isn't granted, the component doesn't get access to that API — no second-guessing what a minified bundle is up to.
Managed Components also unlock capabilities that browser-side scripts never had: server-side network connections, response manipulation before data reaches the browser, caching, and key-value storage. Because the code executes outside the browser, pages can load roughly 40% faster, and the attack surface shrinks dramatically if a vendor's infrastructure is compromised.
At its core, a Managed Component is just a JavaScript module. The full specification is available at managedcomponents.dev, and open-sourced examples are on GitHub.
WebCM: an open-source component manager
Managed Components don't run in the browser, so something has to execute them. That's the job of a Component Manager. The Managed Components APIs were designed to be manager-agnostic, and two implementations now exist: Cloudflare Zaraz and WebCM.
WebCM — Web-based Component Manager — is the open-source reference implementation. If you run a website, you can use it today to load Managed Components, regardless of whether you're a Cloudflare customer. If you're building components, it doubles as an SDK for testing and development.
Running WebCM in five minutes
WebCM operates as a proxy, so it works with any website regardless of how it's built. Start with a simple HTML file:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset="UTF-8">
<title>My Website</title>
</head>
<body>
<h1>WebCM test website</h1>
</body>
</html>
Serve that file from a local HTTP server — for example with Node.js:
npx http-server -p 8000
or Python:
python3 -m http.server
Access the page at http://localhost:8000/index.html.
Next, create a webcm.config.ts configuration file in a new directory:
export default {
components: [
{
name: 'demo',
permissions: [
'access_client_kv',
'provide_server_functionality',
'provide_widget',
'serve_static_files',
'client_network_requests',
],
},
],
target: 'http://127.0.0.1:8000',
hostname: 'localhost',
trackPath: '/webcm/track',
ecommerceEventsPath: '/webcm/ecommerce',
clientEventsPath: '/webcm/system',
port: 8080
}
Here's what each setting does:
componentslists the Managed Components to load. Specifying"demo"is enough — WebCM fetches the package from NPM automatically. Each component declares thepermissionsit needs, and WebCM alerts you if a component lacks a required permission.targetpoints to your origin HTTP server (port8000in this case).portis where WebCM serves your proxied site.hostnameis the bind address.trackPath,clientEventsPath, andecommerceEventsPathare endpoints WebCM uses to relay browser events to its backend.
With your origin server still running, execute npx webcm from the directory containing webcm.config.ts (Node version 17 or higher is required). WebCM fetches the configured components into a components folder and starts a proxy server.
Open http://localhost:8080/index.html and the page will look identical to the origin version — but the demo component is now active. Mouse movements and clicks produce log output in the WebCM terminal, and the page displays a weather widget that was injected by the component. That weather data was fetched server-side with no additional browser requests, and WebCM can cache it for faster delivery. The component also exposes a new endpoint at http://localhost:8080/webcm/demo/cheese, demonstrating how components can add routes to your server when permitted.
Adding a real component: Google Analytics
The demo component exists purely for testing. For a real-world example, swap in the Google Analytics component:
export default {
components: [
{
name: 'demo',
permissions: [
'access_client_kv',
'provide_server_functionality',
'provide_widget',
'serve_static_files',
'client_network_requests',
],
},
{
name: 'google-analytics',
settings: { 'tid': 'UA-XXXXXX' },
permissions: [
'access_client_kv',
],
},
],
target: 'http://127.0.0.1:8000',
hostname: 'localhost',
trackPath: '/webcm/track',
ecommerceEventsPath: '/webcm/ecommerce',
clientEventsPath: '/webcm/system',
port: 8080
}
This Google Analytics-managed component needs fewer permissions because it runs entirely server-side. Replace UA-XXXXXX with your actual Universal Analytics (version 3) property ID, then re-run npx webcm. The page will look unchanged, but page views will appear in your Google Analytics Real Time dashboard — the component forwards events server-side without any browser-side tracking code.
Other components are available through the Managed Components organization on NPM and GitHub.
Building your own component
Managed Components isn't a closed catalog. The available tools are open source, so you can file issues or submit pull requests when something seems off. What's more, you can author new components from scratch.
To scaffold a new component, run npm init managed-component inside the components directory that WebCM created. The create-managed-component wizard walks you through the setup. For a component with no special permissions, you can decline all permission prompts.
The generated src/index.ts file starts with a listener for all page views:
import { ComponentSettings, Manager } from '@managed-components/types'
export default async function (manager: Manager, settings: ComponentSettings) {
manager.addEventListener('pageview', event => {
// do the things
})
}
Edit the commented-out line so the listener logs each page view, prefixing settings with an underscore since it's unused:
import { ComponentSettings, Manager } from '@managed-components/types'
export default async function (manager: Manager, _settings: ComponentSettings) {
manager.addEventListener('pageview', event => {
console.log(`New pageview at ${event.client.url}`)
})
}
The component now prints the current URL on every page view. Build it with npm i && npm run build, then register it in webcm.config.ts using the component's namespace and restart WebCM:
export default {
components: [
{
name: 'demo',
permissions: [
'access_client_kv',
'provide_server_functionality',
'provide_widget',
'serve_static_files',
'client_network_requests',
],
},
{
name: 'google-analytics',
settings: { 'tid': 'UA-123456' },
permissions: [
'access_client_kv',
],
},
{
name: 'your-component-namespace',
settings: {},
permissions: [],
},
],
target: 'http://127.0.0.1:8000',
hostname: 'localhost',
trackPath: '/webcm/track',
ecommerceEventsPath: '/webcm/ecommerce',
clientEventsPath: '/webcm/system',
port: 8080
}
This simple example shows how easily functionality that previously required browser-side JavaScript can move to the server. Replacing the console.log call with a fetch request sends page-view events straight to your own analytics warehouse. The Managed Components documentation covers other APIs for widgets, click tracking, cookies, caching, and more — capabilities that go beyond what was possible with script tags alone.
For third-party tool vendors, Managed Components offer a safer integration path that customers can adopt with confidence. The discoverability benefits are also real: components can be featured in tools like the Cloudflare Zaraz dashboard, putting them in front of thousands of websites. The managedcomponents.dev site is the starting point for building your own, with support available at [email protected].



