Skip to main content
FlowFn
IntegrationsTemplatesPricingDocsBlogSign inStart free
All documentation

Public sheet writes

UpdatedJun 20, 2026Reading time2 min read

How public visitors write to a sheet

A Database isn't a publishable surface on its own — it has no public URL. Visitor writes reach a sheet only through a published playground that links the Database (linked_database_id). The playground renders the UI; the SDK's flowfn.data.insert / update / delete calls land on the linked sheet. See Using Data Sheets from a Playground.

The gate

Every public write must clear all of these, or it's rejected before touching the data:

  • Per-sheet opt-in. Each sheet has three flags — allow_public_insert, allow_public_update, allow_public_delete — all off by default. Only the operations you turn on are callable from the public iframe; a disabled write fast-fails in the SDK with err.code === 'sheet_write_disabled'.
  • Plan gate. Public sheet writes are plan-gated alongside the rest of Data Sheets (allow_data_sheets).
  • Published playground. The linking playground must be published and publicly reachable; writes through a draft or private playground don't apply.
  • Rate-limited. Public write endpoints are rate-limited per IP to blunt abuse.

When all three sheet flags are off, the sheet stays strictly read-only from the public page — reads still work, writes don't.

No per-row ownership

When updates or deletes are enabled, any visitor with the playground link can mutate any row — there's no per-visitor row ownership. If you need authenticated-per-user semantics, leave update / delete off and route mutations through a gated workflow trigger or server-side fetchData entry instead. A public delete is a soft delete: the row leaves all reads immediately but you can restore it from Recently deleted within 90 days. There is no public restore.

Row actions run the linked playground's server code

A sheet can carry up to 10 owner-defined row actions — "admin buttons" on each row that call an exported function in the Server tab of the playground that links the Database. Because server functions live on a playground, a database with no linked playground has no row actions to run. The function receives { id, row, row_id, action, sheet } (id is the primary-id column's cell, or the stable row_id when unset), plus an optional input when the action defines a prompt. Row actions are owner-only — they're never exposed to public or embed visitors.

Sheet-full errors

A public insert at the plan's row cap (max_data_sheet_rows) rejects with err.code === 'sheet_full'. Handle it in your playground JS to show a friendly message instead of retrying.

Spotted an issue or have feedback?

support@flowfn.com
Back to docs hub →