Fast rendering
Goal: the artifact shows content — or at least its structure — immediately, never a blank screen, while data loads in the background.
What the viewer already does for you
Section titled “What the viewer already does for you”- The viewer wrapper streams a branded loading skeleton instantly (free — no code).
- Your artifact HTML streams from the CDN, so static markup paints as it arrives.
- The SDK posts
shareout:content-readyautomatically once your data calls settle; the wrapper then removes the skeleton.
You don’t build a skeleton yourself. Your job is to make the moment after the skeleton fast and correct.
The three speed tiers
Section titled “The three speed tiers”| Content | Speed | Guidance |
|---|---|---|
| Static HTML (headings, labels, layout, copy) | Instant — streams and paints | Put real structure/text in the markup, not empty <div>s filled by JS |
sdk.json / sdk.table() | Instant — server-prefetched and injected | First-paint data should come from here |
sdk.connection().query() / live REST | 1–3s — live warehouse/API query | Never block first paint on these |
- Ship real static HTML. Headings, layout, labels, units, empty states — in the markup. The page should look like itself before any JS runs.
- First-paint data from
json/table. These are prefetched server-side and injected into the page, soawait sdk.json.get('snapshot')resolves with zero network round-trip. - Don’t run live queries on load. Precompute them into
sdk.json(or a table) with a scheduledquery_snapshotjob, then read the snapshot. - Load in parallel, hydrate per section. If you must fetch at runtime, use
Promise.alland fill each section as its data arrives. - Signal readiness when painted. Call
ShareOut.ready()after your render completes (tables drawn, charts mounted) to remove the skeleton at the exact right moment. If you omit it the SDK auto-detects readiness (network-idle); calling it is crisper on chart-heavy pages.
Snapshot-first dashboard (fast)
Section titled “Snapshot-first dashboard (fast)”const sdk = await ShareOut.create();// Instant: precomputed snapshot, injected by the server (no round-trip).const s = (await sdk.json.get('snapshot')) || {};renderTables(s);await mountCharts(s);ShareOut.ready();Refresh the snapshot key on a schedule with a query_snapshot job so the live
warehouse hit happens off the critical path. See Crew for narrating
snapshots on a later cron.
Live query on load (slow — avoid)
Section titled “Live query on load (slow — avoid)”const sdk = await ShareOut.create();// 1–3s blank: the warehouse runs the query before anything renders.const rows = await sdk.connection('warehouse').query('SELECT ...');render(rows);Use a live query only behind an explicit user action (a “Run” button), never for first paint.
Progressive hydration
Section titled “Progressive hydration”const sdk = await ShareOut.create();renderShell(); // static structure paints instantlyconst [kpis, events] = await Promise.all([ sdk.json.get('kpis'), sdk.table('events').query({ limit: 100 }),]);fillKpis(kpis);fillTable(events);ShareOut.ready();Checklist
Section titled “Checklist”- Page structure (headings, layout, labels) is in the HTML, not built only by JS
- First-paint data reads from
sdk.json/sdk.table(), not a live query - Live
connection.query()is precomputed viaquery_snapshot, or gated behind a user action - Runtime fetches run in parallel and hydrate per section
ShareOut.ready()is called once the page is painted
Related
Section titled “Related”- SDK overview —
ShareOut.create(),ShareOut.ready(),sdk.me() - Scheduling jobs —
query_snapshotfor off-path warehouse refresh - Live data — connection queries and the two-origin sandbox