# Guest writes

Visitors who aren't signed in add data, through statements you publish: sign-ups, votes, feedback, scores.

**When to use it:** Visitors who aren't signed in add data: a sign-up sheet, a vote, feedback, a high score. Save it in the database.

**Status:** Live. **Turned on:** Off by default. An admin turns on "Pages can save data for people who are not signed in" in the space's Settings, under Guests. Public spaces only.

## How

Publish named statements in db/guest-writes.sql ("-- name: vote", then one INSERT, UPDATE or DELETE; $guest and $guest_id are filled in by the server). In the page, hide the form when `(await cloudtifact.ready).guestWrites === false`; `null` means try. Then cloudtifact.guest.set(name) once and cloudtifact.db.run("vote", params) on submit.

```sql
-- db/guest-writes.sql, next to the page. Publishing replaces the whole set.
-- name: vote
INSERT INTO votes (idea_id, voter, bucket) SELECT ?, $guest, substr($guest_id, 1, 4)
  WHERE (SELECT count(*) FROM votes WHERE bucket = substr($guest_id, 1, 4)) < 3;
```

```html
<form id="vote" hidden><button name="idea" value="1">Vote</button></form>
<script>
  async function vote(ideaId, name) {
    const { guestWrites } = await cloudtifact.ready;
    if (guestWrites === false) return;
    await cloudtifact.guest.set(name);
    await cloudtifact.db.run("vote", [ideaId]);
  }
  cloudtifact.ready.then(({ guestWrites }) => {
    if (guestWrites === false) return;
    document.getElementById("vote").hidden = false;
  });
</script>
```

## Limits

- Public spaces only; off until an admin turns it on.
- 120 writes per browser and 300 per address every 10 minutes.
- Params are strings up to 4 KB, numbers, booleans or null. Every write is logged with who and roughly where from.
- Visitors can read every table, so never store $guest_id itself; keep a short prefix if you need a bucket for caps.

## Errors

A failed call rejects with an Error whose `code` is one of:

| Code | When |
| --- | --- |
| `no_guest` | Call cloudtifact.guest.set(name) first. |
| `forbidden` | Guest writes are off for this space, or the page was opened by a private link (no guests there). The bridge refuses it before the page tries. Hide the form when ready's guestWrites is false; unanswered (null) still try. |
| `rate_limited` | Too many writes from this browser or address; wait a few minutes. |
| `bad_request` | No statement with that name, or the params don't fit it. |
| `network` | The request didn't reach Cloudtifact (offline, blocked). |
| `timeout` | No answer in time; try again. |

## Cost

Included in every plan.
