Appearance
Storage
approvedThe player's browser storage: what is stored, under which key, in which shape, and how the mechanism behaves. Implementations follow this contract exactly; nothing about storage is left to interpretation.
What is stored, and why
Exactly one thing: the user state, the three properties the user owns through the player's visible controls (see the config contract's user state section):
- volume and mute
- playback rate
- captions on or off, and the chosen track language
Stored as intent, the values let preferences survive page loads and later visits on the same site. Nothing else is ever written: no analytics, no identifiers, no playback positions, no configuration.
The key
text
lt-player:user:v1The pattern is <product>:<domain>:<schema version>:
| Segment | Value | Meaning |
|---|---|---|
| product | lt-player | Namespace, preventing collisions with the hosting page's own storage |
| domain | user | The data domain; today the only one |
| schema version | v1 | Versions the shape of the stored value, and nothing else |
Versioning, deliberately independent of the config version
The config contract's version (currently 3) versions the public configuration JSON between hosting pages and the player, and bumps with the player major. The storage schema version versions this private little object, which no page and no integrator ever touches. The two evolve independently, so user preferences survive player major releases: player 4 keeps reading v1 as long as the stored shape is unchanged. A v2 appears only when this object's shape itself changes incompatibly; the new version reads only its own key, and older keys are left in place untouched, since they are the user's data, not ours to clean up.
The value
One JSON object; every field optional:
json
{
"volume": 0.8,
"muted": false,
"playbackRate": 1.5,
"captionsEnabled": true,
"captionsLanguage": "de"
}| Field | Type | Valid range | Meaning |
|---|---|---|---|
volume | number | 0 to 1 inclusive | Last volume level the user set |
muted | boolean | Last mute state the user set | |
playbackRate | number | finite number greater than 0 | Last rate the user chose, kept as intent |
captionsEnabled | boolean | Whether the user wants captions | |
captionsLanguage | string | BCP 47 tag | The caption language the user chose, kept as intent |
Reading rules:
- A missing field means no preference; the built-in default applies.
- Each field is validated on read; a field outside its type or range is treated as absent. A value that does not parse as JSON at all is discarded entirely and silently, with no console output. Invalid stored data does not change the storage backend; the next explicit user change repairs the key with a sanitized whole-object write.
- Unknown properties are ignored and dropped on the next write: the player owns this schema.
Behavior
- Creation is lazy. No key is written until the user's first explicit change (a volume adjustment, a rate cycle, a captions toggle). Merely watching a video creates nothing: the entry exists only because the user expressed a preference.
- Read once, write through. Read once per instance creation (hydration); written as one whole object on every explicit user change, read-modify-write, last writer wins.
- No live sync. The player never listens for storage events. Two instances or two tabs do not mirror each other mid-play; every newly created instance starts from the latest stored state.
- Fail-safe, always. Every storage operation is wrapped: private browsing, unavailable, partitioned, or denied storage inside embed iframes, quota errors, and thrown acquisition, read, write, or serialization operations degrade silently to in-memory state for the session. A storage-access problem must never affect playback and never reaches the user, nor the console as an error.
Scope and privacy
localStorage is per origin, and browsers partition it for embedded iframes by the embedding site, so preferences follow the user per site and never travel between sites. This is functional storage in the strict sense: created only by the user's own explicit choices, stored only on their device, never transmitted anywhere, and unreadable by Latest Thinking or by the hosting page's servers. It therefore requires no consent mechanism and no configuration switch.