Skip to main content

Embed Server

A small Node/Express server that serves the embeddable widget. Locally, it runs on http://localhost:3010.

Prerequisites

  • Node 22. The Dockerfile, CI and package.json all pin the same major version — keep them in step if you change it.

Run it

cd embed
npm ci
npm run dev

The dev command prepares static assets, builds the widget bundle, and starts the server.

Use npm ci rather than npm install. It installs exactly what package-lock.json pins, which is what CI and the Docker image do.

Routes it serves

RouteWhat it is
/script.jsThe widget bundle you just built. Development only — disabled under NODE_ENV=production.
/healthz{"ok":true,"version":"…","commit":"…"} for the help pages.
/The help page.
/privacyThe privacy policy.

In production the widget is served from a Cloudflare R2 bucket, not by this server, and the versioned URLs (/v1/script.js, /v1.3.0/script.js) exist only there — the dev server has no equivalent of them. See Production → Embed Server.

Pointing a dev site at it

If you're developing a site that embeds the widget (e.g. abair.ie locally), set the widget URL via an env var:

NEXT_PUBLIC_WEBREADER_URL=http://localhost:3010

Restart the framework's dev server after changing it.

Rebuild without restart

CommandPurpose
npm run prepare-publicRefresh static assets (help pages, i18n, CSS)
npm run buildRebundle the widget into a single minified script

How the bundle is put together

embed/build.js concatenates the extension's own content scripts, in manifest order, into one IIFE and minifies it. Two things make that work in a page the widget doesn't own:

  • embed/src/shim.js provides a chrome.* API — storage, messaging, TTS calls — so the content scripts run unmodified. It is scoped to the bundle, not attached to window, so it cannot disturb a host site that talks to its own browser extension.
  • embed/src/boot.js applies WebReaderConfig, installs the public window.WebReader API, and removes every other global the bundled files publish. Only WebReader and WebReaderConfig are left on the host page.

If you add a file to the content scripts, add it to the FILES array in embed/build.js and to the three manifests, or it will ship in one deliverable and not the other.

Ready to ship? See Production → Embed Server.

Last updated 2026-08-18