Thank you for being patient! We're working hard on resolving the issue
Ephemeral sheets can be encoded directly into a URL so the client renders them without a server round-trip. This is useful for sharing previews, demos, or programmatically generated sheets via a link.
Two URL formats are supported. Both produce a URL under /sheet?... that
the app detects and renders on load.
Encode the full EphemeralSheet JSON as a URL-escaped ?e= parameter.
Supports all sheet features including attributes and children.
/sheet?e=%7B%22id%22%3A%22abc%22%2C%22title%22%3A%22My+Sheet%22%2C...%7D
Build with EphemeralSheetSerde.buildJsonUrl():
import { EphemeralSheetSerde } from "@lona-js/ephemeral-sheet-serde";
const url = EphemeralSheetSerde.buildJsonUrl({
id: crypto.randomUUID(),
title: "Garmin Stress",
timeScale: "week",
rows: [{
id: crypto.randomUUID(),
type: "data",
label: "Stress",
lookupKey: ":~garmin:stress",
timeScale: "week",
}],
});
Sheet metadata and row fields are individual query params. Human-readable and hand-constructible — no encoding tools needed.
/sheet?title=My+Tasks&timeScale=week&r0.type=task&r0.label=Work&r0.ts=day&r1.type=task&r1.label=Personal&r1.ts=day
| Param | Description | Default |
|---|---|---|
title | Sheet title | — |
timeScale | year, month, week, or day | — |
id | Sheet ID | auto-generated |
d | Anchor date (ISO format) | today |
Each row uses an index prefix (r0, r1, r2, ...):
| Param | Description | Default |
|---|---|---|
rN.type | Row type (required) | — |
rN.label | Row label | — |
rN.ts | Row time scale | day |
rN.key | Row lookup key | — |
rN.id | Row ID | auto-generated |
Single task row:
/sheet?title=Work&timeScale=week&r0.type=task&r0.label=Deadlines&r0.ts=day
Two data rows with lookup keys:
/sheet?title=Health&timeScale=week&r0.type=data&r0.label=Weight&r0.ts=day&r0.key=:~weight&r1.type=data&r1.label=Sleep&r1.ts=day&r1.key=:~sleep
Build programmatically with EphemeralSheetSerde.buildIndexedUrl():
import { EphemeralSheetSerde } from "@lona-js/ephemeral-sheet-serde";
const url = EphemeralSheetSerde.buildIndexedUrl({
id: crypto.randomUUID(),
title: "My Tasks",
timeScale: "week",
rows: [
{ id: crypto.randomUUID(), type: "task", label: "Work", timeScale: "day" },
{ id: crypto.randomUUID(), type: "task", label: "Personal", timeScale: "day" },
],
});
EphemeralSheetSerde.parse() auto-detects the format. If ?e= is present
it uses Format 1; if r0.type is present it uses Format 2.
const params = new URLSearchParams(window.location.search);
const result = EphemeralSheetSerde.parse(params);
if (result) {
const { sheet, anchorDate } = result;
await client.open({ ephemeral: sheet });
}
Both formats support an optional d parameter to set the initial viewport
date. If omitted, defaults to today.
/sheet?title=Retro&timeScale=week&r0.type=text&r0.label=Notes&r0.ts=day&d=2026-01-01
attributes, children, formula, or other
advanced row fields. Use Format 1 for complex sheets.