Node.js Proxy
The MonetizationOS Node.js proxy is an open source integration that adds server-side monetization decisions to any HTML origin. It runs the same proxy core as the Cloudflare, Fastly, and Akamai proxies, hosted as a service you deploy yourself.
What is the proxy core?
@monetizationos/proxy is a runtime-agnostic pipeline: a Fetch Request goes in, a transformed Response comes out.
On Node.js, an HTTP service hosts that pipeline in front of your origin, on containers, virtual machines, or your own servers.
Why use the Node.js proxy?
The MonetizationOS Node.js proxy lets you evaluate and apply monetization behavior before HTML reaches the browser, on infrastructure you run yourself.
Installation and configuration
Prerequisites
- Node.js 22 or later
- A surface and a secret API key from environment settings
- The base URL of your origin server
1. Create the service
mkdir mos-node-proxy && cd mos-node-proxy
npm init -y
npm pkg set type=module
npm install @monetizationos/proxy @hono/node-server htmlrewriter@hono/node-server serves the Fetch-based proxy on the Node.js HTTP server.
The proxy applies component behaviors through htmlrewriter, which packages Cloudflare's HTMLRewriter for Node.js.
2. Create the server
Create server.js, which reads configuration from environment variables and serves the proxy:
import { serve } from "@hono/node-server";
import { MOSProxyBuilder } from "@monetizationos/proxy";
import { HTMLRewriter } from "htmlrewriter";
const htmlRewriter = {
capabilities: { onEndTag: true, nthChild: true },
create: () => new HTMLRewriter(),
};
const proxy = new MOSProxyBuilder()
.withConfig({
originUrl: process.env.ORIGIN_URL,
surfaceSlug: process.env.SURFACE_SLUG,
mosHost: process.env.MONETIZATION_OS_HOST || "https://api.monetizationos.com",
mosSecretKey: process.env.MONETIZATION_OS_SECRET_KEY,
anonymousSessionCookieName: process.env.ANONYMOUS_SESSION_COOKIE_NAME,
authenticatedUserJwtCookieName: process.env.AUTHENTICATED_USER_JWT_COOKIE_NAME,
injectScriptUrl: process.env.INJECT_SCRIPT_URL || undefined,
surfaceDecisionsIgnorePaths: process.env.SURFACE_DECISIONS_IGNORE_PATHS,
})
.withHtmlRewriter(htmlRewriter)
.build();
serve(
{
fetch: (request) => {
if (new URL(request.url).pathname === "/healthz") {
return new Response("ok");
}
return proxy.handle(request);
},
port: Number(process.env.PORT) || 3000,
overrideGlobalObjects: false,
},
(info) => {
console.log(`MonetizationOS proxy listening on http://localhost:${info.port}`);
},
);htmlRewriter is the adapter the proxy core uses for HTML transforms.
create() returns a rewriter for each response, and capabilities tells the core which rewriter features it can use: onEndTag for replacing a range of elements, nthChild for :nth-child() selectors.
Any package that implements Cloudflare's HTMLRewriter API can take the place of htmlrewriter.
overrideGlobalObjects: false keeps the native Request and Response objects the proxy core expects.
The /healthz route answers load balancer health checks, which the AWS ECS Fargate guide relies on.
3. Configure environment variables
| Variable | Description |
|---|---|
MONETIZATION_OS_SECRET_KEY | Your MonetizationOS secret key. Get it from environment settings. |
ORIGIN_URL | The base URL of your origin server. |
SURFACE_SLUG | The MonetizationOS surface to evaluate for every HTML request. |
AUTHENTICATED_USER_JWT_COOKIE_NAME | Cookie name containing the authenticated user's JWT. |
ANONYMOUS_SESSION_COOKIE_NAME | Cookie name for anonymous session identifiers. |
SURFACE_DECISIONS_IGNORE_PATHS | Comma-separated regex patterns for paths that should skip surface decisions (optional) |
MONETIZATION_OS_HOST | MonetizationOS API host. Defaults to https://api.monetizationos.com (optional) |
INJECT_SCRIPT_URL | URL of the MonetizationOS web components script to inject when component transforms run (optional) |
PORT | Port the HTTP server listens on. Defaults to 3000 (optional) |
For further configuration fields, such as surfaceDecisionsCookies and originRequestHeaders, see the project README.
4. Run locally
Start the service with your configuration:
ORIGIN_URL=https://news.example.com \
SURFACE_SLUG=web \
MONETIZATION_OS_SECRET_KEY=<YOUR_SECRET_KEY> \
AUTHENTICATED_USER_JWT_COOKIE_NAME=__session \
ANONYMOUS_SESSION_COOKIE_NAME=anon-session-id \
node server.jsThe terminal prints:
MonetizationOS proxy listening on http://localhost:3000Request a page through the proxy:
curl -i http://localhost:3000/The response is your origin's HTML.
Notice the Set-Cookie header on the first response: the proxy created an anonymous session identifier for the visitor.
5. Containerize
Create a Dockerfile that installs the runtime dependencies and runs the service:
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY server.js ./
USER node
EXPOSE 3000
CMD ["node", "server.js"]Build and run the image:
docker build -t mos-node-proxy .
docker run --rm -p 3000:3000 \
-e ORIGIN_URL=https://news.example.com \
-e SURFACE_SLUG=web \
-e MONETIZATION_OS_SECRET_KEY=<YOUR_SECRET_KEY> \
-e AUTHENTICATED_USER_JWT_COOKIE_NAME=__session \
-e ANONYMOUS_SESSION_COOKIE_NAME=anon-session-id \
mos-node-proxyThe container prints the same listening line, and curl -i http://localhost:3000/ returns your origin's HTML.
For canonical setup details and updates, see the project README.
Next steps
- Deploy the container to AWS with the AWS ECS Fargate guide
- Learn the broader concept and architecture in Proxies
- Explore the request pipeline in the Proxy API reference