Self-hosted · Apache-2.0

Provable acceptance for your legal documents.

clickwrap is a self-hosted service for capturing provable acceptance of versioned agreements — terms of service, DPAs, privacy policies, any document your users must accept — backed by an append-only evidence chain. It also archives externally-signed documents as immutable per-customer evidence.

One compliant: true | false answer per customer. Two acceptance modes. A tamper-evident audit trail. Runs in a single container.

What it does

Two acceptance modes

Active click-consent — the user ticks a box against the exact, versioned consent text. Passive tacit acceptance — a new version counts as accepted unless objected to within an objection period.

Deadlines start on provable access

A passive objection period begins only on provable access (e-mail delivery confirmation or a confirmed popup display) — never on publish alone. Active versions carry an absolute hard deadline stamped at rollout.

Append-only evidence chain

Who accepted which version, when, from which IP / user-agent, against which exact consent text and document hash. Immutable — enforced by DB privileges; corrections are new rows, never edits.

Compliance-gate API

Downstream apps ask one question — is this customer allowed in? — and get compliant: true | false with per-document detail. The single integration point for your portals and tools.

Versioned documents

One document per (type × audience) with an immutable version history (DRAFT → PUBLISHED → RETIRED). Publish rolls out to customers, tracks deadlines, sends reminders and escalates.

Externally-signed archive

Flag a document type external to skip the clickwrap machinery and instead store already-signed PDFs (e.g. counter-signed offers) per customer as immutable evidence — never part of the compliance gate.

Plugin-extensible

E-mail delivery, file storage, admin auth, the acceptance-page renderer and admin notifications are all plugins, discovered from installed npm packages. Ship your own without forking.

Admin web UI included

A React admin UI for legal / operations staff: documents, versions, customers, compliance dashboards and the evidence history — served from the same container.

Quickstart

The combined image serves the API, the hosted acceptance page and the admin UI from one container. This runs a self-contained demo (in-memory store, no external services):

docker run -p 3000:3000 \
  -e ADMIN_API_TOKEN="$(openssl rand -hex 24)" \
  -e SERVICE_API_TOKEN="$(openssl rand -hex 24)" \
  -e ACCEPTANCE_LINK_SECRET="$(openssl rand -hex 32)" \
  -e PUBLIC_BASE_URL="http://localhost:3000" \
  ghcr.io/jramm/clickwrap-combined:latest

Then open http://localhost:3000 — a bare / redirects to the admin UI at /ui. For a production setup (Postgres via Prisma, S3 storage, an e-mail provider), see the README and docs.

Three images, one for every shape

backend

The API + hosted acceptance page only. Put your own frontend in front of it.

admin-ui

nginx serving the admin SPA, proxying /api to a separate backend.

combined

Everything in one container — API at the root, admin UI under /ui.

Public images on ghcr.io/jramm/clickwrap, -admin-ui and -combined — anonymous pull, semver-tagged.

Extend it with plugins

Everything pluggable ships as an npm package the host discovers at boot: e-mail providers (Postmark / SMTP / no-op), file storage (memory / local / S3), admin auth (Google SSO / static token / SuperTokens), the acceptance-page renderer and admin notifications. Build your own against the typed SDK:

npm i -D @jramm/clickwrap-plugin-sdk

See the plugin guide for the definePlugin contract and a worked example.

Run it yourself.

Open source, Apache-2.0, no SaaS lock-in. Your agreements and evidence stay on your infrastructure.