Contents

Live demo

A live demo is the demo site (pnpm seed:demo, the fictional audio brand Varde) on a public address, with a login anyone may use. Visitors open the site, log in, change pages, publish and translate, and the next night it is all undone.

DEMO_MODE=true turns a deployment into a live demo. Without it, nothing on this page applies and a site works as before. Never set it on a real site.

What demo mode does #

  • A notice on every page. A slim bar at the bottom of the window says the site is a demo, that anyone can change it, and when it resets, in the visitor's own time zone. The server writes the time in UTC and the browser shows its own zone once the page is live. The text is under demo in src/messages, in every language. It is not in Microcopy, so no visitor can edit it away.
  • The admin says so too. A line above every admin page says that anyone can change the site, when it resets, and how much of today's AI allowance is left.
  • The demo login on the login page. The login page shows the email and password from DEMO_ADMIN_EMAIL and DEMO_ADMIN_PASSWORD, and the form comes filled in. They are public by design.
  • No search engines. robots.txt closes the whole site, the sitemap lists nothing, and every page carries noindex, nofollow, whatever Site settings → Search engines says.
  • Nothing leaves the server. No email: form notifications and password resets are dropped, each with a line in the log. No newsletter sign-ups, no calls to Vimeo (Vimeo videos play in Vimeo's own player), and no assistant connection (MCP). This holds even when SMTP_HOST, MAILCHIMP_API_KEY, VIMEO_ACCESS_TOKEN or MCP_ENABLED are set.
  • Small uploads only. Visitors upload pictures (JPEG, PNG, WebP, GIF, AVIF), MP4 and WebM videos and PDFs of at most 5 MB, and nothing else: no SVG, HTML or archives. Pasting a file's address is off, so the server never fetches one. Translate a file takes its Word, PowerPoint, Excel and InDesign files up to the same 5 MB. The demo seed and the server's own files are not limited.
  • No visitors' scripts. An "Embed with scripts" block shows its markup with the scripts removed, as Custom HTML does: on a demo anyone could write them, and they would run for every visitor.
  • AI only within a daily allowance, off by default. See The AI allowance.
  • The nightly reset, with DEMO_RESET=true as well. See The nightly reset.

What it does not do:

  • It does not keep visitors apart. Everyone shares one login and sees everyone else's changes until the reset, form submissions included. The notice asks visitors not to enter personal details.
  • It does not stop vandalism. A visitor may delete pages or rewrite the header. The reset puts it all back.
  • It does not limit requests. A visitor may save as often as they like. Put the demo behind your platform's rate limiting if you need that.
  • It never touches another database. The reset follows the demo seed's own safety rules (see "Demo content" in the README).

What a visitor can and cannot do #

The demo login is an editor (Roles and access), with one rule on top: in demo mode, nobody but an admin changes an account.

A visitor canA visitor cannot
Edit pages, blocks, sections, news, products and every other kind of content, and the header, footer and MicrocopyCreate, change or delete accounts, their own included: not its email, password or API key
Publish, unpublish, schedule and share previewsOpen Site settings, Users or the background jobs
Translate (within the AI allowance), sync blocks between languages, use the Translation Center, the glossary and the style guideLock the demo login: wrong passwords never lock it, while other accounts are still locked after five
Upload small pictures, videos and PDFs, and translate small filesUpload other kinds of file or larger ones, or make the server fetch an address
Build forms and send themHave anything emailed, or signed up to a newsletter

Why an editor: it is the narrowest role that tries everything the kit is about. An admin could change the demo login's password and lock everyone else out, add accounts, or change Site settings (the organisation, the map tiles, search engines). A translator could not publish, sync blocks or proofread the default language.

The AI allowance #

AI translation calls Anthropic's API on the site owner's key, and on a demo anyone can press ✨. So in demo mode AI is off, even with ANTHROPIC_API_KEY set, unless DEMO_AI_DAILY_LIMIT allows a number of model calls a day.

  • Model calls, for the whole site, per UTC day. They are counted where the kit calls the model (callModel in src/utilities/translate/anthropic.ts), so every AI feature counts. One ✨ Translate is usually several calls: one per batch of text, and the review.
  • Kept in Payload's key-value store, on MongoDB and Postgres alike. No admin screen or API shows it.
  • Used up, the ✨ Translate button says so and when the allowance renews (midnight UTC), every AI request answers with the same, and nothing is saved. The admin's line shows what is left.
  • The nightly reset clears it.
  • Close to exact. Several calls at once are counted in the order they were taken, and none is refused while there is room. Two servers asking for the very last call at the same moment may, rarely, both get it.

The nightly reset #

With DEMO_MODE=true and DEMO_RESET=true, the site resets itself every night at DEMO_RESET_AT (UTC, 03:00 by default), on its own jobs queue (Background jobs):

  • The same as pnpm seed:demo --reset. Every page, document, version, uploaded file (visitors' included), global value and queued job is deleted, and the demo is written again. The demo login is made afresh. Other people, such as your own admin, are kept, and the day's AI allowance starts again.
  • Only the demo's database. A reset needs the mark the demo seed leaves in the database. Anything else is refused, and the failed job says why under System → Background jobs.
  • An empty database is filled at once, within a minute or two, as soon as the site has its first admin (see Hosting a demo).
  • Fresh pages straight after. The server asks itself, on its own port and with its jobs runner's token, to drop every cached page (POST /api/revalidate), so nobody sees yesterday's edits. No restart.
  • It takes seconds: about 6 on MongoDB and 13 on Postgres on a laptop.
  • Admins see it waiting under System → Background jobs as "Reset the demo".

More than one container #

The reset runs where the background jobs run. With several containers, let one run the jobs and set JOBS_AUTORUN=false on the others, as for every job: then exactly one container resets the demo.

If two resets start anyway (two containers running jobs, or a cron beside the site's own schedule), the second finds the first's lease in the key-value store and stands back; its job fails with "Another reset of this demo is running".

Each container keeps its own page cache, and the reset refreshes the one it ran on. With several, also POST /api/revalidate to each of the others after the reset. A demo seldom needs more than one container.

Hosting a demo #

One container and a database, as for any site (Deploy):

  1. Deploy the image with a new, empty database and an uploads volume.

  2. Set the environment:

    DEMO_MODE=true
    DEMO_RESET=true
    DEMO_RESET_AT=03:00              # UTC
    [email protected]
    DEMO_ADMIN_PASSWORD=…            # public: the login page shows it
    DEMO_AI_DAILY_LIMIT=0            # or, with ANTHROPIC_API_KEY, the model calls a day you will pay for
  3. Open /admin and create your own admin, the site's first account. Within a minute the server fills the database with the demo and makes the demo login. It waits for your account first: the first account of a site is always an admin, and the demo login must never be one.

  4. From then on, the demo resets itself every night.

A database you filled with pnpm seed:demo before carries the mark too: point the container at it and the nightly reset takes over.

A platform cron instead #

The image holds the server only, not the kit's scripts, so pnpm seed:demo --reset needs a checkout of the kit with its dependencies installed, and the demo's environment: on a server, or a platform service built from the repository. Leave DEMO_RESET unset for the site, so it does not reset itself as well, and set it on the command only:

# crontab: every night at 03:00 UTC
0 3 * * * cd /srv/demo && DEMO_RESET=true pnpm seed:demo --reset

The seed asks the site at NEXT_PUBLIC_SERVER_URL to drop its cached pages, which needs the same PAYLOAD_SECRET as the site. Set DEMO_RESET_AT to the cron's time, so the notice tells visitors the right one.

Environment variables #

VariableDefaultWhat it does
DEMO_MODEofftrue makes the site a public demo: everything on this page.
DEMO_RESETofftrue allows a reset (pnpm seed:demo --reset); with DEMO_MODE, the site resets itself every night.
DEMO_RESET_AT03:00The time of the nightly reset, in UTC, as HH:MM. Also the time the notice shows.
DEMO_ADMIN_EMAIL, DEMO_ADMIN_PASSWORDnoneThe demo login, an editor, made by every seed and reset. Without both there is none. The password needs at least 8 characters.
DEMO_AI_DAILY_LIMIT0Model calls a day (UTC) for the whole site. 0 turns AI off in the demo.

The others a demo uses: ANTHROPIC_API_KEY for AI, JOBS_AUTORUN with more than one container, and DATABASE_URL, PAYLOAD_SECRET and NEXT_PUBLIC_SERVER_URL as for every site. See Environment variables.

Tests #

tests/int/demoMode.int.spec.ts starts the site in demo mode against a database of its own and checks the demo login's limits, email and newsletter, the AI allowance, uploads and the reset job. tests/e2e/demoMode.e2e.spec.ts checks the notice, noindex and the login page, and runs only against a server started in demo mode; the normal run skips it:

DEMO_MODE=true [email protected] DEMO_ADMIN_PASSWORD=demo-password pnpm test:e2e tests/e2e/demoMode.e2e.spec.ts

These guides ship with Tolk Starter 0.6.0: buyers get the same pages in their repository, next to the code they describe.