Something went wrong

Thank you for being patient! We're working hard on resolving the issue

Ephemeral Sheet URLs - Lona Docs Log in

Ephemeral Sheet URLs

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.

Format 1: JSON blob

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",
  }],
});

Format 2: Flat indexed params

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

Sheet params

ParamDescriptionDefault
titleSheet title
timeScaleyear, month, week, or day
idSheet IDauto-generated
dAnchor date (ISO format)today

Row params

Each row uses an index prefix (r0, r1, r2, ...):

ParamDescriptionDefault
rN.typeRow type (required)
rN.labelRow label
rN.tsRow time scaleday
rN.keyRow lookup key
rN.idRow IDauto-generated

Examples

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" },
  ],
});

Parsing

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 });
}

Anchor date

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

Limitations

  • Format 2 does not support attributes, children, formula, or other advanced row fields. Use Format 1 for complex sheets.
  • URL length limits vary by browser (typically 2000-8000 characters). Format 2 is more compact for simple sheets.

See also

  • Sheets — sheet lifecycle, handles, and tree structure
  • Rows — row types and operations