Build apps
Data with crow.db
crow.db gives every app its own database of JSON documents, used straight from the page. There's no schema to set up and no keys: create a collection by adding to it, and set who can read and write in crow.json.
Load the library
<script src="/__crow/sdk.js"></script>It's served by the app's own address, so it always matches. It defines window.crow; every call returns a Promise.
Who is using the app
const me = await crow.me(); // { id, email, name } for a signed-in viewer, or null when signed out
if (!me) crow.signIn(); // sends them to sign in and back to this pageAdd, read, change, remove
const tasks = crow.db.collection("tasks");
const doc = await tasks.add({ title: "Ship it", done: false }); // the saved document with id, createdBy, createdAt, updatedAt
const one = await tasks.get(doc.id); // the document, or null
await tasks.update(doc.id, { done: true }); // merges the fields you pass
await tasks.remove(doc.id);Documents are up to 64 KB each. Crow Nest sets four fields you can read but not change: id, createdBy, createdAt and updatedAt (epoch milliseconds).
Query
const page = await tasks.list({
where: [["done", "=", false], ["priority", ">=", 2]], // up to 4 filters: = != < <= > >=
order: "-createdAt", // one field; "-" for descending
limit: 50, // 1 to 200, default 50
});
// page = { docs: [...], cursor }. Pass { ...the same query, cursor: page.cursor } for the next page; cursor is null at the end.Watch for changes
const stop = tasks.watch({ order: "-createdAt" }, (page, err) => {
if (err) return console.error(err);
render(page.docs);
});
// stop() ends it.watch updates live when people change the collection, and falls back to checking every 5 seconds when live updates aren't available.
Who can read and write
Set rules per collection in crow.json. Collections you don't list default to read: "viewers" and write: "creator".
{
"data": {
"tasks": { "read": "viewers", "write": "creator" },
"settings": { "read": "viewers", "write": "owner" }
}
}read | Who sees documents |
|---|---|
public | Anyone who can open the app, signed out too |
viewers | Signed-in people who can open the app |
creator | Each person sees only their own |
owner | Only the app's owner |
write | Who adds and changes |
|---|---|
viewers | Anyone signed in adds and changes anything |
creator | Anyone signed in adds; people change only their own |
owner | Only the app's owner |
public | Signed-out visitors add, and change their own entry |
public-add | Signed-out visitors can only add |
Finding "mine"
By default other readers see only an author's id: createdBy is { id }. Compare it with the viewer:
const me = await crow.me();
const mine = page.docs.filter((d) => d.createdBy.id === me.id);To show more, set showCreator to name or email on the collection (not allowed with read: "public").
Entries from signed-out visitors
On a public app, a collection can take entries from people who aren't signed in: a booking page, a contact form, a game's high scores.
{
"data": {
"rsvps": { "read": "owner", "write": "public", "fields": { "name": "string:80", "email": "email?", "slot": "string:40" }, "unique": ["slot"], "editFor": "7d" },
"scores": { "read": "public", "write": "public-add", "fields": { "name": "string:30", "score": "integer" }, "dailyLimit": 2000 }
}
}fieldsis required: entries must match it exactly. Types arestring,string:N,number,integer,boolean,email,date,datetime, with?for optional.uniquestops two entries sharing the same values, like one booking per slot. A clash answersconflict.- With
public, a visitor can change their own entry later from the same browser, for as long aseditForallows.collection.editLink(id)gives a link that lets them do it from another device. - The library runs the bot check itself. Signed-out visitors can add 5 entries a minute and 50 a day each, and
dailyLimitcaps the collection. - The owner can block a visitor's entries from the dashboard's Data tab.
Errors
Calls throw an Error with a code: sign_in_required (a change by a signed-out visitor sends them to sign in), forbidden, not_found, bad_request, too_large, limit_reached, rate_limited, conflict, edit_closed or payment_required. See Error codes.
Limits
60 writes a minute per person; 100 MB of data per app (1 GB for companies). See Limits.
Seeing what's saved
The dashboard's Data tab shows each collection with its count, rules and recent documents, and exports everything as JSON. Your AI can use tool_data for the same view.