Two small servers you run yourself
Recognition happens in the visitor's browser, so most of millirec needs no server at all. Two things do — counting votes, and resolving a code someone wrote by hand — and both are yours to run: there is no hosted version. Each is one small folder that runs standalone, in Docker, as a Node library inside a server you already have, or on Cloudflare Workers with nothing to set up.
Widgets server
Reactions and ratings your visitors draw instead of click: a heart, a check, a row of stars. The drawing is read in the visitor's browser; the server counts the vote, once per visitor, with no accounts and no cookies. Drawings shown on the wall are re-checked and drawn by the server itself, so a word or a doodle counts as the vote but never appears on your page.
Standalone
Unzip, then:
npm install
npm start # :3013Docker
In the unzipped folder:
docker compose up -dNode library
In your own Express or http server:
const w = createWidgetsServer(
{ basePath: '/widgets' })
app.use(w.listener)Cloudflare Workers
Votes in a Durable Object, nothing to create:
npx wrangler deployThen, on any page:
<script async src="https://YOUR-SERVER/embed/millirec-widget.js"></script>
<div data-millirec="reactions" data-widget="default" data-target="this-page"></div>
<div data-millirec="ratings" data-widget="default" data-target="this-page"></div>
- The server's own front page is the editor: your own reactions, colours and symbols, with a snippet and an edit token.
- A moderation page: every drawing that passed the check, to show, hide or delete — and a switch to hold new drawings for your review instead of showing them at once. It also shows your reaction symbols, so you can check them.
- Totals without a drawing pad (
reactions-count,rating-average), and a badge with no script:/badge/default/this-page.svg.
Codes server
Short codes people write by hand to open a page or join a room — six characters from an
alphabet with no lookalikes (no O/0, no l/1/I,
no case twins), so the recognizer and the eye both read them right. Written one character on top of the
last in a single box, or typed.
- A code for a page: your app asks for one (a shared puzzle, a document, a checkout); whoever writes it is taken there.
- A room: a code and a shared JSON state that everyone in it sees change live, plus messages relayed and never stored — strokes, cursors, moves.
Standalone
npm install
npm start # :3014Docker
docker compose up -dNode library
const c = createCodesServer()
const { code } = await c.createCode(
'https://example.com/puzzle/42')Cloudflare Workers
Codes, rooms and their live streams in one Durable Object:
npx wrangler deployThe handwritten code box, on any page:
<script async src="https://YOUR-SERVER/embed/millirec-code.js"></script>
<div data-millirec-code></div>
It is the code system behind digitizer.fun's two-player games and shared puzzles, with the games taken out.
What you get in each zip
- The server, its tests (
npm test), aDockerfileanddocker-compose.yml, awrangler.toml, and a README with every setting. - Everything a page loads from it: the embed, the recognizer and its templates. Nothing is fetched from millirec.com.
- Node 20 or newer for standalone and library use; storage is one SQLite file you can copy to back up.
- One setting limits a server to your own sites (
WIDGETS_ALLOWED_ORIGINS/CODES_ALLOWED_ORIGINS, wildcards allowed): pages anywhere else are refused. - MIT licensed, like the millirec package.