← Back to docs

Guestbook hosting

Guestbook hosting

Tools can host multiple separate public guestbooks. /guestbook is the Tools default/demo guestbook. Other books receive their own slug and public URL.

Create a guestbook

Administrators can create a guestbook directly from the main guestbook administration page at /admin/guestbook. The same creation form is also available on the full hosting manager at /admin/guestbook/hosting.

Enter:

  • Name - public title, for example Miazma.
  • Slug - URL identity, for example miazma.
  • Theme - tools, miazma or terminal.
  • Active - whether the book is active in Tools.
  • Publicly hosted - whether the book is actually exposed publicly on its slug.
  • Site URL, Site language and Site / guestbook description - optional context for the site and expected guestbook content.
  • Embed behaviour - optional per-book controls for rich text, public fields and direct signing. New and existing books use safe read-only plain-text defaults until these capabilities are enabled.

Creating a guestbook from /admin/guestbook keeps the administrator on the main guestbook page so the new book can immediately be selected as an import destination. Use /admin/guestbook/hosting for full guestbook management, including editing, embed information, purging entries and deleting a book.

An active and publicly hosted book with slug miazma is available at:

https://tools.tornevall.net/guestbook/miazma

Theme and guestbook identity are separate. /guestbook/miazma selects the Miazma data. ?theme=miazma only selects presentation.

Existing imported legacy books are listed on the hosting page and can be assigned the correct slug and theme without importing them again. Imported books are not published automatically. Publicly hosted must be enabled explicitly.

JavaScript embed

The guestbook management pages generate embed snippets using the lightweight extensionless loader endpoint in the reserved /_embed/ namespace:

https://tools.tornevall.net/guestbook/{slug}/_embed/loader

A minimal embed only needs the script tag placed where the widget should appear:

<script src="https://tools.tornevall.net/guestbook/miazma/_embed/loader"></script>

When no target is supplied, the script creates a container next to the script tag automatically.

To render into a specific element, use target:

<div id="miazma-guestbook"></div>
<script src="https://tools.tornevall.net/guestbook/miazma/_embed/loader?target=miazma-guestbook"></script>

Loading indicator

The loader renders a loading indicator immediately and then requests the extensionless /_embed/runtime endpoint. All query parameters are forwarded, including target, limit, page, theme and refresh.

<div id="miazma-guestbook"></div>
<script src="https://tools.tornevall.net/guestbook/miazma/_embed/loader?theme=miazma&limit=10&target=miazma-guestbook"></script>

If the runtime request fails, the loader changes to a visible error state with a Retry button instead of leaving an empty page. The loader endpoint does not fetch or serialize guestbook entries itself, so the waiting state appears before the heavier guestbook request begins.

The extensionless /_embed/loader, /_embed/runtime and /_embed/data paths are the canonical endpoints for new integrations. The reserved namespace avoids collisions with guestbook slugs. Older dotted .js and .json paths remain application compatibility aliases where they are routed to Tools, but generated snippets no longer use them because asset-routing layers can otherwise treat a dynamic response as a missing static asset.

Supported query parameters:

  • target - element id where the guestbook should render.
  • limit - number of entries per page, normally 10 and at most 50.
  • page - initial page number, starting at 1.
  • theme - temporary presentation override: tools, miazma or terminal.
  • refresh - automatic refresh interval in seconds, or 0 to disable refresh.

The embed renders inside Shadow DOM so the guestbook CSS does not interfere with the surrounding site.

Rich content and public fields

Each guestbook can independently enable Markdown, a small safe HTML subset and automatic HTTP/HTTPS URL linkification. All rendered rich markup is sanitized on the Tools server before it reaches the embed. Scripts, event-handler attributes, embedded active content and unsafe URL schemes such as javascript: are removed.

Owners and administrators can also select which ordinary fields the public embed may show: visitor name, city, coarse country flag, date, homepage and message. E-mail addresses and source IP addresses are private and are never included in public embed data. DNSBL state is also private moderation/admin data and cannot be selected as a public field.

For compatibility, /_embed/data keeps the plain message value when the message field is enabled and also returns sanitized message_html for rich rendering. Browser code must treat message as text, not as HTML.

Pagination

The JavaScript embed uses real server-side pagination. When a guestbook contains more entries than limit, the widget shows Previous, clickable page numbers and Next. Small page sets show every page number. Larger page sets keep the first and last page visible and show a compact window around the current page with ellipses between skipped ranges. The current page is marked visually and with aria-current="page".

Only the selected page is fetched from Tools. Clicking a page number jumps directly to that page without loading the rest of the guestbook.

The corresponding /_embed/data response contains an entries array and a pagination object with page, per_page, total, last_page, from, to, has_previous and has_next. Requests for a page beyond the last available page are clamped to the last page.

Automatic refresh keeps the visitor on the currently selected page instead of jumping back to page 1.

Public entries can show a country flag next to the visitor's location. Tools derives only the country code and flag server-side from the private source IP using the local MaxMind GeoLite2 lookup. The raw IP and detailed GeoIP data remain private. If no country can be resolved, no placeholder is shown. DNSBL status remains available for moderation and administration but is not rendered as public commenter decoration.

Signing

Direct signing inside an external JavaScript embed is disabled by default for every guestbook. An owner or administrator can explicitly enable Direct signing for an active publicly hosted book and choose whether the form contains name, city, homepage and private e-mail. Message is always required.

When enabled, the embed posts directly to the hosted book's public /_embed/data endpoint. No Tools API key is sent to the browser. The submission endpoint is rate-limited, uses a honeypot field and supports cross-origin form submissions from the embed. The source IP and optional e-mail can be stored privately for abuse handling and moderation but are never returned in public embed output.

A best-effort DNSBL check can run after the entry is stored. A DNSBL lookup failure does not discard the visitor's entry; the operational failure is logged for Tools diagnostics while DNSBL details remain private.

If direct signing is not enabled, the widget remains read-only and the Read or sign the guestbook link opens the full hosted guestbook on Tools, where the existing Cloudflare Turnstile-protected signing flow remains available.

Tools default guestbook

The Tools guestbook remains available at:

https://tools.tornevall.net/guestbook

Its generated/default embed loader is available at:

https://tools.tornevall.net/guestbook/_embed/loader

The direct runtime is available at:

https://tools.tornevall.net/guestbook/_embed/runtime

The public paginated data endpoint is:

https://tools.tornevall.net/guestbook/_embed/data

Hosted guestbooks are filtered by guestbook_id and are not shown in the Tools default guestbook.