Documentation

Everything in RowFold, explained.

The same guide that powers in-app help — every view, field type, permission, automation, and the full API. Signed in, press F1 on any page for help about exactly where you are.

Getting started
Getting started

Getting started with RowFold

RowFold is a workspace of related tables — customers, projects, invoices, anything you track — with views, reports, and AI on top. This article walks you from creating an account through onboarding, templates, your first workspace and table, and a quick tour of Home, the sidebar, and the ⌘K palette.

Create your account

On the sign-up page, name the team or workspace and enter your email address. That is the whole opening form: no password, name field, or terms checkbox before you see RowFold build. Continue with Google or Microsoft if you prefer.

After the workspace is ready, an email signup creates the password it will normally use. Google and Microsoft signups skip that step because their identity provider is the credential. A one-time email link remains available as an alternative whenever you do not have your password handy.

If the address already belongs to an account or an unclaimed invitation, RowFold never opens a session from the typed address alone. It sends a sign-in link to that mailbox instead, so only its owner can continue.

Signing up starts your 30-day free trial: every feature is on from the first minute, no card required.

Walk through onboarding

Right after sign-up, RowFold carries your sentence forward as the AI brief. It deliberately does not draw or list a predicted schema: the signed-out illustration uses small local rules, while the authenticated AI builder reasons about the full workflow. You can change the workspace name, icon, or colour, open the template library, import a spreadsheet, or start blank.

Choose Build it to open the real builder. It reports the current phase immediately, adds a checked and linked line whenever an artifact really exists, and keeps its brief, conversation, and progress on the server. Refreshing or losing the connection therefore offers Resume build instead of starting over.

Explicit templates still show their known contents and build in the background while the optional invitation page is open. AI setups offer invitations after the workspace is ready, so inviting people never stands between you and the first result.

The completed AI screen offers an email signup a password on the way in — skippable, since emailed sign-in links keep working either way. On Home, a chip beside the ✓ Built banner offers a 60-second tour of the chrome (the workspace switcher, tables, search, and the rail); it never plays uninvited, and you can replay it any time from the bottom of this help panel.

Choose a template or start blank

A template creates a set of pre-wired related tables — complete with relation, lookup, and rollup fields, plus sample records so nothing looks empty. Onboarding leads with one recommendation and keeps Service Business, Project Delivery, Sales CRM, Product Roadmap, Talent Pipeline, Issue Tracker, Editorial Calendar, Events Co., Inventory & Supply, and Blank workspace behind Pick a different starting point.

The full gallery lives on the Workspaces page. It goes much further — real-world setups like Cedarwood Salon Booking, Cedar Veterinary, Heritage Realty, Compass Magazine, Long Road Podcast, Velocity Legal, and Riverstone Academy, plus personal workspaces such as a wedding, trip, library, garden, or tabletop campaign.

Your account has one home for its data, and a template pours into it — its tables land together in their own folder beside anything already there, able to relate to it rather than sitting on an island. Trying one is cheap for that reason, not because you can spin up a second account and throw it away. See Folders, not separate workspaces.

The gallery presents each template as a worked example business; when one carries into sign-up and onboarding, its card is titled by what it does — Veterinary practice, Inventory & supply — and a first build files its tables under your workspace's name, not the example company's.

Invite teammates

AI-first onboarding offers invitations after the build; template onboarding can show them while its background build runs. Type an email, choose Editor (the default), Viewer, or Admin, and press Add or Enter. Paste a comma-, space-, or line-separated list to add several at once.

The step is optional: Open it now or Open without inviting always remains available. Everyone you do add becomes a member with the chosen role, and an unclaimed address receives a secure invitation path. You can invite more people later from People & access.

Editors and Admins take a paid seat only if you move to Team after the trial; read-only Viewers remain free.

Find your way around Home

Home greets you with a snapshot: counts of tables, records, relation fields, and teammates, plus a Jump into button for your busiest table. Your tables shows a card per table — click one to open its records — and while you have at least one table but fewer than eight, a dashed New table card rounds out the grid. Recently touched lists the six most recently updated records across the workspace.

The Getting set up checklist tracks four milestones — Create your workspace, Add your first table, Add records, and Connect tables with relations — and each row links straight to the page where you do it. The Ask RowFold card opens the search-and-ask palette, and a small card below it points you into the rail's Workspace section for schema, automations, and permissions.

Get around: the sidebar and views

The left sidebar (the rail) is your map. At the top sit the RowFold logo — a click takes you Home — and the workspace switcher, which opens the Workspaces page to switch between the workspaces you belong to. Below come Home, Ask RowFold (it wears an AI badge when an AI model is configured), and your Tables list with live record counts. Under that, a Workspace section gathers everything you build and govern — Reports, Schema & relations, People & access, Permissions, Import data, Automations, Developers, and Audit log. Your avatar, Settings, and sign out live at the bottom.

Select a table and the view pills appear under it: Grid, Board, Gallery, Calendar, Gantt, and Map. They are the same table through different lenses — switching views never changes your data.

Once you star items, a ⭐ Starred section appears in the rail for one-click access.

One rail, no modes

There are no separate modes to switch between: browsing records, editing values, switching views, and asking questions all share the same rail as the structural work. Designing tables and fields, the schema map, permissions, import, automations, the developer API, and the audit log are simply the entries gathered under the rail's Workspace section — always one click away, never tucked behind a separate mode.

To create a table, open the Tables page and press New table: give it a Table name, pick a Template type (Custom starts blank; other types come pre-built with their typical fields), and press Create and add fields → to refine it. There's also Build with AI, which turns a plain-English description into a connected set of tables — you approve before anything is created. Both options appear only for workspace Admins.

Search and ask with ⌘K

Press ⌘K (or Ctrl+K) anywhere to open the palette. Type to search tables and records, move with , open with Enter, and close with Esc. The same box accepts plain-English questions about your data.

Prefer to go straight to asking? ⌘/ (or Ctrl+/) opens the ask prompt directly, and Ask RowFold in the sidebar opens the full page.

Keyboard shortcuts

⌘/CtrlK Open or close the search palette Anywhere
⌘/Ctrl/ Open the ask prompt directly Anywhere
↑ / ↓ Move through results ⌘K palette
Enter Open the highlighted result ⌘K palette
Esc Close the palette or open panels Anywhere
Enter Add the typed email to the invite list Onboarding invite step
Getting started

Folders

Folders keep a growing account tidy — "Sales", "Ops", one per client — without ever splitting your data. A table in one folder relates to a table in another exactly as it would if they sat side by side.

Folders, not separate workspaces

Your account has one home for its data, and everything in it can relate to everything else. Folders are how you organise inside it — Sales, Ops, one per client — and they are deliberately not walls: a Deals table in one folder can link to a Companies table in another, follow lookups across it, and roll values up through it.

That is the whole reason folders replaced separate workspaces. Every boundary between workspaces is a place where relationships stop, and relationships are the point.

Tables in different folders can still be linked, rolled up and reported on together — a folder is a drawer, not a wall.

Folders appear when you need them

A brand-new account shows a plain list of tables and no folder chrome at all. The moment you add a second template or build a second area, folders appear on their own and each build sits in its own.

Right-click anything in the table list to act on it. On a table: Rename table…, Change icon…, and the folders you can move it into. On a folder heading: Rename folder…, Change icon…, New folder… and Delete folder… — deleting a folder frees its tables to the top level and deletes no records. Every table row also carries a grip on its left, and every folder heading one on its right. Drag a grip to reorder tables and folders, drop a table onto a folder heading to file it inside, or drop it among the ungrouped tables at the top of the list to take it out of every folder. A line shows exactly where it will land; a folder tints when the table will go inside it. On a phone the grip is always visible, so all of this works by touch as well. You can also focus a grip and move it with the arrow keys.

All of it needs Admin, and all of it is also a form in the table's own field editor — Name & icon and Folder — if you would rather use the keyboard. Renaming a table changes its label everywhere and nothing else: its API key and every field key stay exactly as they are, so saved views, automations and integrations keep working.

Give someone a whole folder

Open Permissions, pick a person, and set their access on the Folder access card. One setting covers every table in that folder — so “the contractor gets the Acme folder” is a single action rather than one grant per table.

A table's own override always wins over its folder's, so a deliberate per-table decision is never quietly overruled by a broader one.

Hide a folder completely

Mark a folder hidden and it disappears for everyone without an explicit grant — not greyed out, not locked, gone. Its name goes too, which is usually the point: a “Cost Savings” folder sitting there locked still tells the room it exists.

A folder is listed only when at least one table inside it is visible to you. Admins always see everything.

Invite people and set roles

Open the workspace's People page to see everyone with access. Each member card shows their role and a plain-English summary of what it allows. From most to least access:

  • Admin — full control: schema, members, automations, everything.
  • Editor — read, create, edit, and delete records; no schema or member control.
  • Contributor — read everything and create new records; cannot edit or delete records that already exist.
  • Viewer — read-only, for stakeholders who only need visibility.

Only workspace Admins can manage membership. Use the role dropdown on a member's card to change their role, Remove to revoke their access, or + Invite to add someone with a starting role. The picker under Invite someone lists only people you already share a workspace with — if all of them are members already, the invite form doesn't appear.

Transfer ownership

To hand a workspace to someone else, open Settings and find Transfer workspace ownership in the Danger zone. Choose the member to promote and click Transfer: they become that workspace's Admin and you are moved to Editor there.

You can only transfer a workspace you administer, and only when it has at least one other member.

Leave, export, or wind down

Removing a member — or being removed — only revokes access. The workspace and everything in it stays put for its remaining members, and there is no button for deleting a whole workspace.

Before winding anything down, grab your data from Data export in Settings: Full workspace JSON covers schema and every record across all your workspaces, and CSV per table downloads a zip with one CSV for every table you can access. To close your account, type your email to confirm and click Delete account — your profile, memberships, and permission overrides are removed, shared workspaces remain for their other members, and it cannot be undone.

Getting started

Concepts & glossary

Learn the words RowFold uses — workspaces, tables, fields, records, views, relations, and reports — and how the single rail and its Workspace section fit together, so the rest of the app makes sense at a glance.

Learn the vocabulary

  • Workspace — the top-level home for a set of related tables, with its own members and roles. You create one from a template or start blank.
  • Table — a list of one kind of thing: tasks, customers, invoices. Each table has its own fields and records, plus an emoji and accent color so you can spot it in the rail.
  • Field — a column in a table. Types include Text, LongText, Number, Currency, Date, Boolean (a true/false check), Select and MultiSelect, Email, Url, Phone, Percent, Rating, Progress, and People, plus the linked types below.
  • Record — a single row in a table: one task, one customer. Every record has a display name, and deleted records go to the Trash where they can be restored.
  • View — a layout for the same records. Every table offers Grid, Board, Gallery, Calendar, Gantt, and Map. Switching views never changes your data.
  • Relation (link) — a field that connects a record to one or more records in another table of the same workspace.
  • Lookup — a field that shows a value pulled through a relation from a linked record. Edit the source record and the lookup follows.
  • Rollup — a field that summarizes linked records with a count, sum, average, minimum, or maximum.
  • Report — a saved summary of one table, shown as a table, a single KPI number, or a chart that can flip between bar and line and plot several columns at once — with filters, sorting, and grouping. Date groups can be bucketed by day, week, month, quarter, or year.
  • Ask RowFold — ask questions about your data in plain language from the rail or the search palette; answers cite the records they draw on.
  • Automation — a rule that watches a table and acts: a trigger (a record created, updated, deleted, matching conditions, or a schedule), optional conditions, then steps such as updating fields, creating records, sending email, calling a webhook, or generating text with AI.
  • API token / webhook — an API token is a workspace-scoped key (a signed JWT) for calling the REST API at /api/v1; a webhook posts each matching record change to a URL you choose so outside systems stay in sync. Both live on the Developers page.

Understand how your data is organized

Everything nests three levels deep: a workspace holds tables, and each table holds fields (its columns) and records (its rows). The rail shows the tables of your current workspace with a live record count beside each name; click the workspace name at the top of the rail to switch workspaces or create a new one.

Relations connect records across tables in the same workspace — a task can link to a project, an invoice to a customer. Lookups and rollups then carry values along those links, so you enter a number once and summarize it wherever it is linked. Deleting a record moves it to the Trash rather than destroying it, and restoring brings it back exactly as it was.

Everything is this shape. A view is a way of showing a table, not a copy of it, which is why an edit made in one shows up in all of them.

Find your way around the one rail

RowFold has a single rail — there are no modes to switch between. The top is for working with data: Home, Ask RowFold (badged AI when an AI model is configured), and your tables, each of which expands a row of view pills when selected.

Below your tables, a Workspace section gathers everything you build, connect, and govern, in order: Reports, Schema & relations (the live schema map), People & access, Permissions, Import data, Automations, Developers (API keys and webhooks), and Audit log. Super admins also see an Admin entry. Designing a table's fields opens from the Tables list itself.

Star anything and a ⭐ Starred section appears; your avatar, Settings, and sign out sit at the very bottom.

Pick a view for the job

Select a table in the rail and six view pills appear under it: Grid for spreadsheet-style editing, Board for cards in columns, Gallery for larger cards, Calendar for dated records, Gantt for timelines, and Map for addresses. The same views are offered in the table toolbar.

Views are presentations of one shared set of records, not copies. Change a record in any view and every other view reflects it.

Find anything with the search palette

Press ⌘K (Ctrl+K on Windows) anywhere, or click Search or ask… in the top bar, to open the palette. It searches the tables and records of your current workspace; use to move through results, Enter to open the highlighted one, and Esc to close.

You don't have to decide up front whether you're searching or asking. Type something that reads like a question — “who has the most pets”, “what are the totals by status” — and the palette switches itself: the ask row moves to the top and Enter asks it instead of opening a record. Finish the question with a ? and it hands straight over to the Ask chat with your text carried across, so you can just keep typing. +/ still opens the ask dialog directly. Answers cite the records they drew on, and clicking a citation opens that record in the peek drawer over the chat.

Know what your role lets you do

Each workspace member has one of four roles. Viewers read; Contributors can also create records; Editors can also edit and delete records; Admins also control structure, members, and permissions. The New table, Add first table, and Build with AI actions only appear for workspace Admins, and the server enforces the same rule.

Admins can also fine-tune access per person: a table can be set to Full access, Read & create, Read only, or No access (hidden), and an individual field can be made Read only or Hidden for someone. Because of these overrides, two members of the same workspace may see slightly different tables and fields.

Keyboard shortcuts

⌘K / CtrlK Open or close the search palette Anywhere
⌘/ / Ctrl/ Open the ask dialog Anywhere
↑ ↓ Move between results Search palette
Enter Open the highlighted result Search palette
Enter Submit your question Ask dialog
Esc Close the dialog Search palette and Ask dialog
Getting started

Search, navigation & shortcuts

How to move through RowFold: the rail and topbar, switching workspaces, the ⌘K palette for searching or asking questions, the New button, starring, the peek drawer, and the complete keyboard shortcut catalogue.

Get around with the rail and topbar

The left rail is home base. The RowFold mark at the top takes you to Home, and just beneath it sits the workspace switcher. Below that come the Home and Ask RowFold links — Ask RowFold wears an AI badge when AI answers are configured — and then the Tables list, every table in the active workspace with its color, emoji, and record count. Click a table to open it, and the active one expands a row of view pills: Grid, Board, Gallery, Calendar, Gantt, and Map.

Under the tables, a Workspace section lists Reports, Schema & relations, People & access, Permissions, Import data, Automations, Developers, and Audit log (super admins also get Admin). A ⭐ Starred section appears once you star something, and the rail footer shows your avatar with quick links to Settings and sign out.

The topbar carries breadcrumbs (Home, the workspace, then the current page), the Search or ask… button that opens the palette, and the New button.

Switch workspaces

Click the workspace card under the RowFold mark — it shows the current workspace's icon, name, kind, and how many workspaces you have in total. It opens the workspace list, where you can switch between the workspaces you belong to — your account's own, plus any you have been invited to.

The rail lists only workspaces you're a member of, and everything in it — the table list, the palette, search results — stays scoped to the active workspace. If you don't belong to any workspace yet, the card reads Create workspace instead.

Search or ask from the palette

Press Ctrl/⌘ + K anywhere, or click Search or ask… in the topbar. Before you type, the palette offers your most recently starred records, every table with its record count, and a Navigate group with jumps to Home, Schema graph, Ask AI (labeled Ask your data when no AI model is connected), and Import data. Start typing and results refresh a beat after you pause — tables matched by name, plus records from the current workspace.

Move with , open the highlighted item with Enter, and close with Esc. The top row always offers to turn your words into a question — click it to get an answer instead of a list of matches.

You can also go straight to asking: press Ctrl/⌘ + / to open the ask panel, type a question, and press Enter. With an AI model connected the response is headed AI Answer; without one you get an Instant Answer, honestly labeled built-in analyzer — no AI used. When the answer draws on your records, citation cards appear beneath it — click one to jump to that record.

The command palette open over a dimmed grid, with “brightwater” typed in. It offers to ask RowFold that question and answer with record citations, and below, under a Records heading, the matching deal “Brightwater Group — Platform rollout”.
One box for both jobs: it finds records as you type, and hands the same text to Ask if what you typed was a question.

Create things with the New button

The New button in the topbar opens a menu of starting points:

  • Build with AI — describe what you're tracking in plain words and review a proposed set of tables, fields, and relations before anything is created. Press Ctrl/⌘ + Enter in the description box to generate. Admins only.
  • New record — jumps to a table's grid, where the quick-add row is waiting. Appears once the workspace has at least one table.
  • New table — add a table to this workspace. Admins only.
  • New workspace — start from a template or blank.
  • Import workspace — bring in CSVs or Excel; relations are detected for you.

Star tables and records

Star a record with the ☆ Star button in its peek drawer, and star a table with the star icon at the top of its page. A toast confirms each toggle.

Starred items surface in two places: the ⭐ Starred section of the rail (the first six, tables first) and the top of the ⌘K palette (your four most recently starred records). Stars are saved in this browser, so they're personal to you — and to this device.

Peek at records without leaving your view

In the grid, click a cell once to select it, then press Space — or click the expand icon that appears on the Name cell — and the record slides open in a peek drawer, no page change. In the Board and Gallery views, clicking a card opens the same drawer.

The drawer has three tabs: Fields shows every value, Activity shows what changed and when, and Graph draws a small map of related records — click any outer node to open its peek on top of the current one. Relation chips and Records that use this cards do the same, building a breadcrumb trail; click a crumb or ← Back to retrace, or press Esc to step back one record at a time.

When you want the whole page, Open full record is always in the drawer's header.

Build and govern from the Workspace section

Everything structural lives in the rail's Workspace section, no mode-switch required. Schema & relations opens the live schema map, where dragging between tables creates Relation fields; the Tables list higher up is where you design a table's fields, and a record's own detail page is where you add one-off links between two specific records. Automations builds trigger-and-step rules, and Developers manages API keys and webhooks.

Governance sits in the same section: People & access and Permissions control who can do what, Import data brings in CSVs and Excel, and Audit log shows who changed what. Super admins also see an Admin entry for the operator console.

Back out with Esc

Esc always closes the topmost thing first: the palette, the ask panel, the Build with AI dialog, the navigation drawer, then the peek drawer one stacked record at a time, then a cell edit, and finally the cell selection itself. Press it repeatedly to unwind all the way back to the page.

On small screens the rail tucks away into a slide-out drawer. Open it with the menu button at the left of the topbar; tapping the dimmed backdrop, choosing any link, or pressing Esc closes it again.

Keyboard shortcuts

Ctrl/⌘K Open or close the search palette Anywhere
Ctrl/⌘/ Open the ask panel Anywhere
Esc Close the topmost layer: palette, ask panel, dialog, drawer, peek, cell edit, then cell selection Anywhere
↑ / ↓ Move through results ⌘K palette
Enter Open the highlighted result ⌘K palette
Enter Submit your question Ask panel
Ctrl/⌘Enter Generate the schema plan Build with AI dialog
↑ ↓ ← → Move the cell cursor Grid view
Tab / ShiftTab Move one cell right / left Grid view
Page Down / Page Up Jump 15 rows down / up Grid view
Home / End Jump to the first / last cell in the row Grid view
Enter Edit the selected cell Grid view
Space Open the selected record in the peek drawer Grid view
Delete / Backspace Clear the cell (not the Name column or read-only fields) Grid view
Ctrl/⌘C Copy the cell value Grid view
Ctrl/⌘V Paste into the cell Grid view
Ctrl/⌘D Fill down from the cell above Grid view
Any letter, number, or symbol Start editing, replacing the value with what you type Grid view
Enter Save and move down (in a long-text cell, Enter starts a new line instead) Editing a cell
Tab / ShiftTab Save and move right / left Editing a cell
Esc Cancel the edit Editing a cell
Enter Add the record Quick-add row
Esc Clear and leave the box Quick-add row
Enter Apply the filter Filter value box
Esc Close the filter popover Filter value box
Getting started

Notifications, watching & live updates

The bell, watching records, and how changes appear across everyone's screens as they happen.

The bell

The topbar bell collects everything RowFold wants to tell you: records you watch changed, you were added to a workspace, an automation failed. Click any item to jump straight to its subject; Mark all read clears the badge. New items arrive live — no refresh.

Watch a record

Open any record (page or peek drawer) and press Watch. Every change lands in your bell, and optionally your inbox — tick email me changes. Watches are personal: nobody sees what you watch.

Watchpoints: tell me when a number crosses

A watchpoint is a saved number and a threshold — “overdue invoices above ten”, “pipeline under 50,000” — checked every hour, that notifies you when the number crosses the line. You create one from the Watch button on any view's toolbar, so what gets watched is exactly what you were looking at: the view's own filters become the watchpoint's, and the number is either the record count or the sum of a numeric column.

It fires on the crossing, not while the number stays there. An hourly “still above ten” for a fortnight is how people learn to ignore alerts, so a watchpoint that has already fired stays quiet until the number comes back and crosses again. Creating one while you are already past the threshold arms it silently and says so, rather than firing a stale alarm at you.

A watchpoint belongs to you, like a digest: your permissions decide the number, two people watching the same thing are two separate alerts, and if you leave the workspace yours go quiet. Manage them from My Work.

Live sync

When a teammate changes a record you're looking at, your grid updates in place within a moment — and only with data you are allowed to see; RowFold notifies your browser that something changed and your browser refetches through the normal permission checks. Creations and deletions show a small refresh pill instead of yanking the page around.

Views
Views

Grid, Board & Gallery

The main surface for working with a table's records: a spreadsheet-style grid with inline editing and full keyboard navigation, plus Board and Gallery layouts that show the same records grouped into columns or laid out as cards.

Switch views

Every table opens in the grid. The tabs above the table switch how the same records are shown: Grid, Board, and Gallery render right here, while Calendar, Gantt, and Map open their own pages.

Whichever layout you pick, you're looking at the same underlying records — a change made in the grid shows up on the board and in the gallery too. A record count sits at the right end of the toolbar, and the grid's footer shows both records and fields.

The grid loads more rows as you scroll — there is no page size to click past. Everything the toolbar does (filtering, searching, grouping, totals, export) still works over the whole table, not just the rows that have arrived.

The Deals table as a grid. Above the rows: the table name and record count, a row of view tabs reading Grid, Board, Calendar and Gallery, and the toolbar. The rows below show a deal name, a linked company chip, a coloured stage, an amount and a probability bar.
The tabs above the toolbar are this table's views. Everything below them changes when you switch; the records do not.

Create records

Click New record at the top right to open a full form. The first box is your table's first field — that's what names the record, so it's what appears in the grid's leftmost column, in lookups and in relationships. Reorder your fields on Edit fields to change which one that is. Each field gets an input matched to its type; a relation field shows + Link a record, which opens the same picker the grid uses — search the whole related table, link as many records as the field allows, or type a name that doesn't exist yet and choose Create “…”. Lookup and rollup fields are computed automatically, so they don't appear in the form.

For quick capture, use the row at the bottom of the grid: type a name and press Enter to add the record instantly, ready for the next one. Pressing past the last row drops you straight into this box, and Esc clears it. The quick-add row only appears when your role lets you create records in this table.

Edit cells in the grid

Click a cell once to select it, then click again (or press Enter) to edit. You can also just start typing — the cell opens with your text replacing the old value — or double-click to edit immediately.

Each field type gets the right editor: select fields open a dropdown of their options, yes/no fields offer a Yes/No choice, dates get a date picker, and numeric types like rating (0–5) and percent (0–100) are kept within range. While editing, Enter saves and moves down (in a long-text field it adds a new line instead — press Tab or click away to save), Tab saves and starts editing the next cell to the right (Shift+Tab goes left), Esc cancels, and clicking away saves too. Changes save immediately — there's no separate save step — and the Updated column refreshes on the spot.

Relation cells work differently: double-click one (or click it while it's selected) to open the link picker. It searches the whole related table — type to narrow, scroll for more, and the footer says how many matches are still off screen. Current links show as chips you can remove with ×, and Enter work without the mouse, and typing a name that doesn't exist offers Create “…”. Press Done or click away to save; a field set to Just one saves the moment you pick, replacing the old link. Esc is the one thing that abandons the change. Lookup and rollup cells are computed from linked records and can't be edited directly. Cells that are read-only for your role show a Read-only for your role hint and never open an editor.

Select a range, copy, paste, and fill

The cursor stretches into a rectangle: hold Shift with the arrow keys, Shift-click another cell, or press and drag across cells. Ctrl+A selects the whole page; Esc collapses back to one cell.

Ctrl+C copies the rectangle in a format Excel and Sheets understand, and Ctrl+V pastes a block straight from them — a whole column of statuses, a grid of numbers — starting at the selection's top-left corner. Pasting one value onto a selected range fills the range. Delete clears every editable cell in the selection, Ctrl+D fills the selection down from its top row, and the small square at the selection's corner is a fill handle — drag it down to repeat the selected values over the rows below, alternating pattern and all.

Every one of these lands as a single undoable step, and the toast offers Undo on the spot. Cells you can't write — computed fields, sealed records, fields that are read-only for your role — are skipped and counted, never mangled.

Share a view with people outside RowFold

Press Share in the toolbar to publish the view you're looking at as a read-only web page. Anyone with the link can open it — no RowFold account, no seat, nothing to install. It's the way to give a client a live status page or a supplier their own order list without inviting them in.

The link starts switched off: you choose the title, whether visitors may download a CSV, and an optional expiry, then press Create public link. What gets published is exactly the columns and filters you can see at that moment, and that list is frozen — adding a column to the table tomorrow does not widen a link you shared today. Re-save the panel when you do want the new column included.

Some things never travel: attachments (visitors see a file count, never the files), and nothing on the page links back into RowFold. Turn the link off at any time, or press New URL to replace it — the old address stops working immediately, which is what you want the moment a link has been forwarded somewhere it shouldn't have been. Sharing is an Admin action and every publish and revoke is recorded in the audit log.

Share works from every view surface, not just the grid — the button is in the same toolbar on the calendar, timeline and map, and publishes the same view object. The public page always renders as a table, whatever shape the view uses inside RowFold.

Search, group, and shape the columns

The search box in the toolbar scans every cell of every row — server-side, across the whole table, not just the rows on screen. It narrows whatever filters are active rather than replacing them, and the export always matches what you're looking at.

Group collects rows under headers by almost any field — a date, a price, a city, a checkbox, a single-select. A select leads with its own option order; everything else is ordered by value, so grouping by price runs 20, 100, 300 rather than 100, 20, 300. Headers carry whole-table counts, and clicking one collapses its rows (your collapse is your own — it doesn't change the view for anyone else). Four kinds of field can't group, for the same reason in each case — there is no single stored value to bucket on: a link field keeps its connections in the other table, lookups, rollups and formulas are worked out as the page loads, and multi-select, people and attachment fields hold several values at once, so a row would belong under several headers.

Columns chooses which fields this view shows and in what order, plus how tall a row is. There are four heights: Compact and Comfortable fit a cell on one line, while Tall shows two lines of a long value and Extra tall shows four, wrapping instead of cutting off. Wrapping comes with the height rather than as a separate switch, because at one line there is nowhere to wrap to. Taller rows also show more of a link field's chips before they collapse into a count. These save to the view itself, so a shared view changes for everyone — which is why on a shared view they're an admin call. Anyone else gets offered a personal view instead: your own columns, filters, sorting and grouping on the same table, visible only to you.

Size, pin and reorder the columns

Drag the right-hand edge of a header to make a column wider or narrower, or double-click that edge to fit it to what's actually in it. Drag a header itself to move the column.

Widths belong to the view, not to your browser, so the layout you set travels — to your other machine, to your colleagues, and to anyone opening a link you've published, where the layout is the whole artefact and there is no browser of theirs to remember it. Sizing a shared view is a view edit and takes the same permission as hiding a column; if you don't have it, your widths still stick, they just stay yours.

Freeze holds columns still while the rest scrolls sideways. It's a boundary rather than a per-column switch — the menu reads Freeze through this column, so picking the third one holds the first three — because a frozen column pins to the left edge and freezing the fifth while the first four scrolled would drop it on top of them. Nothing is frozen by default. The boundary counts the columns as this view renders them, so hiding or reordering one moves it with the layout instead of stranding it. The checkbox and row number always pin either way.

Totals at the foot of a column

Summarise in the toolbar (or any column's own menu) puts an aggregate in a row pinned to the bottom of the grid. Numbers offer sum, average, min, max and median; dates offer earliest and latest; checkboxes offer checked, unchecked and % checked; and every field type offers filled, empty, % filled, % empty and unique values.

The figure is worked out by the database over every row the view matches, not over the rows currently loaded — which is the point of having it, and the reason it doesn't climb as you scroll further down.

When the grid is grouped, each group carries its own totals in its header rather than in a row underneath, so they stay readable when the group is collapsed — which is where a group total earns its keep.

Lookups, rollups and formulas can't be totalled, and the cell tells you why rather than sitting blank: they hold no stored value, so there is nothing for the database to add up. A summary with no answer shows rather than 0, because 0 is a claim about your data.

A grid grouped by stage with the groups collapsed, so each stage is one row carrying its own count and totals — Discovery 16 records, $620,500, 45.94%. A footer under them totals the whole table: 78 filled, $3,727,000, 55.67% average.
Group totals sit in the group's own header, so they stay readable collapsed — which is when a total is most useful.

Show a field from a linked table

A view can borrow a column from a table it links to — Company → Region, Supplier → Lead time — without changing the schema. Open Columns, choose Add linked column, then click through the relationships and tap the field you want.

It behaves like any other column for width, freezing, reordering and CSV export, and it belongs to this view only — which is what lets any member add one to a personal view, where adding a Lookup field would be an admin decision for the whole table.

See Linked columns: showing a field from a related table for the full picture : what it can and can’t do, how it differs from a Lookup, and how to filter by the same route.

Filter and sort

Click Filter to add a condition: pick a field, choose a condition, and enter a value. Conditions match the field's type — text offers contains, starts with, and ends with; numbers get comparisons like ≥ and ≤; dates offer is before and is after; select fields show their options as clickable pills. Most types also offer is empty and is not empty.

Each active filter becomes a chip in the bar — click a chip to edit it, or its ✕ to remove it. With two or more filters, a toggle appears to switch between AND (all must match) and OR (any can match).

Click Sort to order by up to four levels — sort by Status, then by Due date within each status. Each level gets its own numbered chip, or just click a column header: once for ascending, again for descending, a third time to clear; Shift-click a header to add it as another level instead of replacing the sort. Arrows (numbered when sorting by more than one field) show on the sorted headers. Until you sort, records are listed most recently updated first.

Everything in this section is the same control on the calendar, timeline and map — one toolbar, one saved view. A filter you write here is already applied when you switch to the calendar, and one written there is applied when you come back. Sorting is the exception: it stays on the grid, because the other views impose their own order.

The view toolbar: Filter, Sort, Group, Summarise, Alert me, Columns, a search box for the table, Discussion, and Share.
The same toolbar sits above the grid, calendar, timeline and map — so a filter you learn once works on all of them.

Select rows and act in bulk

Tick the checkbox at the start of a row to select it, or the checkbox in the header row to select everything. A bar appears showing how many records are selected, with three actions: Delete moves them to the Trash after a confirmation (you can restore them from there), Export CSV downloads the checked rows as a spreadsheet-ready file named after the table, and ✕ Clear deselects.

Bulk delete only touches records you're allowed to delete — anything outside your permissions is quietly skipped.

The export writes exactly what you selected — including rows you haven't scrolled to, after Select all N matching. Linked records export as their names rather than internal ids, computed columns export their values, and the file has the same columns in the same order as the view you asked from.

Work with the Board

The Board groups records into columns using a single-select field you choose — one column per option, plus an Unassigned column for records with no value yet (or a value that no longer matches any option). Each column header shows a count.

Drag a card to another column and its select field is written to that column's value; dropping it on Unassigned clears the field. Cards are only draggable if you're allowed to edit that field — a card you can't drop anywhere is never offered as one you can drag. Click a card instead to peek at the full record.

If the table has no single-select field with options, the Board tab shows the grid instead.

The same Deals table as a board. A column per stage — Unassigned, Discovery, Qualified, Proposal — each headed with a count, holding cards that show the deal name, its company, amount, probability and expected close date.
Same records, dealt into columns by one Select field. Dragging a card between columns changes that field on the record.

Split the Board into swim lanes

Columns answer what stage is this in. Swim lanes answer whose is it — pick a second field (an owner, a priority, a client) from Swim lanes above the board and it splits into a row per value, with the columns still running across each one. Records with nothing in that field keep a lane of their own rather than being hidden, since "nobody has picked these up" is usually the row worth looking at.

  • Dragging a card sideways moves it along the columns, as before.
  • Dragging it down into another lane writes the lane's field instead.
  • A diagonal drag does both in one gesture. Only the fields that actually changed are written, so a move within a lane never re-stamps a value the record already had.

Lanes can use a select, a person or a linked-record field, and they're configured on the board itself — it's the only screen where you can see what a lane would do. Set it back to one lane to get a plain board again.

Browse the Gallery

The Gallery lays records out as cards: a large monogram tile, the record's name, and the fields the view is set to show. It's a comfortable way to scan a table visually. Click any card to peek at the record.

The same deals as cards in a gallery. Each card has a coloured header with the record's initial, then its name and the first few fields — company, stage, amount, probability and expected close — ending in a “+3 more” link.
You choose which fields a card shows. With no image field, the header uses the record's initial on the table's own colour.

Choose what a card shows

Board and Gallery cards draw the same field list the rest of the view uses: open Fields in the toolbar and tick what belongs on a card. Until you pick, a card shows the first few fields it has values for, and the panel says so.

  • Empty fields are skipped before the limit, not after, so a record whose first fields happen to be blank still fills its card from the ones that have values.
  • A card shows up to five fields and then says +N more. Ticking a sixth isn't ignored — it moves into that count, and it's on the record itself.
  • Linked columns work here too, so a booking's card can show the client's phone number without that column existing on Bookings.

The same list feeds calendar events, so choosing fields once shapes every surface that draws a record rather than a row.

Peek without leaving the view

Press Space on a selected cell to slide open the peek drawer — or click a board or gallery card. In the grid, clicking a row's number opens it too, as does the expand icon that appears on the name cell while it's selected. The drawer shows the record's fields and lets you edit them in place, plus Activity (a history of changes) and Graph (a map of linked records) tabs, and buttons to star or watch the record.

Clicking a linked record inside the drawer stacks a new sheet on top like paper — the one you came from stays full width underneath with a sliver showing, and clicking that sliver takes you back to it. A breadcrumb trail and a ← Back button do the same. Show full record jumps to the record's dedicatedpage, and Esc closes the drawer — with stacked panels it steps back one panel at a time.

Scrolling a long table

The grid keeps loading as you scroll — there's no page to turn. Rows are added, never swapped out, so your cell cursor, your selection and your place on the page all survive. A Load more link at the foot does the same thing if you'd rather click, and it still works with JavaScript off.

The record count at the foot is always the whole result set, and says how many of them are loaded so far.

Keyboard shortcuts

↑ ↓ ← → Move the cell cursor Grid view
Enter Edit the selected cell; while editing, save and move down Grid view
Tab / ShiftTab Move right / left; while editing, save and edit the neighboring cell Grid view
Space Peek at the selected record Grid view
Esc Cancel an edit, clear the cursor, or close the peek drawer Grid view
Delete / Backspace Clear the selected cell (name, relation, lookup, rollup, and read-only cells are excluded) Grid view
Ctrl/⌘C Copy the cell's value Grid view
Ctrl/⌘V Paste into the selected cell Grid view
Ctrl/⌘D Fill down — copy the value from the cell above Grid view
Page Up / Page Down Jump 15 rows up / down Grid view
Home / End Jump to the first / last column of the row Grid view
Any letter or number Start editing, replacing the current value Grid view
Enter Add the record and keep typing the next one Quick-add row
Esc Clear the box and step back out Quick-add row
Views

Linked columns: showing a field from a related table

Show a field that lives on a related table as a column of one view — Company → Region, Supplier → Lead time — without adding anything to the table's schema. The display half of filtering by a linked field: if you can narrow a view by a route, you can now see it too.

Add one

Open Columns in the view toolbar and choose Add linked column. A picker opens on the table you’re looking at: click a relationship to step across it, keep clicking to go further, and tap a field to finish. You can also pick the linked record’s own name rather than a field on it.

It’s the same picker, on the same routes, that the filter bar uses for Filter by a linked field — deliberately, because they answer two halves of one question. There’s no route syntax to learn and nothing to type.

The column appears immediately, headed with the route it came from (Company → Region). Rename it from the column’s own menu: a route reads long in a narrow heading, and once the column is on screen you usually just want it called Region.

It belongs to the view, not to the table

This is the whole point of the feature, and the thing to be clear about before you reach for it.

A Lookup field is a schema decision. Once it exists, it exists for everyone: in every view, in the REST API, in exports, in reports, and to formulas. That’s why creating one is an admin act.

A linked column is one view’s lens. Nothing is added to the table, no migration runs, and nobody else’s screen changes — so any member can add one to a personal view and answer their own question without asking for a schema change. On a shared view it’s a view edit like hiding or freezing a column, so it takes the same permission.

Reach for a Lookup when the route belongs to the table — when formulas should read it, the API should return it, or everyone needs it. Reach for a linked column when you need to see something while you work.

The route is followed each time you read the view. Nothing is written onto the booking, so nothing can drift out of date.

When the link reaches several records

Some routes land on one record — a deal's company. Others land on many: a customer's orders, a company's contacts, a deal's activities. A linked column never turns one row into several; a row is a record, and it stays one. Instead it asks what you want from the many, as soon as the picker notices the route fans out.

  • List them — the values, comma-separated, de-duplicated. Good when the names are the answer. Up to 25 show before the rest become a count.
  • Count — how many records the route reaches. Usually the right answer, which is why it's the default.
  • Sum, Average, Min, Max — offered when the field at the end is a number.

A column that counts or totals is a rollup, and behaves like one: right-aligned, showing 0 rather than a dash when nothing is linked, because 0 is the answer.

Only counting some of them

Under Only include where you can narrow which linked records are counted or totalled — “the orders that are posted”, “the deals that are Closed Won”. Add as many conditions as you need; all of them must match.

The field you test can live on the linked record itself, or one step further along. The picker lists both: Stage is a field on the order, Company → Tier travels from the order to its company and tests the tier there. That second kind is what lets the thing you're filtering on stay where it belongs — you don't have to copy a country, a type or a tier onto every child record just to make the filter possible.

So “the total value of this customer's orders, only the posted ones, and only where the contact is in the US” is one column, not a schema redesign.

Seeing the records behind a number

Click any rolled-up number in the grid — a linked column that counts or totals, or an ordinary Rollup field — and the records it was made from open in a list, each showing what it contributed. Click one to open it; Back returns to the list.

If the number only counts some records, you get exactly those, because it's the same working-out that produced the number rather than a fresh guess at it. The list is also current: a record that has changed since the page loaded shows as it is now.

What it can and can’t do

A linked column is a Lookup that nobody chose to keep, so most of the grid treats it as exactly that:

  • Resize, freeze, reorder, hide — all work normally.
  • CSV export includes it, under whatever you named it.
  • Public share links publish it, so a link can carry context from a table the reader never sees.
  • Permissions are enforced on the route, at every hop and at the far end — see below.

Three things it deliberately does not do, all for the same reason: the value isn’t stored anywhere, it’s worked out per row as the page loads.

  • You can’t sort by it, and it isn’t offered in the sort menu — there’s nothing in the database to order on.
  • You can’t total it in the summary row, for the same reason a Rollup or Formula can’t be totalled.
  • You can’t filter on it from the column menu. Use Filter by a linked field in the filter bar instead, which travels the same route and is fully supported; the column menu points you there.

If you find yourself needing to sort or total one, that’s the signal the route belongs to the table: add a Lookup or Rollup field and you get all three.

Permissions travel with the route

A linked column can’t become a way around a permission. When you add one, RowFold checks that you may travel every hop and read the field at the end; if you can’t, it says so rather than adding a column that would sit permanently blank.

The check is applied again when the view is read, per person — which matters, because a route saved on a shared view is travelled by everyone who opens it, not just whoever added it. A colleague who can’t see the far-end field sees an empty cell there, not somebody else’s data.

Limits, and what happens when things change

  • Eight per view. Each one is a real lookup for every row on screen, so this is a genuine cost ceiling rather than tidiness — and a grid needing twelve of them is really a report, which RowFold already has.
  • Up to five hops, the same depth limit lookups and rollups use.
  • Removing one takes it out of the column order too, so the freeze boundary stays where you put it.
  • If the relationship or the far-end field is deleted, the column stops resolving and can simply be removed — nothing else in the view is affected, because nothing depended on it.
Views

Calendar, Tree & Gantt

Three more ways to look at the records you already have: Calendar plots them on a month grid by date, Gantt stretches them into timeline bars between a start and end date, and Tree lays out the links between records as an expandable hierarchy. All three filter, search, share and hide fields exactly like the grid, and clicking any item opens its record.

Switch views and pick a table

When a table is active, the sidebar shows a row of view pills: Grid, Board, Gallery, Calendar, Gantt, Map. Click one to see the same table a different way.

Each view also has its own table picker in the header, grouped by workspace. In Calendar and Gantt, tables without a date field are grayed out and marked (no date) — those views need a date to place records in time. Tree accepts any table, since it works from links rather than dates.

Filter, search, and share these views

Calendar, Tree and Gantt carry the same toolbar the grid does, and it means the same thing on all of them.

  • Filter — narrows which records the view draws. A calendar with Status is Active on it plots only active records; a tree draws only the matching parents, children included.
  • Search — the same box as the grid's, scanning every field of every record rather than just what is on screen. It narrows whatever the filter already matched, and never clears it.
  • Fields — which fields this view carries. There are no columns to hide on a calendar, but the choice still decides what the peek drawer shows and what a public link publishes.
  • Share — publishes this view as a read-only web page, exactly as the grid does. The shared page renders as a table whatever shape the view uses here.

A filter lives in the URL, so a filtered calendar is a link you can send a colleague, and anyone who can read the table can filter it. If you can manage the view, Save to “…” appears beside it and makes what you are looking at the view's own filter; Reset throws the unsaved one away and keeps you on the same month or zoom level.

There is no sort control on these three. A calendar places records by date, a timeline by start date and a tree by hierarchy — the order is the view, so a sort would be a button that did nothing. Sorting lives on the grid.

Two kinds of condition the grid can run are not offered here, because these views read records rather than query them: a condition on a Lookup, Rollup, Formula or Auto-number field, and one that reaches through a link (Project → Region is East). They are not in the menu, and if a saved view already carries one the toolbar says “1 filter doesn’t apply here” and links you to the grid, where it does. Everything drawn is still narrowed by the conditions that can run — the view is never quietly showing you the wrong set.

Read the calendar

Calendar lays the month out Sunday through Saturday and places each record on the day from its date field. The line under the table name tells you which field the view is grouped by, along with how many events it found.

  • Each record appears as a colored pill; click it to open the record.
  • A day shows up to three pills. Busier days add a +N more note below them.
  • Every day with at least one event shows a count badge in the corner of its cell — the true total, even when only three pills fit.
  • Days outside the current month are shaded, today's cell is highlighted, and records with no value in the date field don't appear at all.
  • A pill carries the record's name and the fields the view is set to show — pick them under Fields in the toolbar. Anything the event's position already tells you is left off rather than repeated, so an event doesn't print the date it's sitting on or the lane it's in.
A month of deals on a calendar. The header says which date field it is plotted on and how many events are in view, with tabs for Month, Week, Day and Agenda. Each day cell holds coloured pills naming the deal and its company, and a busy day shows a “+1 more” link.
The header names the field being plotted. Days with more events than fit say so rather than silently dropping them.

Hours, lanes, and dragging events around

When the date field behind the calendar is set to include a time (a switch on the field, in Edit fields), Day and Week draw an hour grid and put each event where it actually falls, instead of stacking everything into an all-day strip.

  • Drag an event to move it to another time or day.
  • Drag its lower edge to change how long it runs — which writes to the view's end-date field.
  • Both snap to sensible increments, and an event dragged across midnight rolls its date properly.
  • Records with a date but no time stay in the all-day band at the top, so nothing is drawn twice.

Day view splits into lanes when the view has a lane field set — one column per person, room or machine. That's the rota read: who is on, and when.

Month and Agenda stay as they are on purpose. Thirty hour grids side by side is thirty columns of slivers, and an agenda is a list where a time is a label rather than a position.

Which clock the calendar runs on

Record dates are stored as plain wall-clock time, and the workspace time zone (Settings) says which wall that clock is on. A shift at 9:00 AM is 9:00 AM at the site, whoever is reading the rota — which is the behaviour you want almost always, and it is the default.

For the times that genuinely belong to the people in them rather than to a place — a call, a remote session, a cross-border booking — turn on Show in each viewer's time zone on the date field. Then 3:00 PM London shows as 10:00 AM to a colleague in New York, and dragging it works in their terms too.

Nothing changes for anyone who has never set a time zone on their own profile: they see the workspace's times exactly as stored.

Move between months

Use the and buttons in the page header to step to the previous or next month, and Today to jump back to the current one. The month and year you're looking at is shown on the right side of the calendar's header bar.

Set up a table for the Gantt

Gantt draws each record as a horizontal bar from a start date to an end date, and it picks those fields for you by name: a date field whose name contains a word like start, begin, from, kickoff, or open becomes the start, and a second one containing end, finish, due, complete, target, closed, or to becomes the end. If no name matches, it falls back to your first date field for the start and any other date field for the end — so any two date fields give you true spans, and clear names just decide which plays which role. The toolbar always tells you which fields it chose.

With only one date field there is nothing to infer the end from, so every bar ends three days after it starts and the toolbar says End inferred (+3 days). Add a second date field to draw real spans.

Read the Gantt timeline

Months run along the top ruler, and a vertical Today line marks the current date. Each row shows the record's name and its dates on the left; the bar sits on the timeline to the right. Scroll horizontally to move through time — the name column stays pinned.

Click a bar or a record name to open that record. Records with an empty start date are left off the chart, and a record whose end date falls before its start is drawn as a single day.

Explore links in Tree view

Tree shows the records in a table together with the records they're linked to. Every record with at least one link in the chosen direction becomes a root branch; click a branch row to collapse or expand it. Each child row names the record, the table it lives in, and a small pill with the label of the link that connects them.

Use the Forward → and ← Backward toggle to switch perspective: forward shows outbound links (records this table links to), backward shows inbound links (records that link to this table). The header counts the roots, links, and nodes currently in view, and clicking any record name opens it.

When a view looks empty

Each view tells you what it's missing and offers the fix:

  • Calendar on a table with no date field shows Add a date field, which takes you to the table's field editor.
  • Gantt in the same situation shows Edit fields — one date field gets you bars with inferred ends, a second gets you real spans.
  • Tree with no relationships suggests flipping to the other direction, or following add a link to connect records.

If you have no tables at all yet, all three views point you to Create a workspace instead. Calendar and Gantt also fall back to that message when you open them fresh and none of your tables has a date field yet.

Each of these asks the table for one specific thing. Knowing which is usually the whole answer to “why is my view empty?”.
Views

Map view & Address fields

Put your records on a real map. Give a table an Address field (with Google-powered autocomplete on every edit surface, public forms included), switch to the Map view, and each record becomes a pin placed where its address points — clustered when they crowd, one click from the record itself. The address does not have to live on the table being mapped: a booking can be pinned at the address of the property it booked.

Add an Address field

Open the table, go to its field editor (Edit fields), add a field, and pick the Address type. That's the whole setup. The field stores plain text and behaves like Text everywhere — filters, reports, exports — but every place you edit it offers real address suggestions as you type, so what gets saved is a clean, complete address rather than a guess.

Already keeping addresses in a plain Text field? No rework needed: open the field editor, and in that field's row switch its type to Address. Values are stored as text, so the change is lossless — existing addresses stay exactly as written, and autocomplete kicks in from the next edit.

Every way an address gets in

Once a table has an Address field, addresses arrive from anywhere:

  • Typing, anywhere you edit — the grid cell, the full record page, and the peek drawer all pop suggestions as you type; pick one and the complete address is filled in.
  • Public forms — Address fields on a shared form give visitors the same suggestions, so even data collected from strangers comes in clean.
  • Imports — when you import a spreadsheet, columns named things like Address, Street, or Location are detected and typed as Address automatically, and you can set any column to Address in the import's mapping step. Imported addresses are located on first map load.
  • The API — Address is a creatable field type in the developer API, and values write like any text field.
  • RowFold AI — ask "add an address field to Companies" and confirm the proposal; AI-designed tables can include Address fields from the start.

However an address arrives — picked from a suggestion, typed by hand, or imported — the map places it the same way.

Turn on the Map view

Open the table and click + View → Map in the view switcher. If the table has exactly one Address field the map configures itself; otherwise a card asks which field holds the address. Full street addresses, cities, and postcodes all work.

That question is never asked only once. Above the map, Pinned by names the field in use and opens the same picker, so a table with two address fields — billing and site, say — can be switched between them whenever you like.

Pin by an address on a linked table

Most records have no address of their own, and shouldn't. A booking is not at an address — the property it booked is; an order is delivered to its customer; a shift happens at its site. Stored properly the address lives once, on the table it belongs to.

So the address picker doesn't stop at this table. Every relationship is an entry you can open: click Property and you are looking at the property's fields, and picking Address there pins each booking where its property is. Keep going if you need to — Deal → Company → Address is a perfectly ordinary answer — and the map labels itself with the route it followed.

Nothing is added to your schema. There is no helper column to create and no field copied onto every booking; the address is read through the link when the map loads, so it is always whatever the property says it is today.

If the link reaches several records — a company and its contacts, each at a different office — you get a pin for each of them, all opening the same record. Repeated addresses collapse into one pin.

Read the map

Each record with an address becomes a pin; pins that crowd together collapse into a numbered cluster that spreads out as you zoom. Click a pin to open the record in the peek drawer — edit there and carry on.

A status pill above the map keeps count while addresses are being located, and tells you if any address couldn't be found. Records with an empty address simply don't appear.

Filters saved on the Map view narrow the pins exactly like they narrow the grid — a map of only your Active customers is one saved filter away.

Filter, search, and share the map

The Map carries the same toolbar as every other view: Filter, Search, Fields and Share. Filtering drops pins rather than hiding them — the map asks the server only for the records that match, so a map filtered to Status is Active geocodes and plots only those.

The filter lives in the URL, so a filtered map is a link you can send. Admins get Save to “…” to make it the view's own filter.

As on the calendar and the tree, a condition on a computed field or one that reaches through a link is a grid-only thing and is not offered here.

How locating works (and what it costs you: nothing twice)

Addresses are turned into coordinates on the server and cached permanently, so each unique address is looked up exactly once — ever. Big tables fill in progressively: the map locates a batch at a time and the status pill counts down until every pin is placed. An address Google can't make sense of is marked not found once and won't be retried until its text changes.

Views

Publishing a form

A form is a view of a table, like Grid or Calendar — except it writes records instead of reading them. Drag the questions you want onto a live preview, switch it on, and the link at <code>/f/…</code> takes submissions from anyone at all, with no account and nothing to install.

Add a Form view

Open the table and click + View → Form in the view switcher. RowFold mints the public link there and then and starts the form with every fillable field already on it, in the table's own order — the usual job is everything except a couple of internal fields, and a form with nothing on it renders as the closed page, which reads as broken.

It arrives switched off. Creating a view must never quietly open a public write endpoint on your data, so nothing is reachable until you tick Accepting submissions and save.

Design it in three panes

The designer is one screen with three columns. Fields on the left is everything the form could ask: click a chip to append it, or drag it to land exactly where you drop it. The form in the middle is the form itself — drag to reorder, click a row to configure it, press × to take it off. Settings on the right shows whichever field is selected, or the whole form's settings when none is.

Every row draws the real control the visitor gets — a date picker for a Date, a multi-select for a Multi-select, a dropzone for an Attachment — so there is no separate preview mode to keep in step with the thing itself. The title, the intro paragraph and the submit button's label are edited in place on the canvas.

Per question you can set the Question wording (blank uses the field's own name), Help text underneath it, and Required.

The form designer. On the left, the fields not yet on the form. In the middle, the form itself with its heading, intro and questions, each draggable. On the right, the settings: the form's name, the thank-you message, which answer names the record, and who is notified.
Left is what you can add, middle is what a visitor sees, right is what happens afterwards.

Ask only what's relevant

Any question can be conditional. Select it, set When to ask to Only when …, and list the answers that reveal it under …matching, comma-separated — Bug, Outage. Only Select, Multi-select and Yes/No questions can be the trigger, and only ones sitting above the field they control; drag a field above its source and the condition is dropped there and then rather than being discarded silently when you save.

The rule is enforced again on the server at submit. A question the conditions hid cannot block the submission, and an answer forced into it is thrown away — the browser's idea of which questions exist is never trusted.

What can't be asked publicly

Under the palette, a collapsed line tells you how many fields can never appear on the form; open it and each one is named with the reason why. Relation is out because a public picker would broadcast the linked table's record names to the internet; Lookup and Rollup are calculated from linked records; Auto number assigns itself on submit; People means nothing to someone outside the workspace. Everything else is fair game — text, long text, numbers, currency, percent, rating, progress, dates, yes/no, choices, email, URL, phone, address and file uploads.

Collect files

Put an Attachment field on the form and visitors get a dropzone: up to 10 files of 10 MB each, uploading as they are picked so a large file never stalls the submit button.

Files are parked until the submission actually happens, and the browser is handed nothing but opaque ids — the name, size and type that end up on the record are read back from RowFold's own rows at submit, so a borrowed or invented id resolves to nothing rather than to a stranger's file. Anything picked and then abandoned is deleted, bytes included, about six hours later.

Name the record, then go live

In Form settings, Record name comes from decides which answer titles the record in the grid — choose the one you would scan a queue by. After submitting is the confirmation the visitor reads. After submitting, go to replaces that card with a redirect to a page of your own, and must be a full http:// or https:// address.

The bar above the designer carries the rest: the live URL with Copy link and Open ↗, a live or closed chip, the submission count and the date of the last one, the Accepting submissions switch, and Save form. Saving publishes at once — the live link serves the new version on the next load.

Who hears about a submission

Three independent channels, because who gets told has three different answers in practice.

  • Notify — tick the workspace people who work this queue. They get a RowFold notification, and an email if their own notification settings say so, so one person's preferences govern everything rather than forms keeping private rules.
  • Also watch each new record — the same people join the new record's watch list, so they hear about replies and status changes too, not just the arrival. This is what turns a form into the front door of a queue.
  • Also email — one address outside RowFold, a shared support@ inbox or an on-call alias. It is independent of the people list, not a fallback for it.

Submissions ride the same write path as everything else, so Auto number fields stamp themselves and this table's Record created automations fire exactly as though the record had been typed in by hand.

Send the visitor a receipt

Under Reply to the sender, point Acknowledgement at an Email field that is actually on the form — RowFold will not acknowledge to an address the form never asked for. The mail goes out in your account's branding, subject We received your …, and echoes their own answers back so it doubles as their copy. What it says overrides the wording; leaving it blank reuses the on-screen confirmation, which is usually the right thing to say.

Views

The chat widget

A chat bubble for your own website where every conversation becomes a ticket in a table — the same thread your team answers from the record page. Anonymous conversations, the visitor's own credential, polling, rate limits and framing rules, a designer to configure it and a one-line snippet to paste on your site.

The third door into a table

A form takes a submission and stops. An email address takes a message and can carry on. The widget is the third way in and is deliberately the same shape as both: an unguessable token is the address, the table it files into is fixed when the view is created, and it starts switched off so minting one never silently opens an anonymous write endpoint on somebody's data.

What makes it different is that the conversation keeps going. One chat is one record, and that record's thread holds the chat, any email about it, and your team's internal notes together.

A messenger, not a live chat

This is the distinction the whole widget is built around. It is not a live-chat queue where someone sits waiting and an answer is expected in seconds. A visitor leaves a message, it becomes a record in your table, somebody works it, and the reply arrives — here if they are still around, by email if they are not. That is a perfectly good experience, but only if it is the one they were led to expect.

So the widget never pretends otherwise. There is no typing indicator and no presence dot, because either would claim someone is at the other end when nobody may be. Instead you get two honest signals:

  • An expected reply time, set in the Widget view and shown in the header before the visitor types a word — Typically replies in a few hours. Say it, then keep it.
  • Progress, so they can watch the ticket move instead of watching an empty box.

Try it before your customers do

The Widget view carries a live example beside the settings: the real chat window, rendered from the same markup and stylesheet your visitors get, with your branding already applied. Type into it and it plays the whole round trip — the message sent, the reply promise, the ticket moving through your published statuses, and the reply arriving after a visible gap.

It is driven by a scripted conversation, not the live endpoint, so designing a widget never files a real ticket into your table. Edits to the title, opening message, reply time and status labels appear in it as you type, before you save.

Answers from your own knowledge base

While someone types, the widget can offer answers drawn from a table of yours — so the commonest questions never become a ticket at all. The answer opens inside the chat; nothing links away from your site.

In the Widget view, open Answers. If you have no knowledge base yet, Create a knowledge base for me builds one — a table with an Answer, a Published tickbox, a Category and Keywords — and points the widget at it in one step. You can also nominate any table you already have, then choose which field holds the question, which holds the answer, and which field marks a row as published.

Because it is an ordinary table, everything else in RowFold applies: edit answers in the grid, import them from a spreadsheet, filter and sort them, and let automations keep them fresh.

What is public, and what is not

Nominating a table publishes part of it. The widget's snippet sits on your public website, so anything the widget can read can be read by anyone who opens the chat.

That is why publishing is opt-in per row rather than per table. You choose a field — usually a tickbox called Published — and the value that means published. Only rows matching it are ever offered, and only through the two fields you mapped: the question and the answer. Nothing else on the row travels, not the record's id, not your other columns, not how many rows the table has. A draft stays a draft, and a private table cannot be nominated at all.

Add a Widget view

Open the table and click + View → Chat widget. RowFold mints the token and maps the obvious fields — the visitor's email, their name, and the opening message — but only where the answer is unambiguous: one Email field on the table means one candidate, and several means it maps nothing and leaves the choice to you in the designer.

The view is created switched off. Its designer carries the snippet to paste on your site, what the visitor sees, which fields a conversation lands in, who gets told, and where the widget is allowed to run.

What happens when a visitor opens the chat

Your page loads a small launcher and an iframe pointing at /w/{token} on RowFold's own origin. Everything that touches data runs inside that iframe, same-origin with us, so the conversation's credential never enters your page's JavaScript, a hostile site hosting the widget cannot read it, and no cross-origin API surface has to exist at all.

The first message creates the ticket through the ordinary write path — Auto number stamps a reference, automations fire, a chat ticket is not a second-class ticket. The record is named after the question actually asked, trimmed at a word, because that is what an agent scans in the grid.

Where the chat came from

How do I cancel this? is unanswerable without knowing what this is. Every conversation carries the page the visitor was standing on and its title, shown at the top of the thread — and if they move around mid-chat, a moved to marker appears between the messages, so a wandering conversation reads as a trail rather than a mystery. Point Put the page in at a field and it becomes a column too, so you can filter and group the queue by where chats are coming from.

You can attach your own details as well. Call RowFoldChat.setContext({ plan: 'pro', orderId: 'A-1183' }) anywhere on your site and those values ride along with the conversation. Send what identifies the customer to you — not passwords, card details, or anything you would not put in an email about them, because everyone who can open the ticket can read them.

The query string is dropped unless you ask for it. Plenty of real URLs carry a session token, a sign-in link or a customer's email address after the ?, and copying that into a ticket table — and into the notification emails about it — is not a thing to do by accident. Turn it on when you need it, on the widget that needs it.

One honest limit. The chat window runs on RowFold's origin, so it cannot see the page around it; your site tells us, which means the address is reported by the page rather than proven. The one thing we can check is the site the browser loaded the chat from, and where that disagrees with the reported address the thread says so and stops offering it as a link.

How the conversation stays live

The widget polls rather than holding a socket open, and its cursor is a sequence number the database assigns rather than a timestamp. Two messages committed at the same moment can disagree with the clock, and a cursor that disagrees with commit order silently steps over a customer's message. A couple of seconds of latency is the price; not losing what somebody said is what it buys.

Show them where their ticket has got to

Every conversation shows Received the moment it lands — that one is automatic and needs no setup, because it is true the instant the record exists.

Beyond it, progress comes from the Select field your team already works in the grid. In the Widget view, pick that field and write what each option should say to a customer: In progress might read Working on it; Tier 2 might read Escalating to a specialist. Moving the card is then the same act as telling the customer — there is no second status to keep in step.

Publishing is per option, and blank means never shown. Leave Spam, Waiting on legal or Duplicate empty and a visitor sitting on one of those simply keeps seeing the last published state. An option you never label can never leak.

When a published status changes, the visitor sees it in the header and gets a line in the conversation saying so. It is the one "something happened" signal an async conversation has between messages — and unlike a typing indicator, it is true.

What a visitor is allowed to read

Every message carries an explicit visible to the visitor flag, set when it is written and never inferred from who wrote it. The distinction is the whole point: an agent emailing a supplier about the same ticket produces a message from your side, and filtering on who wrote it would hand that supplier correspondence to the anonymous stranger who opened the chat. Internal notes are excluded for the same reason — nobody set the flag on them.

The visitor sees you and them and never a staff name. They came to talk to a business rather than to Sarah in support, and the widget renders your side as your brand.

Leaving an address, and ending the chat

A visitor can leave an email address mid-conversation so a reply still reaches them after the tab is closed. It is strictly a delivery target: it never resumes a conversation, because type an address to pick up where you left off is an account-takeover primitive dressed as a convenience.

End conversation retires their credential immediately — the point of which is a shared machine — and can email them the transcript first. The transcript contains exactly the messages they could already read, and nothing else. The ticket and everything said on it stays with your team; the team's record of a conversation is not the visitor's to delete.

Answering from the record

There is nothing new to learn. A chat ticket opens in the same Conversation panel as an emailed one, and each message is labelled by how it travelled, so you are never told a chat reply went out as an email. A ticket with an open chat and an address gets both at once — you type once and reach the person wherever they actually are.

Views

Scheduler — the appointment book

The inside of what a booking page sells from the outside. A Scheduler view lays a table's appointments across the day with a column per staff member, so you can see who is free, drag an appointment to a new time or a different person, book the walk-in standing in front of you, and check people in as they arrive. It works on any table whose date field records a time of day; if the table already has a booking page, the scheduler reads that page's staff, service and client links and arrives configured.

Add one, and what it needs

Add a Scheduler from the + View menu beside the view tabs. It is offered on any table with a Date field that records a time of day — a scheduler places appointments on hours, so a date with no time gives it nothing to place them on.

Most tables are one switch away rather than genuinely unsuitable, because Include time is off by default. Where a table has exactly one date field, the menu offers Scheduler anyway and says what it will change: it turns the time on for that field first, then makes the view. Turning it on never rewrites a stored value — a date with no time keeps reading exactly as it did.

Where a table has several date fields it cannot guess which one starts an appointment, so it sends you to the field list instead of picking one.

It configures itself

A scheduler needs to know more than a calendar does: not just when, but who is delivering the appointment, what it is, and who it is for. It works those out for itself, in this order.

  1. What you chose. Anything set on the view wins.
  2. Your booking page. If the table already takes public bookings, that page has answered these exact questions — which link is the staff member, which is the client — so the scheduler inherits them rather than asking twice. Re-point the booking page and the scheduler follows; nothing is copied onto the view to go stale.
  3. An unambiguous single candidate. One link called Staff, one called Service, one Select called Status: taken. Two that could each be the staff member: neither, because guessing wrong books somebody with a haircut instead of a stylist.

Every role is optional. No status field means no status buttons; no staff link means no per-person columns and the day is shown instead, with a picker to fix it.

Six ways to look at it

Resource is the one most schedulers open on: one day, one column per staff member, room or chair — including people with nothing booked, because an empty column is the one you want to fill. Day is the same day in a single column. Week puts the seven days side by side. Month answers “how busy is this week” rather than “what time”, so it shows counts and the first few bookings; clicking a day opens it. Agenda is the next 30 days as a list, and the one that reads best on a phone.

Stays is for anything booked by the night rather than by the hour — a cottage, a room, a boat, a hire car. It is a chart with a row per unit and a column per day, and each booking is a bar across the days it occupies. A scheduler switches to it by itself when its dates carry no time of day and it knows when each booking ends.

The hour grid always shows a working day even when nothing is booked, and grows to fit anything outside it — an early appointment widens the window rather than being hidden off the top.

Running the day

  • Click any empty slot to book it. A dashed outline follows your pointer in 15-minute steps showing what you would be booking; the panel opens with the time and the person already filled in from the column you clicked.
  • Drag an appointment to move it. Dropping it in another person's column reassigns it in the same gesture, and it keeps its length rather than collapsing.
  • Drag its bottom edge to change how long it runs. This one only appears when the view has an end-date field to write to — a handle that did nothing would be worse than none.
  • Click an appointment for who, what, when, and the status buttons. Open record hands off to the usual record drawer for everything else.

Every change is written straight to the record, so automations, webhooks and the audit trail all fire exactly as they would from the grid.

How long is a booking? It is decided once

When you book something, the scheduler asks the service how long it takes and writes that onto the booking. From then on the booking is its own authority.

That is deliberate, and it is the difference between a schedule you can trust and one you cannot. If a 90-minute massage becomes a 120-minute massage next year, every massage you have ever booked would otherwise grow by half an hour — including the ones already delivered, already invoiced, and sitting in last quarter's reports. Instead: bookings made when it was 90 stay 90, and new ones take 120.

It has to be kept somewhere, so the view needs either an end date or a number of minutes on the booking itself. A duration that is looked up through the service does not count — that is the live value this is protecting you from. If there is nowhere to keep it, the scheduler says so above the grid and every booking is drawn the same default length until you pick a field.

Typing a number in the booking panel always wins; leaving it blank is what asks the service.

Moving and cancelling — and who gets told

Drag a booking to move it, drag its bottom edge to change how long it runs, or use Reschedule… in the panel to send it to another day without dragging. Moving keeps the length it was booked with.

Cancel booking sets your status field's own cancelled option — whatever you happen to call it — so the booking stays visible as a cancellation rather than vanishing. If the table has no such option the record goes to Trash, where you can get it back. Nothing here deletes anything permanently.

Both ask whether to tell the customer, and then say who was actually told. A booking taken through your public booking page carries the customer's address, so they get a proper email: the reschedule one shows the old time struck through above the new one, because “was that always when it was?” is the first thing anyone thinks. A booking somebody typed in by hand often has nobody to write to, and the scheduler says nobody to notify rather than implying an email went out.

Every change also runs your automations, so a rule watching the date field can add an SMS, a webhook or anything else on top.

Repeating bookings, and changing just one

A repeating booking is stored once, as a rule, and drawn for whatever period you are looking at — so “every Tuesday, forever” is literally true and costs nothing to keep. Generated bookings are drawn with a faint hatch because they are not records yet.

Move or cancel one and the scheduler asks how far the change should reach:

  • Just this one — the rule skips that date, and the one booking becomes a record of its own you can edit freely. This is how you handle “same as usual, but an hour later this week”.
  • This and all later ones — the old rule stops here and a new one starts, so everything before today is left exactly as it was. This is the one you want for “from now on we do Wednesdays”.
  • The whole repeat — changes every booking in the series, including ones already past.

You are only asked when it could matter. A one-off booking just moves.

Classes and anything shared

Twenty people at one yoga class is twenty bookings at the same time with the same instructor — which, on an ordinary appointment table, is nineteen double-bookings. It is not, and the scheduler needs to be told.

Give the view a capacity — a number saying how many the session takes — and it switches to counting seats instead. Bookings sharing a slot stop being flagged, and only genuine problems remain: a class with more people in it than it holds, and one instructor booked into two different things at once.

An over-full class is counted once, not once per person — it is one thing to go and solve.

Booked by the night

Cottages, rooms, boats and hire cars are booked in days, not hours. Give the view a start date and an end date that carry no time of day, plus something to draw a row per, and it becomes a Stays chart.

The end date is the day it becomes free again. A cottage booked the 1st to the 8th is available on the 8th, and the next guest's bar starts in that same column — so a changeover morning reads as one booking ending and another beginning, not as a clash. That is what every hotel system means by check-out, and reading it the other way would report most of a busy month as double-booked.

Drag the middle of a bar to move the whole booking keeping its length; drag either end to change just the arrival or just the departure. A genuinely overlapping pair stacks into two rows so neither is hidden, and both are outlined.

The side panel

Needs a decision is the queue worth checking first: appointments with nobody assigned, and two appointments booked on one person at the same time. Both are worked out from the data rather than from a status somebody has to remember to set, so the count is always real. Double-booked appointments are outlined on the grid too.

Below it, one list per role — staff, service, status — each with a live count for the period you are looking at. Click a row to narrow the view to it, or hover and click only to narrow to just that one. These are ordinary filters: they show up as chips on the toolbar, they ride the URL so a filtered scheduler is a link you can send, and an admin can save them onto the view.

The mini month marks days that have something on them. Hide the whole panel with the button at the left of the toolbar; that choice is remembered for you alone.

Colour and time zones

Colour appointments by staff, by service or by status from the toolbar. Colours come from each value's position in its own list, so the same person is the same colour on every screen and every day, and nothing needs configuring.

Times follow the same rules as the calendar. Appointments are shown in the workspace's zone by default, and a quiet line says so if yours differs. Where the date field is marked as converting, the hour gutter carries both clocks and a drag converts back on the way to storage.

Keyboard shortcuts

← / → Previous / next day, week or month Scheduler
T Jump to today Scheduler
R / D / W / M / A Resource, Day, Week, Month, Agenda Scheduler
N Book an appointment now Scheduler, with create access
/ Search this view Scheduler
? Show the shortcuts Scheduler
Esc Close whatever is open Scheduler
Records
Records

Comments, history & assigning people

Working on records together: the comment thread with @mentions, the per-record history of who changed what, watching, the People field for assigning teammates, and what a Contributor can and can't edit.

Comment on any record

Every row carries a speech-bubble at its right-hand end. It shows a number when the record has discussion, and turns accent-coloured when someone has @mentioned you there and you haven't read it yet — so you can see at a glance which rows are talking, and which are talking to you. Click it and the record opens straight on its Comments tab.

You can also open a record any other way — click the row, press Space, or open the full record page — and pick Comments. The box at the top takes a comment; Ctrl+Enter posts it. Type @ to mention a teammate — pick them from the list and they're notified in their bell, and by email too if their notification settings say so (Settings → Notifications, Mentions). The same thread appears in the peek drawer, on the full record page and in the table panel; it is one conversation wherever you open it.

Commenting automatically starts watching the record, so replies come back to you. Everyone in the workspace can comment — including read-only Viewers, whose seats are free: commenting is how a stakeholder weighs in without edit rights. You can delete your own comments; admins can delete anyone's. These threads are internal — on tables connected to email or the chat widget, the customer conversation is a separate thread and nothing here is ever shown to a customer.

A record's Comments tab in the peek drawer. Three comments about a compliance deal are interleaved with the record's own change history — “Probability: 12 → 80”, “Stage: Proposal → Negotiation”, and “created this record”.
Comments and changes share one timeline, so the discussion sits next to the edit it was about.

Ask a question about a whole table

Some questions aren't about one row — "where are all the US orders?", "should this table have a region field?". Those go in the table's own thread: press Discussion in the toolbar above the grid. It works exactly like a record comment, @mentions included, and the button shows how many messages the thread holds.

A table thread belongs to the table, not to the view you happen to be looking through — so everyone finds the same conversation whether they're on the grid, the board or the calendar, and a thread can never end up stranded on a personal view only its owner can see. Mentioning someone links them straight back to the table with the discussion open.

Read the record's history

The same Activity tab is the record's memory: who created it, every edit with the field name and the old → new values, moves to and from the Trash, posting and unposting, approvals — and the comments, woven in between. Linked records and people show by name, not by id, and edits made by an automation or through the API say so.

History respects field permissions: a field hidden from you stays hidden in history too.

Assign people with a People field

Add a People field (Fields → add a field → People) to put teammates on records — an assignee on tasks, an owner on deals. Its cells open a member picker; assigned people show as avatar chips, and being assigned notifies the person in their bell. Only actual members of the workspace can be assigned.

People fields group boards, filter (has a person, is empty), and appear in history and notifications by name.

One shared view, everyone’s own list

Filter a People field by @me and the view answers per person who opens it. One saved view called Assigned to me serves the whole team — there is no need for a view each, and somebody who joins next month gets theirs by existing.

Assigning somebody now starts them watching the record as well, so the next comment reaches them without anyone remembering to arrange it. And if the person you want isn't in the workspace yet, you can invite them from the mention or the People field itself — as a Viewer only, because an invitation sent mid-sentence shouldn't be able to hand out edit rights by accident.

Everything waiting on you

My Work gathers what is assigned to you, what you are watching, what is waiting on your approval and your watchpoints — across every workspace you belong to, not just the one you are in. It is the answer to “what do I owe anyone?” without opening eight tables to find out.

What a Contributor can edit

The Contributor role reads everything and creates records — and can edit and delete the records they created, nobody else's. It's the right role for someone logging their own work in a shared table without being able to reshape everyone else's rows. Field-level read-only and hidden overrides still apply to their own records; an Editor or Admin can edit anything their permissions allow.

Records

Generating documents

Turn a record into a branded PDF — an invoice, a quote, a work order, a certificate. You design a template once against a table, then any record in that table can be rendered from it: downloaded, saved onto the record as an attachment, or generated and emailed automatically by an automation.

A template is a stack of blocks

Templates are built from a handful of blocks, in the order you want them on the page:

  • Header — your logo and organisation name from account branding, with meta rows on the right (invoice number, dates).
  • Title and Text — free wording that can carry {{record.fieldKey}} tokens, plus {{record.name}}, {{workspace.name}} and {{today}}.
  • Field rows — a label and a value, straight off the record.
  • Line items — a table of the records that link to this one, with the columns and number formats you pick.
  • Totals — the money at the bottom, with one row emphasised.

A token you spell wrong renders as nothing rather than printing raw braces onto a customer's invoice.

Line items come from your relations

The line-items block walks the same link as subitems: a Relation field on the child table pointing back at this record. Point an invoice at its line items, or a job at its visits, and the rows appear in the order they were created.

Values print the way they read in the app — a Relation shows the customer's name rather than an id, and a Rollup shows its computed total — so a document never leaks the plumbing underneath.

Getting the document out

From a record you can download it, or save it onto the record in an attachment field, where it behaves exactly like a file someone dragged in.

An automation can do both without anyone pressing anything: add a Generate a document step, choose the template, and either save it to a field, email it to {{record.email}}, or both. That is the difference between "we can make invoices" and "invoices send themselves when the job is marked done".

What it looks like

The document wears your brand, not RowFold's — the logo, organisation name and accent colour come from account branding, and there is no RowFold marking anywhere on the page. Paper size is A4 or Letter per template.

The designer previews the real thing: it renders an actual PDF from a real record rather than an HTML impression of one, so what you approve is what your customer receives.

Records

Record history: attribution, batches and retention

What the per-record history records, why it names an automation rather than the person who configured it, how bulk operations are grouped, and how long any of it is kept.

Where history comes from

History is written centrally, at the single point every save already passes through. That is why the grid, the peek drawer, an import, an automation and the public API all produce it identically, with nothing wired up per surface — and why a new write path gets history for free.

It is the record-scoped sibling of the audit log rather than a replacement. The audit log is the workspace's forensic trail; this is the story of one row. See Comments, history & assigning people for reading the feed itself.

Attribution is honest

A change made by an automation is recorded as that automation — not as the person who configured the rule months ago. Attributing a rule's write to a human is the one way a history actively misleads: it says somebody was at their desk when nobody was.

The same applies to the AI, to imports, to public form submissions and to inbound email. Each says what it actually was.

What kind of thing wrote it

Alongside the displayed label, every entry stores the kind of actor — a person, an automation, the AI, an import, a system write. The label is prose ("Automation · Overdue chaser"); the kind is a fact you can filter and count on.

They are kept separate on purpose. Renaming an automation changes what future entries are labelled; it does not change what they were.

Batch references

A bulk operation stamps every row it touches with one batch reference. The four thousand rows a single import wrote are therefore one identifiable thing rather than four thousand unrelated edits, which is what makes it possible to see the shape of what happened rather than scrolling past its consequences.

Retention

History is kept for 24 months by default, changeable in Settings, or set to keep forever. A nightly pass enforces it, on the same schedule that already prunes automation runs and webhook deliveries.

It is a duration rather than a cap on rows deliberately: "the last 500 changes" cannot answer whether a value was different in March, which is the question people actually bring to a history.

History that was never captured cannot be recovered and there is no backfill, so the default errs long. Shortening it takes effect on the next nightly pass.

Working with data
Working with data

Records & the peek drawer

Every row in a table is a record, and there are two ways to open one: a quick peek drawer that slides in beside your view, and a full record page for editing and linking. This article covers reading, editing, linking, starring, and deleting records.

Open a record

In Board and Gallery views, click a card and a peek drawer slides in from the right — a fast, read-friendly summary that keeps your view underneath. In the grid, clicking a cell selects that cell instead, so peek another way: press Space with any cell of the row selected, click the expand arrow that appears on the selected row's name cell, or click a spot on the row outside the data cells, like the row number.

For the full page, click Show full record at the top of the drawer — that's where attachments, subitems, one-off links and generated documents live. To leave the drawer, click the dimmed background or the × button; Esc also closes it once you're on the first sheet. Anything you were part-way through typing is saved on the way out.

Read a record in the peek drawer

The drawer opens on its Fields tab: the record's name, its table, and every field value rendered exactly as the grid shows it — progress bars for percents, stars for ratings, chips for selects. Fields that are hidden from you by field permissions are left out entirely.

The drawer isn't just for reading. Click any value — or the record's name — and it becomes an editor right there: a date picker for dates, a Yes/No choice for Boolean fields, the option list for selects, and the link picker for relations. Each change saves the moment you leave the field, so there's no save button. Esc cancels the field you're editing without closing the drawer. Lookup, rollup and auto-number values stay read-only because they're computed, and attachments, subitems, one-off links and generated documents are handled on the full record page.

Below the fields, Records that use this lists up to a dozen records that link to this one, grouped the same way the full page groups them.

A record open in the peek drawer on the right, over a dimmed grid. The drawer shows tabs for Fields, Comments and Graph, the record's name as a heading, and its values: company, stage, amount, probability, expected close, owner.
The drawer opens over the view rather than navigating away, so the row you came from is still behind it.

Hop between linked records

Relation values in the drawer are clickable chips. Click one — or any card under Records that use this — and a new sheet lands on top of the current one like a sheet of paper, so you can wander through your data without losing your place. The sheet you came from stays full width underneath with a sliver of its edge showing down the left; click that sliver to go straight back to it.

A breadcrumb trail across the top shows the path you took. Click ← Back or press Esc to step back one sheet, or click any name in the trail to jump several at once. An edit you were part-way through on a sheet underneath is kept, not thrown away, and clicking the dimmed background closes the whole stack.

Check activity and the graph

The drawer's Activity tab shows a light history of the record: when it was created, when it was last updated, and links made to other records, each with a timestamp.

The Graph tab draws a small map — this record in the center, up to eight connected records around it. Click any of the surrounding nodes to peek that record.

Edit a record on its page

The full page's Fields card opens with the record's name — that's the table's first field, shown under its own label — then an input for every other field, matched to its type: date pickers for dates, a Yes/No choice for Boolean fields, dropdowns for selects. Nothing is written until you press Save changes; the grid, by contrast, saves each cell as you go.

Lookup and rollup fields show computed values you can't type into — they're derived from linked records. Hover the small lookup, rollup, or relation badge next to a field name for a plain-English reminder of what it does.

Link records together

A relation field shows its current links as chips. Press + Link a record+ Link another once there is one, or Change on a field that takes just one — and a picker opens that searches the whole related table rather than a slice of it: type to narrow, scroll for more, and the footer says how many matches you haven't seen. Remove a link with the × on its chip. If the record you want doesn't exist yet, type its name and choose Create “…” to make it and link it in one step. The same picker appears everywhere you link a record — the grid, this page, the new-record form, a subitem row and the peek drawer — and it honours the field's How many can be linked? setting: Several accumulates, Just one replaces. On this page the links are written when you press Save changes; in the grid and the drawer they save straight away.

The Records that use this panel shows every record that links to this one — through a relation field or a one-off link — grouped by table with counts; click any chip to open that record. For a connection that doesn't fit any relation field, use Add a one-off link: pick a Target record, give the link a Key and an optional Label, and press Add link. One-off links appear under Manual links, where the × button removes one.

A one-off link can't reuse a key that belongs to a relation field on this table — you'll get a message telling you to edit that field instead. This protects the link from being wiped the next time the record saves.

Star a record

In the peek drawer, click ☆ Star — it flips to ★ Starred and the record joins the ⭐ Starred section of the sidebar, where up to six starred items show (starred tables listed first). Click the button again to unstar.

Stars are personal and saved in your browser, so your starred list is yours alone — it won't appear for teammates, and it won't follow you to a different device or browser.

Delete records — they go to the Trash

In the grid, tick the checkboxes at the left edge of the rows you want gone. A bar appears showing how many are selected; click Delete and confirm. The records move to the Trash rather than being destroyed.

On the Trash page, Restore brings a record back with its relations intact, Delete forever removes it permanently, and Empty trash purges everything you're allowed to delete. The Auto-purge column counts down a 30-day recovery window for each item, turning red in the final week — restore anything you want to keep before its time runs out.

Keyboard shortcuts

Space Open the selected record in the peek drawer Grid view, with a cell selected
Esc Step back one peek card; closes the drawer from the last card Peek drawer
Enter Edit the selected cell inline Grid view
Working with data

Running support: tickets, threading & replies

Give a table an email address and it becomes a support queue whose records are tickets — each carrying one ordered conversation of what the customer said, what you said back, and internal notes they never see. Replies are written from inside the record, and the customer's answer threads onto the same ticket instead of opening a second one.

Where the conversation lives

Open a record and the Conversation panel sits below its fields. It appears only on tables that can actually receive one — an email-in address, an open chat, or a record that already has messages — so an ordinary table of products never grows a support interface it has no use for.

That last clause earns its keep: a mailbox can be deleted or a widget switched off, and the record of what was said to a customer must not vanish from the page along with it.

The header shows the ticket's reference when the table has an Auto number field — Ticket 1042, built from the field's own name and the record's number — and a count of messages, with internal notes counted separately.

A support conversation in order: the customer's first message, a reply sent to them, an internal note badged as not sent, and their answer. Below, a composer with tabs for Reply to customer and Internal note.
Notes sit in the same thread as replies, badged so nobody skim-reading mistakes an internal remark for something the customer was told.

Reply to the customer

The composer has two tabs. On Reply to customer, To is prefilled with the address the mailbox filed their message into, or failing that the first Email field on the record that holds a value. Type and press Send.

The message goes out in your account's branding with your organisation's name as the sender, and it is written into the thread whether or not delivery succeeded. A send that failed is badged Not delivered with the reason — a failed reply that left no trace would tell the next person the customer was never answered, and they would answer twice.

Internal notes

The Internal note tab writes into the same thread and is never emailed to anybody. The To row disappears, and the note is badged Internal note · not sent so that nobody skim-reading a long ticket mistakes an internal remark for something the customer was told.

A note is unsendable by construction rather than by convention: nothing in RowFold mails one, so don't send this is a property of the message rather than a rule every future feature has to remember.

How a reply finds its way home

Every message RowFold sends sets its reply address to t-{mailboxToken}+{recordId}@… — the table's own inbound address with the ticket's id sub-addressed onto it. That is the primary mechanism because it survives mail clients that strip threading headers, and plenty of them do.

When it is missing, RowFold falls back to the headers: In-Reply-To first, then the References chain read from the nearest ancestor outwards, matched against messages it has actually seen.

Matching on the subject line is deliberately not implemented. Re: Invoice from two different customers is the classic way support systems cross-contaminate threads, and a wrongly merged ticket shows one customer another's conversation.

The address is the primary mechanism rather than the threading headers, because plenty of mail clients strip those.

New ticket, or a reply to an old one?

A reply address naming a record in that mailbox's own table appends to it. One naming a record somewhere else is treated as unthreaded and starts a fresh ticket instead — a wrong thread is worse than a new one. Mail matching nothing at all becomes a new record exactly as it always did.

Either way the body is cleaned first: quoted chains, On … wrote: trails and signature blocks are stripped, so the thread holds what somebody actually said rather than the archaeology underneath it. Attachments arrive as real files on the message, stored exactly like an upload.

It updates while you read it

A reply arriving lands in an open thread without a refresh. First paint, your own send and a live arrival all go through one rendering path on purpose — a second path would be a second set of bugs, and the place they would show up is the place that matters most: an agent believing they replied when they hadn't.

People watching the record hear about replies too, which is why the form and widget settings offer to put the queue's owners on the watch list automatically.

Chat and email in one thread

Where a reply goes is decided per ticket, not per channel. A ticket opened in chat is answered in chat; one opened by email is answered by email; one that started in chat and left an address gets both, so an agent types once and reaches the person wherever they actually are.

The thread labels every message by how it travelled — Sent to customer for mail, a chat badge for a widget reply — because telling an agent their chat message went out as an email is the sort of small lie that costs trust.

Keyboard shortcuts

Ctrl/⌘Enter Send the reply, or save the internal note Conversation
Working with data

Importing data

The import wizard turns CSV files and Excel workbooks into connected tables — field types, cross-file relations, and rollups are detected for you, and you review everything before a single record is created.

Start an import

Open Import data in the left rail, or choose Import workspace from the New menu. The wizard walks you through four steps: add files, analyze, review the plan, import.

Nothing is created until the final step. Analysis only reads your data, so you can back out at any point without leaving anything behind.

Add your files

Drop files onto the upload area, or click browse to pick them. CSV files and Excel workbooks (.xlsx and .xls) both work, and you can add several files in one go.

  • Each CSV file becomes one table. Each sheet in an Excel workbook becomes its own table, so a whole workbook imports as a connected set.
  • The first row of each file or sheet is read as column headers. A file or sheet needs at least one data row under the header to be included.
  • Every sheet appears as a card showing its column and row counts — click to remove one before analyzing.

Choose where the data goes

The import lands in your account, adding its tables alongside the ones already there so the new data can relate to them. Your account has one home for its data — see Folders, not separate workspaces — so there is no step here that splits it in two.

If you opened the wizard from a workspace where you are an Admin, a Destination picker names that workspace explicitly and is selected for you. Editors and Viewers never see it, because adding tables changes the workspace's structure and that is reserved for Admins.

A workspace is created for you only if you do not have one yet — an account that was invited into somebody else's workspace and has none of its own. In that case the Workspace name field prefills from your first file's name, and you become that workspace's Admin when the import finishes.

Analyze the files

Click Analyze files and RowFold reads a sample of each sheet — up to the first 300 rows — to propose a plan. Every column gets a suggested field type (numbers, currency, percentages, dates, emails, URLs, phone numbers, checkboxes, select lists, and more), and select columns get their options collected from your actual values.

Relations are found by matching values across files: when most of a column's values match the row names in another sheet — say an Orders file whose Customer column is full of names from your Customers file — that column is proposed as a relation between the two tables. Detected relations also produce suggested rollups, such as a count of linked rows or a total of an amount column.

Let AI refine the plan

When an AI model is configured, it reviews the detected plan and refines it: cleaner table and field names, better type calls, an emoji for each table, and rollups where the data makes them meaningful. It also writes a one-line summary and a short list of suggestions — things it noticed and ideas for later — shown above the plan.

Without a model configured, the built-in detection still produces the full plan on its own. AI runs only during analysis; the import step itself never calls the model.

Review and adjust the plan

Each proposed table appears as a card you can edit before anything is created:

  • Rename the table or any field by typing directly into its name.
  • Pick which column names each row with the Row name selector.
  • Untick a column's checkbox to leave it out of the import — columns that look like noise, such as empty ones, come pre-unticked.
  • Change any column's type from its dropdown. A relation column shows the table it points to; switch it to Text if you would rather import the raw values.
  • Suggested rollups sit in the Σ Rollups strip — click on any you don't want. Turning a relation into text also removes rollups that depended on it.

Use Back to files to add or remove files, then analyze again.

Finish the import

The Import button shows the total number of rows in your files. Clicking it builds every table and field, adds the records, then links relation columns: each value is matched against the row names in the related table, and matches become real record links, so rollups calculate immediately.

The confirmation screen shows how many tables, records, and relation links were created — and, if any relation values had no match, how many were left blank. Click any table pill to jump straight to its records, or See the schema map to view the imported structure as a diagram.

Values are tidied on the way in: currency symbols, commas, and percent signs are stripped from numbers, yes/no becomes a checkbox value, and dates are normalized to a standard format.

Several files with the same columns become one table

Exports are often split up — one file per year, per region, per batch — with the same columns in each. Drop them all in together and RowFold treats them as what they are: more rows of the same thing.

Files whose column headers match exactly are combined into a single sheet before anything is analysed, so you get one table rather than one per file. The upload list says so — “3 files combined — identical columns, so they become one table” — and the row count is the total across all of them, so you can check it before going any further.

A file whose columns differ, even slightly, stays separate and becomes its own table. Matching is on the full set of headers, ignoring case and surrounding spaces.

If you genuinely want identically-shaped files kept apart, import them one at a time.

Import into a table you already have

Importing into an existing workspace doesn't have to mean new tables. When the destination already has tables, each sheet gets an Into: picker — create a new table, or add these rows to one that's already there.

Choose an existing table and two more things appear:

  • Column mapping. Every column gets a picker: fill an existing field, or add it as a new field on that table. Columns are matched up by name automatically, so you normally only fix the odd one.
  • Match on. The column that identifies a row already in the table — a SKU, an email, an order number. Rows whose value is already there are updated; the rest are added.

Leave Match on empty and every row is simply added — which is what you want for a log or a list of new records, and what you very much don't want when re-importing a corrected export.

The wizard spells out which of the two will happen before you commit, and the summary at the end reports how many records were updated as well as how many were added.

The match key is the whole difference between tidying a table up and doubling it.

What an update does and doesn't touch

Updating merges the incoming row into the record that's already there. Only columns with a value are written, so a blank cell never wipes what you already had — handy when your export only carries the fields that changed.

Columns you left as “+ New field” are added to the table as part of the import. Untick a column to leave it out entirely.

Relation, Lookup and Rollup fields can't be mapping targets. Lookups and rollups are calculated, and text dropped into a relation would sit there looking linked while pointing at nothing — so those fields aren't offered, and a column aimed at one is skipped rather than filled with something misleading.

Conversations
Conversations

The Inbox

One shared queue for every message your customers send you, whatever way they sent it. Email that arrives at a mailbox address, chats from the widget on your site, and form submissions all become tickets — and a ticket is an ordinary record, so everything you can already do with records still applies to it. The Inbox is the place you work them: see what is waiting, answer it, assign it, and move it along.

What lands here

A table appears in the Inbox as soon as anything has written to it — you do not switch the Inbox on. Set up any of the three intake routes and its conversations start arriving:

  • Email in — forward your support address at a RowFold mailbox and every email becomes a ticket, with replies threaded onto the original rather than piling up as new rows.
  • Chat widget — visitors write from your site and you answer here.
  • Public forms — each submission opens a conversation.

If several tables receive messages, chips above the list let you narrow to one.

A table joins the Inbox as soon as anything writes to it — there is no switch to turn on.

Reading the queue

Conversations are ordered by most recent activity. A warm line down the left and a bolder name mean the customer spoke last — nobody has answered yet. Use Needs reply to see only those.

An internal note deliberately does not clear that state: writing a note to your team is not the same as answering the customer, and the queue would be lying if it said otherwise. Notes are prefixed Note: in the preview so an internal remark is never mistaken for something the customer was told.

Where the queue promises a response time, each conversation also carries the clock: a countdown chip while there is time, Held while the clock waits on the customer, Late once a promise is missed. A Late filter appears beside Needs reply on exactly those queues. Response times explains how the promises work.

The Inbox in three panes. On the left a queue of support conversations with tabs for Mine, Unassigned, All and Late, each row showing its status and, where a promise has been missed, a Late chip. In the middle the selected conversation with the customer's message and the reply, badged “sent to customer”. On the right the ticket's own fields.
One queue for every way a customer can reach you, with the conversation and the record's fields beside it.

Answering

The middle pane is the same conversation and the same composer you get at the bottom of the record page. Reply to customer reaches them the way they reached you — email if the ticket came by email, the chat window if they are still there, and both if they left an address. Internal note is never sent anywhere.

Every message carries a badge saying what actually happened: Sent to customer, Delivered in chat, Internal note · not sent, or Not delivered with the reason. Press ⌘/Ctrl+Enter to send.

When a teammate has the same conversation open, the thread says so, and shows typing dots while they write, so two people stop answering one customer at once. This is for your side only; visitors never see who is viewing or typing.

Saved replies

Anything your team answers twice belongs in a saved reply. Press the Saved replies button, or type / in an empty composer, and pick one — it drops into the box so you can edit it before sending.

Bodies can carry the same tokens automations use, like {{record.name}} or {{workspace.name}}. They are filled in against the ticket you are answering, and you always see the finished text before it goes anywhere.

A reply can also move the ticket. Give a saved reply Also set status to and Also assign toWhoever sends it, a named teammate, or Clear the owner — and both happen when the reply is sent, not when it drops into the composer. Edit the text as much as you like first; the actions ride the send.

Assignment and status

Both are ordinary fields on the ticket, which is why they show up everywhere else too — in views, filters, reports and automations.

The Inbox uses a People field for the owner. It picks one named something like Assignee or Owner, or the only People field if there is just one. If the table has none, Admins get a one-click Add an Assignee field button — the Inbox never adds a column to your table on its own.

For status it uses the Select field the chat widget or the mailbox nominates, or one named Status. Changing it here is an ordinary edit: it is audited, it can trigger automations, and if the widget publishes that option to visitors, the customer sees the ticket move.

Staying current

The queue and the open conversation both update on their own. A live connection makes that near-instant, and a slower poll runs regardless of whether that connection is healthy — because the failure worth designing against is an agent reading a ticket, believing they have seen everything, while the customer's reply sits unrendered.

Updates pause while the tab is in the background and catch up the moment you return.

Keyboard shortcuts

/ Open saved replies Empty composer
⌘/CtrlEnter Send the reply or save the note Composer
Conversations

Response times

A promise on a queue: how fast a new ticket gets its first reply, and how fast it gets resolved. Set one or both targets and every conversation in the Inbox carries the clock — a countdown while there is time, Held while the clock waits on the customer, Late once a promise is missed. This is not a report you check later; it is the queue telling you what to pick up next.

Two promises

A policy makes up to two promises: a first reply within so many minutes or hours, and a resolution within so many. Either can be left untracked: a desk may care about resolution and not first touch — and an untracked target draws no badge rather than a green one.

One policy per queue, on the table itself rather than a view. A view is a lens, and two people looking through different lenses must not be owed different answers.

Held time is added back on, and a held ticket cannot go Late — the desk is legitimately waiting on somebody else.

When the clock starts, and what counts as an answer

The clock starts when the first message arrives. The first reply is the first message the customer could actually read — an internal note is not an answer, the same rule the queue's Needs reply state follows.

Deadlines are stamped when the clock starts and never re-derived. Tightening a policy from eight hours to four applies to new tickets; it does not retroactively make last month's tickets late, and last quarter's numbers stay what they were.

Pausing, and stopping

Pick which of the status field's own option values pause the clock and which end it. Pausing values are things like Waiting on customer or Snoozed; ending ones are Solved or Closed. Both are matched from the field's own options, never a hard-coded list. A paused ticket shows Held and cannot go Late: the desk is legitimately waiting on somebody else. Time spent paused is added back to the deadline when the clock resumes, and the original promise stays on record.

The response-times page for a support queue. A summary states that new tickets get a two-hour first reply and an eight-hour resolve deadline counted during business hours, that the clock pauses on “waiting on customer” and stops on solved or closed, and that deadlines already promised keep theirs. Below, the two targets in minutes and the status mapping.
The summary at the top is written from your actual settings, so what the page promises and what it does cannot drift apart.

Business hours

Each policy chooses whether its targets count around the clock or during business hours only. The weekly pattern and closed days live at Settings → Business hours; a closed day (a bank holiday, a shutdown week) is skipped entirely.

A workspace that has stated no hours counts around the clock. That is deliberate: "4 hours" must not quietly mean "4 working hours" until you have said what working means.

Late, and who hears about it

Miss a promise and the conversation's chip turns Late, and a Late filter appears beside Needs reply, on exactly the queues that promise a response time and nowhere else. You can also name people to notify on a breach; they are told once per missed promise, not hourly, because an alert that repeats for a fortnight teaches people to ignore the one that matters. Naming nobody is fine: the badge is the whole notification, and that is a legitimate way to run a small desk.

Conversations

Who picks it up

New tickets stop waiting for a volunteer. Name the people who take new work and the queue assigns each unclaimed ticket as it arrives — the customer's usual person where one can be established, otherwise whoever has the fewest recent tickets. It writes the same owner field the Inbox reads, so Mine, notifications and the audit trail all just work.

Preference first, then load

Two rules, in order. If the same customer has written before and their previous ticket's owner is on the roster, they get their usual person. That person is recognised by the address the message came from, so it works even when the ticket table has no customer relation at all. Otherwise the ticket goes to whoever has had the least work lately, measured over a window you choose, with ties broken stably rather than randomly.

Assignment here is an offer of convenience, not an argument — it never overwrites a choice anybody made.

Only unclaimed tickets

Routing fires when a ticket arrives with nobody in the owner field, and never again. It will not overwrite a person's assignment, an import's, or its own earlier choice. Assignment here is an offer of convenience, not an argument. Reassigning stays a human act: the Inbox, the record, or a saved reply with Also assign to.

People removed from the workspace drop out of the roster on their own; nobody has to remember to edit it.

The routing page for a support queue, stating in a summary that a new ticket goes to whichever rostered person is least busy over the last fourteen days, and that a customer who has been in touch before goes back to whoever helped them last.
Name the people who take new work; everything else is the two rules above, in that order.
Conversations

How did we do

One question, one click. When a ticket reaches a finishing status, the person who wrote in is emailed a rating request under your own brand. They click a score, land on a page that says thank you, and the answer files itself against the queue. No login, no form, no second question.

When it asks

You choose which of the status field's own values count as finished (Solved, Closed, Shipped) and how long to wait after a ticket gets there. The wait matters: a ticket is often marked solved a beat before the customer agrees it is, and asking in that gap invites a rating of the wrong moment. The ask goes out by email, worded with your question, under your logo and colours. This is your workspace asking its own customer, exactly like a booking confirmation.

The pause matters: a ticket is often marked solved a beat before the customer agrees it is, and asking in that gap rates the wrong moment.

Asked once, and not hounded

One ask per ticket, ever. A ticket reopened and re-solved does not ask again; the customer already answered, or already declined to. There is also a per-customer cooldown, so somebody who closes four tickets in a week is asked about one of them, not all four. A ticket with no email address is simply never asked — staff-entered tickets are ordinary tickets, not a problem.

Where the answers go

Scores are 1 to 5, with an optional comment. They gather on the queue's How did we do page, kept on their own ledger rather than as columns on the ticket: a rating is the customer's word, and a cell a person can type into is a cell a person can type into.

The satisfaction page for a support queue. Its summary says that when a ticket reaches solved or closed the person who wrote in is emailed a one-click rating an hour later, and reports the running result — two asked, one answered, averaging 5.0 out of 5.
The page keeps the running score, so the ratings live beside the setting that produced them rather than as a column somebody could type into.
Conversations

The help centre

Publish a table of articles as a public, brandable, searchable site at /kb/your-name. It reads the same knowledge the chat widget answers from (one body column, one published gate), so an article is published to both or to neither, and your help site can never disagree with your help bot.

From table to site

Point the help centre at the columns that matter: which field is the article body, which column says an article is published, and — optionally — which groups articles into categories. The record's name is the article's title. Pick a slug and the site answers at /kb/that-slug, wearing the logo and colours from Settings → Branding.

Readers get a search box above the index, running the same matcher the chat widget answers with — same stemming, same scoring — so the two doors rank the same article the same way. It needs at least six characters: type fewer and the page says so and shows you everything, rather than handing back a result set that quietly matched almost every article.

Setup is honest about the difference between "published" and "publishes something": a centre that is switched on but cannot read a body column says so on its own settings page, rather than serving an empty site.

A published help centre: the workspace's name and a one-line description, a search box, and articles grouped under Billing, Troubleshooting, Getting started, Cloud dashboard and Hardware, each showing its title and the start of its text.
This is the public site, wearing your branding. The categories are just a column on the articles table.

One knowledge base, two doors

The chat widget already answers visitors from a table of articles behind a published gate. The help centre is a second door onto the same rows — browsable and searchable instead of conversational. Publish an article by setting its gate column; unpublish it the same way, and it leaves both doors at once.

One gate column controls both doors, so publishing and unpublishing happen once rather than twice.

What public means

The site needs no login and the slug is guessable on purpose — it is an address, not a secret. The gate column is the whole control over what appears, so treat it the way you treat a share link's column list. Search engines are allowed in only if you say so.

Intelligence
Intelligence

Ask RowFold & AI tools

Ask plain-English questions and get cited, verified answers - and go further: Ask can build. It proposes saved views, tables and fields (including auto-computed Lookup and Rollup fields), batches of related records, dashboards, automation drafts, and a scheduled digest. Every proposal appears on a card showing exactly what will be created, and nothing exists until you confirm it.

Ask a question about your data

Open Ask RowFold from the left rail — or press Ctrl/⌘ + / anywhere — type a question in plain words, and press Ask. The assistant investigates with read-only tools and narrates as it goes: small chips like Querying Deals or Crunching numbers show each step while the answer streams in.

Within a conversation it remembers what it already looked up, so follow-ups like “and which of those is biggest?” come back instantly instead of re-querying. It also knows your fields’ real option values and ranges, sample records, and saved views — so “who’s in the Overdue view?” resolves to exactly that view’s filters.

An empty chat suggests questions written from your own schema — real table and field names, not generic examples — so the first thing you see is something worth asking. You can also just type a question into Ctrl/⌘ + K: once it reads like a question rather than a record search, the palette hands it to Ask for you.

Read the answer, and check its working

Every record an answer mentions is a link — click one to peek at it without leaving the chat. Underneath, the citation chips list the records the answer drew on; if there are more than six, the overflow is stated rather than quietly dropped.

The chips above the answer are its working. Each names a step the assistant took — Crunching numbers in Visits, Opening a record — and clicking one shows the query that ran and the data it returned.

The footer says whether the answer's figures survived being re-computed against your live data: ✓ N figures verified, ⚠ N figures unconfirmed, or no figures to check when the answer made no numeric claims. Click the badge to read the full receipt — each claim, the exact query replayed, and the live result it came back with. It opens inside the conversation, so nothing is lost.

When an answer rests on a breakdown, a small chart is drawn under it from a fresh re-run of that aggregate — so the picture cannot drift from the data. You can Copy any answer, or Share the conversation: the link opens the same transcript for a colleague, under their own permissions.

It runs a real query rather than reading a sample — and when a condition could not be applied, the answer says so instead of quietly dropping it.

Keep typing — the chat keeps up

You never have to wait for an answer to finish. Press Enter while one is streaming and your message is queued to send next; press Ctrl/⌘ + Enter to interrupt and steer — the assistant keeps what it had said and takes your correction on board. The send button doubles as a stop button while streaming, and if you scroll up to reread, the view stays put with a Jump to latest pill instead of pulling you back down.

Create things by asking

Describe what you want built and Ask proposes it on a card — nothing is created until you press the card’s button.

  • Tables & fields — “set up order intake with line items and inventory that tracks itself” designs connected tables, including subitem hierarchies and auto-computed Lookup and Rollup fields, so totals maintain themselves. (Admins only; Build with AI in the New menu starts this conversation.)
  • Records — “add a company with two deals and a contact” creates related records together, links included; batches go up to 40 at a time.
  • Saved views — “save deals over $200k as a view” turns the query it just ran into a view on the table.
  • Saved reports — “revenue by month as a report” becomes a shareable report page with a live chart and CSV export; answers that crunched numbers also grow a 💾 Save as report button.
  • Dashboards — “make me a pipeline health dashboard” designs a board of live tiles from your description.
  • Automations — “when a dispatch is created, reduce that product’s stock” drafts the rule; it arrives switched off for you to review and enable in the editor.
  • A digest — “send me a weekly digest” puts a short AI summary of what changed on your Home page on schedule.

When something genuinely needs your call — an option that doesn’t exist yet, a theme, how tables should relate — Ask asks a quick question first instead of guessing.

Confirm, and the flow continues

Each card shows exactly what will be created. Not now dismisses it — nothing is lost; ask again any time. Confirming applies it through the same permission checks and audit trail as doing it by hand: schema, views, and automations need workspace Admin; record batches need the same per-table create permission you’d need in the grid.

Multi-step work drives itself: confirm the schema card and the records proposal follows automatically; confirm one batch and the next appears — no “go ahead” messages needed. Your confirmation buttons are the steering wheel.

Keyboard shortcuts

Ctrl/⌘K Open or close the search palette Anywhere
Ctrl/⌘/ Open the ask panel Anywhere
Enter Ask the question you typed Ask panel
↑ / ↓ Move through results Search palette
Enter Open the highlighted result Search palette
Esc Close the palette, ask panel, or Build with AI dialog Anywhere
Ctrl/⌘Enter Submit your description for a schema design Build with AI dialog
Intelligence

How RowFold checks its own numbers

Every figure an AI answer states is re-computed against your live data before you read it, and you can open the result to see exactly which query was replayed and what came back. This explains what that check does, how to read the badge, and — just as importantly — what it does not promise.

Why an answer needs a receipt

A language model can write a confident sentence containing a wrong number, and nothing about the sentence looks different when it does. That is the single reason not to trust AI with an operational question — so RowFold does not ask you to.

Instead of promising the model is right, RowFold checks it. After the answer is written, every figure in it is re-computed against your live tables and compared to what was claimed. You see the outcome on the answer, and you can open the whole working.

What actually happens

While answering, the assistant reads your data with read-only tools — querying a table, aggregating a column, opening a record. When it states a figure that came straight from one of those calls, it also records which call produced it.

The moment the answer is finished, RowFold replays each of those calls against your database as it stands right then, and checks whether the claimed figure is in the fresh result (allowing 0.5% for display rounding). Up to five figures are checked per answer. The replay is a read — it changes nothing, costs no AI usage, and the model has no part in it.

Reading the badge

The footer of every AI answer says which of three things happened:

  • ✓ N figures verified — every checked figure came back from your live data.
  • ⚠ N figures unconfirmed — at least one did not. The answer is still shown, because the reasoning may be sound and only one number stale, but treat those figures as unchecked and open the panel to see which.
  • no figures to check — the answer made no numeric claims. This is deliberately different from staying silent: nothing failed, there was simply nothing to re-run.

Open it and read the working

Click the badge and the receipt opens inside the conversation — your chat stays exactly where it is. For each figure it shows the claim, the tool that was re-run, the exact input it was re-run with, and the real result that came back, verbatim.

The step chips above the answer work the same way. Each one names something the assistant did while investigating; click it to see the query it ran and the data it got. Nothing there is written by the model — it is the record of what was executed.

Charts are checked too

When an answer rests on a breakdown — visits by reason, revenue by month — a small chart appears under it. The assistant does not supply the bars; it names the aggregate, and RowFold re-runs that aggregate and draws whatever comes back. A chart therefore cannot disagree with your data even if the prose above it does.

What verification does not promise

It is a check on arithmetic against live data, not a judgement about meaning. Specifically:

  • Figures the assistant worked out itself — a percentage, a difference between two totals, a growth rate — are not re-run, because there is no single query behind them.
  • A verified figure is the right answer to the query that was run. If the question was understood differently than you meant it, the number can be correct and beside the point — which is why the answer cites its records and shows its queries.
  • Prose is not verified. Only figures are.
  • Verification is recorded for the answer you are looking at. Re-opening a past conversation from History shows the answer without a badge, rather than implying a check that isn't on file.
Intelligence

Reports & charts

Reports turn your tables into saved, shareable answers: tabular summaries, KPI cards, and bar or line charts that pull fields, follow relations, roll up related records, and compute formulas — with grouping, filtering, and CSV export.

Start smart: reports arrive pre-built

A new report is never an empty shell. RowFold reads the base table and seeds a sensible starting shape: a Select field becomes the grouping axis (or a Date field, bucketed by month), the first money or number field becomes a real sum aggregation so the KPI cards and totals row light up immediately, and the visualization is picked to match — a bar chart for grouped shapes, KPI cards when it's all numbers.

Switching the base table re-seeds fresh defaults for the new table instead of wiping you back to nothing. From there, sculpt: every column, filter, grouping, and sort is yours to change.

Aggregate the table's own rows

Aggregation columns can now point at this table as well as related ones. Pick This table as the source to add “sum of Amount”, “average Deal size”, or a plain record count over the report's own (filtered) rows — that's what powers KPI totals like Total revenue without needing a second table. Cross-table rollups (“count of Deals via company”) work exactly as before, and both kinds respect grouping: each group row shows its own slice.

Create a report

Open Reports in the rail and click + New report. RowFold builds a starter report from your workspace's most-connected table — a category column and a numeric column when the table has them, plus up to three counts of related records — and drops you straight into the editor. If the workspace has no tables yet, you're sent to create one first.

Each saved report appears as a card on the Reports page, which also shows a quick workspace overview: table, record, relation, and teammate counts. Clicking a card opens the read-only view; the Edit button there takes you back to the editor.

Pick a visualization

The tabs at the top of the editor switch how the report renders: Table, KPI, or Bar.

  • Table lists every row, with a Total line for aggregation and formula columns.
  • KPI shows one big number per aggregation or formula column — its total across all rows (an average column shows the average). It needs at least one of those column kinds.
  • Bar charts every numeric column as a series, with a Bar/Line toggle. It needs at least one numeric column.

Click Save to keep changes to the name, emoji, base table, visualization, grouping, and sort. The Live preview panel shows the report against your real data as you build it.

A report page headed “Deals report, 6 rows, from Deals”, with buttons to export CSV or PDF. Below, a bar chart of total amount by stage, with chips above it to toggle each plotted series and a Bar/Line switch.
Each chip is a column the report computed. The chart plots whichever ones are lit, which is why they need comparable scales.

Add columns

A report is a list of columns. Pick a kind, give it a Label, fill in that kind's controls, and click + Add column.

  • Field — a value straight from a column on the base table, or the record's name.
  • Lookup — follow a Relation field on the base table and pull a value (or the record name) from the linked record.
  • Aggregation — roll up records from another table that link back to this one: count, sum, avg, min, or max. count ignores the value field; the other four need a numeric field to aggregate.
  • Formula — arithmetic over other columns, referenced by label, e.g. [Pipeline $] / [Deals]. Operators: + - * / ( ).

Remove a column with the × button — any filters, grouping, or sort that used it are cleaned up automatically. The Base table picker sets which table the report reads from; changing it clears all columns and filters, so choose it first.

Group and sort

Group by collapses rows that share a value in one column into a single line per value. Numeric columns re-aggregate within each group (sums, or the aggregation's own operation for avg/min/max columns); text columns show the shared value, or a count like 3 values when members differ. The first column shows how many records each group contains, and formula columns don't appear in the Group by picker.

When the grouped column holds dates, pick a period — By day, By week, By month, By quarter, or By year — to see totals over time, such as revenue by month. Exact value groups by the precise date instead. Bucketed groups come out in chronological order unless you set an explicit sort.

Sort orders rows by any column, ascending or descending — numerically when both values are numbers, alphabetically otherwise.

Cross-tab: group down the side and along the top

Set a second group column and a report becomes a cross-tab: the first grouping runs down the side, the second along the top, and one measure fills the grid — revenue by region by quarter, in a single table. Choose the measure under Matrix measure; it is deliberately one number, because a cell holding six columns is a spreadsheet rather than a cross-tab.

An empty cell reads , never 0: nothing landing there is a different fact from a measured zero, and the CSV exports it empty for the same reason. Row totals, column totals and the corner are all computed over the records themselves rather than by adding up the cells, so an average column doesn't turn into an average of averages.

Filter rows

Click + Filter (available once the report has at least one column) to add a rule: a column, an operator, and a value. Click Save filters to apply. Operators cover equality (=, ), text (contains), numeric comparisons (>, <, , ), and blank checks (is empty, is not empty — these need no value, so the value box greys out).

For date columns, in last … days and in next … days take a number of days and match a rolling window that includes today.

With more than one filter, a Match selector appears: all keeps rows that pass every rule; any keeps rows that pass at least one.

Filters run in the database wherever they can, so a filtered report reads the whole table rather than a slice of it. A filter that reaches through a lookup, a rollup or a formula can't be run there — those values are computed while the report is being built, so they don't exist yet — and a report using one falls back to the first 20,000 records and says so at the top. If you hit that, filtering on a stored field instead removes the limit.

Filter the groups, not just the rows

An ordinary filter narrows the records — “amount is over 10,000” keeps the big deals. A group filter narrows the groups: “only the regions that billed over 10,000”, which is a different question and was previously unaskable.

It uses the same builder and the same operators, because a grouped row is still a row — its values are the aggregates in each column. Groups are dropped before anything else is built from them, so the totals at the foot always add up to the rows above, and a column that empties disappears from a cross-tab rather than lingering with a total nothing accounts for.

Report on a period, and compare it

Pick the field that decides whether a record falls in the period — an order has an ordered date, a shipped date and a paid date, and each gives a different answer, so RowFold asks rather than guessing. Then pick the window: This month, Last month, This quarter, This year, Last 7/30/90 days, Last 12 months, or All time — eight windows and the default.

Then answer “compared to what”. Previous period steps back by the window's own kind — this February against January entire, not against 28 days straddling two months — and Same period last year is the one a seasonal business usually wants, since December against November says little about a toy shop. Each KPI and each group then carries its change.

Growth from nothing says up from nothing rather than inventing a percentage, and a group that wasn't there last time reads new. The arrow shows direction only — a report has no way of knowing whether the column is revenue or refunds. Periods are resolved on the workspace's timezone, so two people in different countries see the same set of records, and the window is half-open, so two adjacent quarters never double-count the day between them.

Which one you pick changes what “compared to” means — and both leave the day a period ends on to the next period.

Chart multiple series

In the Bar visualization, every numeric column becomes a series with its own chip above the chart. Only the first series starts on; click chips to toggle others, and at least one always stays on. Each series keeps a fixed color, so turning one off never recolors the rest — the chips double as the legend.

Hover, tap, or keyboard-focus a point to read every visible series at that position in one tooltip. All series share a single axis, so pick series with comparable scales. Switch between Bar and Line with the toggle above the chart.

Click a mark to see the records behind it

Bars and points are a way into the data, not just a picture of it.

  • Where one record sits behind a mark, clicking it opens that record in the peek drawer.
  • Where a group sits behind it, clicking opens the list of that group's records on the same drawer stack — so clicking a row pushes the record on top, and ← Back returns you to the list rather than dead-ending on the first thing you opened.

The list is paged from the server and its header counts the whole group, not the page you can see. The group is worked out by re-running the same grouping the chart used, so it is exact, and it is current: a bucket that has emptied since the chart was drawn comes back empty and says so, rather than showing you a stale list.

Share and export

Every member of the workspace can open a report. Cards on the Reports page link to the read-only view — the same numbers and chart without the editing controls — so it's the page to send teammates. Reports honor field permissions per viewer: a field hidden from someone stays blank in their copy, even when reached through a lookup, and hidden numbers can't leak through sum/avg/min/max (counts still work).

Export CSV on the read-only view downloads the current result as a spreadsheet-ready file. Grouped reports export the group label with its record count, and values with commas or quotes are escaped so columns line up in Excel.

Have it emailed to you on a schedule

Press Subscribe on a report and it arrives in your inbox every day, every week on a weekday you choose, or monthly on the 1st — as a PDF or a CSV, at an hour you pick in your own timezone.

A subscription is yours, not the report's: subscribing does not sign your colleagues up, and each person's copy is computed with their own permissions, so a report emailed to you can never contain a column you would not be shown on screen. Pause it with the toggle; delete it to stop entirely. If the report is deleted, or you lose access to it, the subscription simply stops sending.

Publish it to a link

Publish gives a report a public web address at an unguessable token, for a client, an accountant or a board member who has no RowFold login. You can set an expiry date and choose whether the page offers a CSV download. It starts switched off — you turn it on when you're ready.

The columns are frozen at the moment you publish, and that is the whole security model. Add a column later and it is not merely hidden from the public page: its data is never computed for a public request at all. The same goes for a grouping or sort column that wasn't published, or its values would reappear as row headings. Re-publish when you mean to widen the link.

Unknown, switched-off, expired and deleted links all render the same closed page on purpose: a message distinguishing them would confirm to a stranger that a token had once been real. Turn a link off and the address is dead immediately.

Delete a report

Click Delete report at the bottom of the editor and confirm. Deleting is permanent — there's no undo — but it removes only the report definition; the records in your tables are untouched.

Ask for a report in chat

The fastest way to a report is to describe it: tell Ask RowFold “revenue by month as a report I can share” and it proposes name, columns, grouping, filters, and chart type on a card. Confirm and the saved report exists at Reports, chart and CSV export included. Two more paths land in the same place: answers that ran an aggregation grow a 💾 Save as report button, and any dashboard metric tile built with “Build a metric” has a Save as report page button in its configuration.

Intelligence

Dashboards

Dashboards are composable boards of live tiles — KPI cards, charts, tables, an AI summary, and an activity feed — laid out on a drag-and-drop grid. Each tile draws from a saved report or a metric you build on the spot over your data, and a board can be shared with the team or set as everyone's workspace home.

Create a dashboard

Open Dashboards in the rail and click + New dashboard — RowFold creates an empty board and drops you into the builder in edit mode. You can also jump between boards, or start a new one, from the dashboard switcher at the top-left of any dashboard.

A board is a grid of tiles. Add them from the panel on the right, arrange them, then click Save dashboard. Boards you can see appear as cards on the Dashboards page, with the workspace home and most-recent boards first.

Tiles you can add

In edit mode, the Add a tile panel offers eight types:

  • KPI card — one metric, with an optional sparkline and trend.
  • Line chart — a value over time.
  • Bar chart — compare across groups.
  • Donut / pie — each group's share of a total.
  • Data table — rows from a table or a saved report.
  • AI summary — plain-language highlights and anomalies about your workspace.
  • Activity feed — the most recent record changes.
  • Text / notes — a heading or bit of context you type in.

Click a type to drop it on the canvas. A tile's title is editable inline, and the × removes it.

A dashboard with four number tiles across the top — pipeline value, open deals, average deal size, ARR potential — then a bar chart of pipeline by stage, a donut of companies by industry, a line chart of closing by month, and a table of recent activity.
Every tile reads live from your tables. The range control at the top narrows all of them at once.

Connect a tile to data

KPI, chart, and table tiles show a gear in edit mode — click it to choose where the numbers come from:

  • Saved report — point the tile at any report in the workspace, and its numbers stay in sync with that report. The Pull a saved report shortcuts in the panel do this in one click.
  • Build a metric — pick a table and a measure (count of records, or sum, avg, min, or max of a numeric field). Charts add a Group by field; grouping by a date lets you bucket By month, quarter, or year. A KPI can set an optional Trend by date field to draw its sparkline and change figure.

While you edit, tiles preview against your real data without saving, so you see the result before you commit it.

What the chart tiles can do

Bar and line tiles use the same chart engine as the report page: a proper axis with round numbers, every series plotted rather than just the first, a tooltip that reads all of them at the point you're hovering, and marks you can reach with the keyboard.

Tiles adapt the data to the space they're given rather than scrolling — fewer ticks, thinner bars, labels thinned before they'd overlap — so a chart stays readable in a small tile. Resize the tile and it redraws for the new shape.

Clicking a bar or a point drills through to the records behind it, exactly as it does on a report. A tile you've just configured and not yet saved drills too.

A tile that measures a rollup, lookup, formula or auto number resolves it properly — totalling a rollup is one of the most obvious things to want on a dashboard. If a measure can't read anything, the tile says so and points at the setting rather than drawing a flat line at zero. Blank cells are skipped rather than counted as zero, so an average isn't dragged down by records that simply have no value.

Arrange the grid

The canvas is a 12-column grid. In edit mode, drag a tile by its header (or anywhere on a KPI) to move it, and drag the bottom-right corner to resize; tiles snap to the grid. Give the whole board an accent colour from the panel to tell your dashboards apart.

Save dashboard keeps the layout, titles, accent, date range, and every tile's data connection. Cancel discards everything since you started editing — nothing is written until you save.

Generate with AI

In edit mode, click Generate with AI, describe what you want to see — "revenue and pipeline health, plus a recent-activity feed" — and RowFold lays out a set of tiles wired to your real tables and reports. Without an Anthropic key configured it still builds a sensible starter layout from your workspace's tables. Generating replaces the current layout, so use Cancel to undo it if you don't like the result.

The AI summary and activity feed

The AI summary tile writes a few grounded highlights about your workspace — what's up, what's at risk — and flags an anomaly when the numbers suggest one. When AI isn't configured it falls back to a plain heuristic summary, clearly labelled as such. The Activity feed lists the most recent record changes across the workspace, each dot coloured by its table.

Filter by date range

The Range control at the top of a board — This quarter, This month, Last 30 days, Year to date, or All time — narrows the tiles that are built on a date, such as a chart grouped by a date field or a KPI with a trend date. Tiles without a date dimension are unaffected, so the range never invents a filter that can't apply.

Click a chart to filter the whole board

Click a bar or a point on a dashboard chart — Won, say — and every other tile reading that same table narrows to the records behind it. Total value, the breakdown by month, the table of recent rows: all about Won deals until you clear it. Click the same bar again, press Escape, or use the × on the bar that appears at the top of the board.

Nothing is saved. A selection is an exploration, not configuration, so it never rides the URL and the next person to open the dashboard never inherits yours.

The chart you clicked keeps all of its bars, with the one you chose picked out and the rest faded — that's what lets you move the selection somewhere else without starting again. Every other tile says whether the filter reached it, and the ones it couldn't reach say why: an activity feed is a log of edits rather than a total, a tile built on a saved report carries that report's own filters, and another table's records aren't what “Stage is Won” is about. The bar at the top counts them — “6 of 8 tiles narrowed” — and names the exceptions one by one.

View records on that bar lists the records behind the selection.

Share a dashboard and set a home

Click Share to control who sees a board. Set its visibility to everyone in the workspace or only people you invite, invite teammates by email as Can view or Can edit, and change or remove access per person. The owner and workspace admins always keep full control.

Turn on Workspace Home to make a board the one everyone in the workspace is pointed to — only one board per workspace can be the home, so setting a new one clears the last.

Intelligence

Schema suggestions

A review of your workspace's shape and the real data in it, proposing changes that would make it more useful — a column that should be a date, a total a parent should carry, a set of columns that are really a table of their own. Every suggestion quotes the numbers it is based on, shows what it would do to your data before you commit, and can be applied in one click. Admin only.

Run a review

Open Schema & relations in the left rail's Workspace section and choose ✦ Schema suggestions. The review reads your tables, your fields and a sample of the values in them, then proposes changes. It takes around half a minute and narrates what it is doing as it goes, because most of that time is spent measuring your data rather than waiting on the model.

It counts against your workspace's AI allowance, so it runs only when you ask for it — never on page load, and never on a schedule.

An empty result is a real answer. If the review finds nothing worth changing it says so, rather than inventing something to justify the trip.

What it can propose

A closed list, so that every suggestion can be checked against your schema and carried out rather than just described:

  • Field type — a text column whose values are really dates, money, an email address or an address. Retyping gives you sorting, date filters, calendar and map views and calculations.
  • Pick list — a text column with a small, repeated set of values that should become options, so it can be grouped and shown as a board.
  • Calculation — a total, count or looked-up value a record should carry from the records linked to it.
  • Link — two tables that describe related things with no relationship between them.
  • Relationship — a link marked “many per record” where every record only ever links to one.
  • Ownership — a link whose child records only make sense inside one parent.
  • New table — several columns that are really describing a separate thing, with the values repeating across rows to prove it.
  • Formatting — a calculated column printing a bare number where it means money, a percentage or a duration.
  • Cleanup — a column nothing has ever filled.
  • Automation — work the data shows is being done by hand, repeatedly.
  • Approvals — sign-off that is plainly already happening in a status column somebody can overtype.

Suggestions where the work is

You do not have to go back to the map to act on a review. Once one has run, any table with something outstanding carries a quiet ✦ Suggestion button on its toolbar — on the grid, and on the calendar, timeline, tree and map views too. Open it and you get the same card, with Apply in place.

It appears only when there is something to say about that table, and only for admins. No review, or nothing outstanding, and there is no button.

See what a change would do first

Every suggestion is measured against your actual records before you decide, and says so plainly. The most useful thing it will tell you is how little most changes touch: changing a field's type rewrites nothing. Every value is stored as text, so retyping a column changes how it is read and not one byte of any record — and you can change it back.

Where a change does touch stored data — removing an unused column, making a link an ownership one so children delete with their parent, extracting a table — the card says so in stronger terms. What this is based on opens the counts and sample values behind the suggestion, and where there is a row-by-row difference to look at, you can open that list too.

Apply, or decline

Apply carries the change out. Where several suggestions only add things — a calculated column, a link, an automation — the panel offers to apply those together; changes that alter or remove something stay one at a time, so it is always clear which one mattered.

Not for me declines a suggestion for the whole workspace, and it sticks. Declining is remembered against what was proposed rather than how it was worded, so the same idea cannot come back in a new phrasing on the next run.

You will never be nagged about work you have already done. Before anything is shown, each suggestion is re-checked against your live schema — so a change you made yourself in the field editor, through an import, or over the API retires its suggestion automatically, with nothing to tick off.

How current a review stays

A review is kept so you can come back to it: reopening the panel shows the last one immediately instead of spending another. It tells you when it ran, and Review again starts a fresh one.

It stops being offered on a table's toolbar once its evidence no longer holds — when you change the schema, when the number of records has moved appreciably, or after a fortnight. The map still shows it after that, with the reason and a button to run another, because there the caveat is on screen where a quiet button on a grid has nowhere to put it.

Structure & schema
Structure & schema

Tables & field types

Tables are the building blocks of your app — customers, projects, invoices, or anything your team tracks. This article covers creating a table (blank, from a template type, or with AI) and designing its fields: every field type, how to configure choices and cross-table connections, and what really happens when you delete a field.

Create a table

On the Tables page, click New table (in an empty workspace it reads Create first table). Give it a Table name and pick a Template typeCustom starts blank, while every other type comes pre-built with its typical fields. Click Create and add fields → and you land straight in the field editor.

Only workspace Admins can create tables. If you don't see the buttons, ask an Admin of your workspace.

Start from a template type

Each template type pre-builds the fields that kind of table usually needs, so you're editing a working table instead of a blank one:

  • Customer — Email, Phone, Status (Lead / Active / Inactive), Notes.
  • Project — Status (Planned / Active / Blocked / Complete), Start Date, Due Date, Budget.
  • Task — Status (Todo / In Progress / Blocked / Done), Priority (Low / Medium / High / Urgent), Due Date, Done.
  • Asset — Serial, Status (In Service / Maintenance / Retired), Acquired, Value.
  • Event — Start (required), End, Status (Scheduled / Confirmed / Completed / Cancelled), Notes.
  • Invoice — Amount (required), Issued, Due, Status (Draft / Sent / Paid / Overdue).
  • Document — URL, Type (Contract / Proposal / Spec / Report / Other), Status (Draft / Review / Final).

Template fields are ordinary fields — delete them or add more alongside them freely afterwards. The type itself is chosen at creation and can't be switched later.

Build with AI

Click Build with AI to describe what you're tracking in plain words — the AI designs the tables, fields, and the relations between them, and you review the plan before anything is created. Click ✦ Design my schema or press Ctrl/⌘ + Enter to generate the plan.

On the plan screen, click ↻ Redesign to try a different description, or approve the plan to create the tables — RowFold then opens the Schema graph so you can see the new tables and their connections.

Like New table, this is available to workspace Admins, and you need a workspace open first.

Add fields

Open the field editor from a table card's Fields button, or from the grid via Edit fields. In the Add field panel, type a Name — RowFold generates the field's key from it automatically, and once the field is saved you can read that key in the API key column. Pick a Type, tick Required on forms if every record needs a value (required fields show a * in the list), then click Add field.

Fields appear in the grid in the order you add them, and the ↑ ↓ arrows on each row move one up or down afterwards.

The first field is what your records are called — its value is the record's name everywhere it appears: the grid's first column, relation chips, search results, notifications. There is no separate name field to add. Because of that, the first field has to be a type that can identify one record — text, a number, a date, an email, or an auto number — so a link, a file, a calculation, or a repeating choice like a Select or a yes/no can't lead the table. RowFold blocks the move and says why. Reordering fields so a different one comes first renames every record in the table, so those two arrows ask you to confirm.

Changing fields you already have

Edit the existing fields directly in the list — rename them, switch a type, change a Select's options, tick Required on forms. Change as many as you like: the rows you have touched are highlighted, and one Save changes at the bottom of the list saves all of them together. If any single change can't be applied — a formula that doesn't compile, or a type the first field isn't allowed to be — nothing is saved at all, the reason appears against that row, and everything else you typed stays on screen so you can fix the one and save again.

Renaming the table itself

The Name & icon card renames the table and sets the emoji the left rail draws beside it. Faster still: right-click the table in the left rail and choose Rename table… or Change icon…. Both need Admin.

Renaming changes the label only — in the rail, the grid header, relation chips, search and notifications. The table's API key and every field key stay exactly as they are, so saved views, reports, automations and anything talking to the API keep working. The icon button opens a picker: search it by what the table is about — “invoice”, “delivery”, “booking” — or paste any emoji you already have. Remove icon drops back to the first letter of the name.

When you're done, Open grid view takes you to your data.

The field editor for a Deals table, listing its nine fields — Deal, Company, Stage, Amount, Probability, Expected close, Deal owner, Industry and Tier — each with its type and its settings, above a panel for adding another.
The whole list is one form: rename several fields, change their types, reorder them, and save once.

Field types at a glance

  • Text — a short, single line of text.
  • LongText — longer free-form notes.
  • Number — a plain number.
  • Currency — a money amount, displayed with money formatting.
  • Date — a calendar date, displayed in your date format.
  • Boolean — a yes/no value, shown as a checkmark when on.
  • Select — one choice from a list you define in Options (comma-separated), shown as a chip.
  • MultiSelect — several choices from your Options list, shown as multiple chips.
  • Email — an email address, edited with an email-style input.
  • Url — a web link.
  • Phone — a phone number.
  • Relation — links a record to one or more records in another table (see the next section).
  • Lookup — shows a value pulled from the record a Relation points to.
  • Rollup — aggregates values from records in another table that link back to this one.
  • Formula — computes a value from an expression over this record's own fields (see below).
  • Percent — a 0–100 value, drawn with a small progress bar in the grid.
  • Rating — a star rating out of five.
  • Progress — a number for tracking completion, shown as a plain value.
  • People — an owner or assignee, entered as a name.
Which group a field is in decides everything else about it: whether you can edit it, whether an import can write it, and whether it can ever be wrong.

Dates that carry a time

A Date field holds a date on its own by default. Tick Include a time on the field and its cells hold a time of day too, with the editors and pickers following automatically. Sorting, filtering, grouping and relative windows like in the next 7 days keep working exactly as they did.

Turning the setting back off leaves every stored time alone, and still visible. A configuration box must never quietly rewrite your records, and hiding the times would be indistinguishable on screen from having wiped the column.

Underneath it sits the setting that actually needs a decision: Show in each viewer's time zone.

  • Off (the default) — the time belongs to a place. A shift, an on-site appointment, a delivery slot: 9:00 AM at the site, whoever is looking. Converting it would be wrong, and with a draggable calendar it would be destructive.
  • On — the time belongs to the people in it. A call, a remote session, a cross-border booking: two people in two places need the same moment shown in their own terms.

Nothing in the data can tell those two apart, which is why the field has to be told. Storage never changes either way.

Connect tables with Relation, Lookup, and Rollup

Relation fields link to other tables. Lookup fields pull a value from a linked record. Rollup fields aggregate values from records that link to this one.

  • Relation — choose which table this connects to. In the grid, each link renders as a chip you can click to peek at the linked record.
  • Lookup — pick the route to follow from a dropdown (directly-linked tables first, deeper routes grouped by how many relationships they cross), then pick which field it should pull in from a second dropdown of that table's fields. Everything is chosen by name — there is nothing to type.
  • Rollup — pick the route to the records you want to total, choose an Aggregation (Sum, Count, Average, Min, or Max), and pick the number to aggregate from a dropdown — not needed for Count. A Formula counts as a number here. If each line carries a calculated line total, the order can sum that directly, with no helper field in between — and it doesn't matter what that formula is built from. It can reach through a link ({Order.Rate}) or read the line's own Lookup and Rollup fields; it is evaluated on the line exactly as it is in the line's own cell. The only formula that can't be totalled is one that doesn't currently compile.

Both Lookup and Rollup can also filter which records they include: once a route is picked, an Only include records where… section appears — add conditions like Stage is Won or Amount greater than 1000, chosen from the far-end table's real fields with the same operators grid and report filters use. "Sum of Amount across Deals where Stage is Won" becomes one field, no helper views needed — and unlike other tools, the conditions work however many relationships deep the route travels.

A condition can also test something one link past the records it is filtering — the dropdown lists those as Order → Type. That is what lets a discriminator live where it belongs: model purchases and sales as one Orders table with a Type, and a product can still total Sum of Quantity across Order Lines, only where Order → Type is Purchase. Without it you would have to copy the type onto every line just to make the filter legal. Pair two such rollups with a formula that subtracts them and a reorder level, and stock keeps itself up to date.

The config appears automatically when you pick one of these types in the Type dropdown. If the table you want isn't linked yet, choose + New link to… at the bottom of the route picker — the Relation field is created for you as part of saving the Lookup or Rollup.

Formula fields: compute a value from an expression

A Formula field computes its value from an expression instead of storing one. Type it in curly braces to reference other fields, combine them with operators and functions, and RowFold recalculates the result every time the record — or a field it depends on — changes.

  • Reference a field on this table by name: {Amount} * {Probability} / 100.
  • Do date maths with - and +{Check Out} - {Check In} is the number of days between two dates, and {Start} + 7 is the date a week later. When the field carries a time the answer keeps the part-day, so wrap it: ROUND({Check Out} - {Check In}, 0) for nights, DATEDIF({Check In}, {Check Out}, "hours") for hours (it also takes "minutes", and is exact where multiplying a day count by 24 leaves a rounding tail).
  • Reach straight through a link — no Lookup field required first: {Company.Region} follows the Company relation field and reads Region off the linked record. Chain it as many hops deep as the schema allows: {Company.Region.Manager}. And there's no syntax to memorise — in the Insert a field list, click the beside a link field to browse the linked table and insert the whole reference with one click.
  • Use functions across text, math, dates, and logic — ROUND(...), IF(...), CONCAT(...), DATEDIF(...), and more. The Function reference in the Add field panel lists every one with its exact usage.
  • Combine with a Rollup for totals across a to-many relation — a formula can reference an existing Rollup field by name ({Total Line Items}) alongside its own math, but can't aggregate a to-many relation directly; that's still what Rollup is for. It also works the other way round: a Rollup can total a Formula, so an order total can sum a calculated line total sitting on each line — whatever that formula is built from, including one that reaches through a link or reads the line's own Rollup.

Formulas are checked as you type — an unknown field name gets an immediate "did you mean" suggestion, and a problem is reported with the exact spot in the expression, not just a generic error. Typing { opens field suggestions (keep typing to filter, dots walk through links), and typing a function name offers completions with their signatures — Enter or Tab accepts.

Prefer plain English? Describe what you want in the ✨ Or describe it box — "profit margin as a percent" — and press Write it for me. The formula is generated and validated against your real schema before it lands in the box, so it can never hand you something that doesn't compile. It counts as one AI action.

Unlike Lookup and Rollup, a formula's expression can be edited any time from its row in the field list — there's no need to delete and recreate it.

Show a computed value as money, a percentage or a bar

Most field types carry their own formatting: a Currency field shows money, a Progress field draws a bar. A Formula or a Rollup has already spent its type saying "this is calculated", so it gets to say how it should look separately — with the Show as setting on the field.

Pick one of:

  • Number — thousands separators, e.g. 1,234.5.
  • Currency — money in your currency and locale, e.g. £1,234.50. A line total of {Qty} * {Unit Price} reads like the Currency column beside it instead of like a bare number.
  • Percent — a trailing %, e.g. 42%. The number isn’t scaled: a formula producing 42 reads as 42%.
  • Progress — the same percentage plus the filled bar you get from a Progress field, so {Done} / {Total} * 100 looks like progress.
  • Duration — minutes as hours and minutes, e.g. 150 becomes 2:30.

For Number, Currency and Percent you can also set Decimals, which is worth doing on anything involving division — that’s how a value acquires fourteen decimal places. Leave it on Auto and the format decides.

This changes the display only. The underlying number is untouched, so filters, sorting, totals and rollups over the field all keep working on the real value — a currency-formatted formula still sorts as a number, not as text.

The format follows the value everywhere it goes: the grid, the peek drawer, the record page, reports and their CSV and PDF exports, generated documents, dashboard tiles, and the grid’s own CSV export. Like the expression itself, it can be changed any time from the field’s row in the field list — no need to delete and recreate.

Lookup fields deliberately have no Show as setting: a lookup re-presents a field that already has a type of its own, and letting the copy restate the formatting is how the two drift apart.

Delete a field

Click the × at the end of a field's row and confirm Delete this field?. The column disappears from the grid and forms right away, but your records are untouched — the values that were stored under that field are hidden, not erased.

Because values are kept, adding a new field later with the identical key brings the old data back into view. New fields are added at the end of the column order, so deleting and re-adding a field also moves it last.

Table emoji and accent color

Every table gets an emoji and an accent color automatically from its template type: Customer 🧑 mint, Project 📁 violet, Task ✅ amber, Asset 📦 sky, Event 📅 rose, Invoice 💸 coral, Document 📄 ink, and Custom 🧱 violet.

They appear on the table's card, at the top of the grid, and in accents like the fill of Percent bars. A table without an emoji shows the first letter of its name instead.

The emoji is yours to change: right-click the table in the left rail and choose Change icon…, or use the Name & icon card in the field editor. Both open the same picker — search by what the table is about, take one you used recently, or paste any emoji — and Remove icon goes back to the first letter. The accent color is set by the template type and is not editable.

Name tables and fields so they read like English

Names are the one thing in a workspace that's hard to change later — every report, rollup, and AI prompt refers to your tables and fields by name, so a clean name keeps everything downstream clean. Four rules keep them honest:

  • Tables are plural nouns. Customers, Deals, Bookings — so one record reads naturally as "a Customer."
  • Fields are descriptive singular phrases. Just Email, not cust_email — the table already supplies the scope.
  • No abbreviations. Spell it out: Expected close, not Exp Cls. It saves more time than it costs.
  • Relation fields name the other side, not the action. The field on Deals that points at Companies is simply Company — not company_id or linked_company.

The payoff is readability: "Sum of Amount across Deals where Stage is Closed Won" is a sentence you can trust; SUM(deal_amt) WHERE stg = 'CW' is a guess at meaning. Watch for names that signal a deeper problem — Status1 / Status2 usually wants two real names like Stage and Health, and a Misc or Other field is often a sign you need a new table or to split an existing one.

Know when to split a table

A table starts as one concept; as it grows you'll feel one of three signs that it's really two concepts wearing one costume. Splitting early is cheap — splitting late is painful.

  • Half the fields are empty for half the rows. If Tasks has renewal_amount and contract_term filled in only for renewal rows, that's two things — split into Tasks and Renewals, with a relation between them if they belong together.
  • You keep filtering by one field. If you filter Contacts by type = "Customer" every single time, that field is doing a table's job — split into Customers and Leads, each with its own fields and relations.
  • Two distinct lifecycles. If some rows run "Open → In progress → Won → Lost" and others run "Draft → Submitted → Paid," they follow different state machines and belong in different tables, even when they share a few fields.

To split safely: create the new table with its unique fields, add a relation back to the original if they stay connected, move the rows with filter → Export CSV → import, update any reports that pointed at the old table, then soft-delete the moved rows (they wait in the Trash if you need them). And resist the urge when it isn't warranted — if two kinds of row share most fields and the same lifecycle, a Select field is plenty. The test: would you write different paragraphs about them?

Auto-number fields: invoice and order numbers that mind themselves

An Auto number field gives every record a permanent sequential number — perfect for invoices, orders, tickets, and quotes. Choose a starting number when you create the field (say 1000); existing records are numbered immediately, oldest first, and every new record takes the next number automatically no matter how it arrives: typed into the grid, imported, created by an automation, the API, a connector, or the AI.

The numbers are read-only by design — nobody can edit, reuse, or accidentally clear one — and they sort and filter like any other number. Records imported with their own numbers keep them.

Attachment fields: files on the record

An Attachment field holds files — contracts on a deal, photos on an inspection, CVs on a candidate. Upload from the record page (10 MB per file, up to 10 files per field); the grid shows a compact 📎 count. Files are stored privately (Azure Blob storage in production) and downloads run through the same permission checks as everything else — a hidden field's files stay hidden. Executable file types are refused outright.

AI fields: a column a model writes

An AI field is a column a model writes for you. You give the field an instruction once, and it applies to every record — “In one line, is this project on track? Status {{record.status}}, {{record.openTasks}} open tasks.”

The {{record.something}} bits pull in that record's own values. They are the same tokens automations use, so a linked record arrives as its name rather than an internal id, and you can reach through a link with a dot — {{record.company.region}}. The field editor lists your fields as buttons; clicking one inserts the right token, so there is nothing to memorise.

Nothing happens until you ask

Cells stay empty until you fill them. That is deliberate — it means opening a big table never quietly spends your AI allowance.

  • One cell: hover it and click the .
  • Many at once: tick the rows, then Fill with AI in the bar at the bottom. It tells you how many cells it will write before it writes any, then runs in the background — the rows fill in as they finish, and you get a notification at the end. Up to 500 rows per run; filter the view down if you need more.

You can always correct it

An AI cell is ordinary text once written: type over it whenever the model gets something wrong. RowFold remembers which cells you have corrected, so a bulk fill skips them and tells you how many it left alone. If you do want them replaced, it asks first — a correction is never lost to a stray click.

Because the value is real text, everything else works on it normally: filter by it, sort by it, group by it, search it, export it, read it through the API.

What it costs

One cell is one AI action from your workspace's monthly allowance, so a 200-row fill is 200 actions. If the allowance runs out mid-run the fill stops and tells you where it got to, rather than failing silently on every remaining row.

Changing the prompt later doesn't rewrite cells you have already filled — regenerate the ones you want updated.

Keyboard shortcuts

Ctrl/⌘Enter Generate the schema plan from your description Build with AI dialog
Structure & schema

Schema map & relationships

The schema map is a live diagram of every table in a workspace and the arrows connecting them, and it lets you create new relationships by dragging between tables. For ad-hoc, one-off links between two specific records, open a record's detail page and use Add a one-off link.

Read the schema map

Open Schema & relations in the left rail's Workspace section. Every table in the current workspace appears as a card showing its name, its record count, and each of its fields with the field's type. Click a card to jump straight to that table's records.

Arrows between cards are relationships. Each arrow carries a pill with the connection name and a count like ×12 — the number of live record-to-record links of that type. The toolbar above the map totals it up: how many tables, how many relationship types, and how many links overall.

The header's Tables button takes you to the table list. To connect two specific records that no relation field covers, open either record's detail page and use Add a one-off link.

The schema map. Four coloured cards — Companies, Contacts, Deals and Activities — each listing its first fields and its record count, joined by curved lines labelled with the field that makes the link. A legend explains the line styles.
One picture of the whole workspace. The label on a line is the field the link travels.

Zoom and pan the map

Use the and + buttons in the map toolbar to zoom between 40% and 200%, and Fit to snap back to 100%. Drag any empty spot on the canvas to pan around a large schema.

Draw a relationship by dragging

Every table card has a small round + port on the right edge of its header. Press it and drag — a dashed line follows your cursor — then drop onto another table. The target table highlights as you hover over it.

A pop-over appears, titled with the two tables — Connect Clients → Projects, say. The name box is prefilled with the target table's name; change it if you like, then press Create relation. This adds a Relation field on the table you dragged from, pointing at the table you dropped on; from then on, you connect records by filling in that field on each record. Press Cancel or Esc to back out.

A link is a connection between two records, not text typed into a cell — which is what lets a lookup and a rollup travel it.

Link two specific records

Most connections are best expressed as Relation fields — defined once on a table and filled in per record. For a genuine one-off between two exact records that no relation field covers, open a record's detail page and use Add a one-off link.

Pick a Target record, give the link a Key (its connection name) and an optional Label, then press Add link. The new link appears under Manual links on that record, and the record it points at lists it under Records that use this — click either side to open the other.

Name the connection

The link's Key is its connection name — the label RowFold groups links by. The optional Label is a human-friendly note shown alongside the connection.

  • A Key that matches a Relation field on the starting record's table is rejected — you'll be told to set that field on the record instead, which keeps the one-off link from being wiped the next time the record saves.
  • Creating an identical link twice (same two records, same Key) quietly does nothing; no duplicate is stored.

See a record's links

A record's own detail page is where its links live: Manual links lists the one-off links you added from it, each with an × to remove it, and Records that use this gathers every record that links to this one — through a Relation field or a one-off link — grouped by table with counts. Click any chip on either side to open that record.

Choose links or Relation fields

Every link is a one-way arrow: it runs from a starting record to a linked record and carries a name. A record can sit on either end of any number of links, so one-to-many and many-to-many shapes both work.

Relation fields are the durable version: defined once on a table, filled in per record, and RowFold keeps the map's arrows in sync with their values. Lookup and Rollup fields — which pull or aggregate values across a relation — are added in a table's field editor, not on the schema map; the map just lists them on the table's card like any other field.

Preview multi-level records (concept)

The page at /MultiLevel is an interactive design concept for nested, multi-level records — a relation marked as owning its children so linked tables nest inside their parent. It is visible only to super admins (an app-operator allowlist), has no link in the rail, and everything on it is hard-coded sample data: edits are never saved, and the Submit → button on the form surface sends nothing.

Four numbered tabs show the same idea from different angles: Schema · composition (a field inspector with ownership modes Reference, Owns children, and Belongs to parent), Record panel · document (parent fields with owned children and grandchildren embedded inline, plus live rollup totals), Public form (LiveForm) (the same nesting as a fillable form with cross-level validation), and Ledger view (one row per parent, expandable to depth L0, L1, or L2).

A dropdown pill in the top bar switches between two demo datasets — Orders → Line items → Serials and Inspections → Rooms → Defects — and switching resets any edits. A floating Tweaks panel toggles Comfortable/Compact density and whether hidden conditional sections show as ghosted hints.

Keyboard shortcuts

Esc Close the Connect pop-over without creating the relation Schema map
Enter Create the relation from the pop-over's name box Schema map
Structure & schema

Subitems: records inside records

Some records only make sense inside another one — the line items on an order, the serial numbers on a line item, the checklist items on a task. Subitems let you build those rows directly inside the parent record instead of creating them separately and linking them up afterwards. This article covers turning a table into subitems, the editable grid you get on the parent, nesting several levels, and what happens when you delete.

Subitems vs. a plain relation

Both connect two tables, but they mean different things.

A plain Relation points at a record that exists on its own and gets reused — a customer, a part in your catalogue, a venue. You pick an existing one.

Subitems mean ownership: the child belongs to exactly one parent and is created inside it. You add them, you don't pick them. Delete the parent and they go too.

If you find yourself creating a record in one table just so you can link it from another, that relationship almost certainly wants to be subitems.

Nothing is copied and no field is added — the child records still live in their own table. Only where you read them changes.

Turn a table into subitems

Do it from the parent — the way you'd describe it out loud (“an order has line items”).

  1. Open the parent table and choose Edit fields.
  2. In the Subitems panel, pick the child table.
  3. Press Make subitems of ….

RowFold adds the link on the child table pointing back at the parent (or reuses one that's already there). You never have to build the relation in reverse yourself.

Already have the relation on the child table? Open that table's field editor and press Make subitems on the relation row instead — nothing is recreated and no links are lost.

The grid on the parent record

Open any parent record and the subitems appear as a grid below its fields, with an Add… button. Rows are editable in place — click a cell, type, tab onward.

Computed columns ride along read-only, so a per-line lookup or rollup is visible while you work. The link back to the parent isn't shown as a column: it's always this record, so showing it would just be noise.

A relation column inside the grid (a line item's part number, say) gets a picker that searches the target table — and if what you need isn't there yet, type the name and choose Create to make it and link it without leaving the row.

Nesting several levels

Subitems nest. If serial numbers are subitems of line items, and line items are subitems of orders, then each line item row in the order gets an expander (▸). Open it and that line item's serial numbers appear, with their own Add button.

Levels load only when you expand them, so a long order stays fast. Nesting is capped at four levels deep — past that, open the row itself (↗) to keep going.

Totals from subitems

A Rollup on the parent summarises its subitems. An order total is a Rollup over Order Line Items, through the link back to the order, summing the amount field.

Because the rollup follows the same link the grid does, the number tracks whatever you type into the rows.

Deleting and restoring

Deleting a parent sends its subitems to the Trash with it, all the way down — an order takes its line items, and their serial numbers.

Restoring the parent from the Trash brings back the ones that went down with it. A subitem you had already deleted separately, before the parent, stays deleted — restoring a parent won't quietly resurrect things you meant to get rid of.

Letting AI find the hierarchy

When you describe a schema in Build with AI, it now marks the parent/child relationships itself — ask for orders with line items and serial numbers and you get the nesting, while shared things like a parts catalogue stay ordinary relations. The preview labels them inside … so you can see the shape before anything is created.

For a workspace you've already built, open Schema and press Suggest hierarchy. It reviews the relations you have, proposes the ones that look like ownership with a reason for each, and applies only the ones you tick.

Keyboard shortcuts

Enter Commit the cell you're editing Subitems grid
Esc Discard the edit and restore the previous value Subitems grid
Structure & schema

Units of measure

Give Number fields a unit, so values entered in grams, kilograms and tonnes total correctly — stored canonically, displayed in the unit you chose, and never converted across kinds of thing.

Classes, and the units inside them

A class is a dimension — mass, length, count, volume, time, area, or anything your business invents. Inside it sit the units: mm, m, km. One unit in each class is the base, and every other unit says how many base units it is worth (a millimetre against a base of metres is 0.001).

A workspace arrives with a seeded library so nobody starts from an empty page. Seeded rows are editable but flagged, so "did I define this, or did RowFold?" always has an answer.

Stored canonically, shown in your unit

A value is stored in the unit the column declares — not the class's base unit, and not whatever it happened to be typed in. Type 1200 g into a column held in kilograms and 1.2 is what lands in the cell; the column, its total and its export all read 1.2 kg. That is what makes a column people fill in grams, kilograms and tonnes add up to the right number: the conversion happens once, on the way in, so everything downstream is adding like to like.

What you typed is not thrown away. It stays beside the value, seeds the editor when you reopen the cell, and shows on the cell's tooltip — so a row entered as 1200 g still says so.

Changing the column's unit later converts the values with it. Move a column from kilograms to grams and every stored number is multiplied through exactly, once, inside the same save — the confirmation tells you how many changed. This is the one config change in RowFold that rewrites records, and it does so because the alternative is worse: leaving them alone would keep the same digits under a new label, silently restating every number by a factor of a thousand. Moving to a unit in a different class is refused instead, because no exact factor exists.

Conversion inside a class only — never across one

Units convert freely within a class. Across classes, conversion is refused rather than guessed.

This is the whole safety property. Turning a mass into a length depends entirely on what is being measured, and a silent 1:1 fallback is exactly how a figure ends up wrong by three orders of magnitude with nothing raised. If you genuinely need to cross classes — kilograms per metre of a specific product — that factor belongs on the record, not in the unit table.

Decimals, not floats

Conversion factors and converted values are held as decimals end to end, in C# and in the database. Binary floating point is how 0.30000000000000004 ends up in front of somebody on an invoice, and it is not used here.

Each unit also carries the number of decimal places to show when a value is displayed in it — a display setting, not a storage one.

Structure & schema

Numbering sequences: identifiers people can read

Turn an AutoNumber field into a formatted identifier — WO-2026-0042 rather than 42 — with per-category prefixes, resets, and control over the moment a number is handed out.

Where to set it

A format is a setting of an AutoNumber field, so you set it on that field: Edit fields → the AutoNumber row → the Format box. Type WO-{YYYY}-{####}, and the line underneath shows what the next record will get. Leave it empty and the field keeps handing out plain numbers.

The restart policy and the moment a number is allocated sit on the same row. You only need the separate Numbering page for one thing: running several schemes off a single column — PO- and SO- numbering independently, each with its own condition and priority. The field's row links straight to it.

It extends AutoNumber, it doesn't replace it

A sequence writes into an existing AutoNumber field. A field with no sequence attached keeps handing out plain integers exactly as before, so switching this on is additive.

AutoNumber was chosen deliberately over a Text field: it is already server-owned, so no write path anywhere — grid, import, automation or public API — will accept a value for it. Nothing new had to be protected to make an identifier trustworthy.

The format

A format is literal text plus tokens: {YYYY}, {YY}, {MM}, {DD}, and one run of {#…} whose length sets the zero-padding. WO-{YYYY}-{####} produces WO-2026-0042.

Formats are validated when you SAVE the configuration, not when a record is created — an unknown token is a mistake you can fix while looking at it, rather than an error thrown from inside somebody's save six weeks later.

The counter is the part worth understanding: it is never reused, so a deleted record leaves a gap rather than letting a number be issued twice.

Several sequences on one field

More than one sequence can target the same field. Each carries a condition and a priority, and the first match by priority wins.

That is what "different prefixes per category" means in practice: PO- and SO- can live on one Orders table, each with its own counter, numbering independently off the same column.

When the number is handed out

Two choices. On create stamps the number the moment the record exists. On transition waits until the record reaches a particular lifecycle state.

Where a lifecycle exists, on transition is the recommended setting. Allocating on creation means every abandoned draft burns a number, and a sequence full of holes reads as broken to everyone who sees it — even though it is working exactly as designed.

Counters can reset yearly, monthly or never, and are advanced atomically, so two records created at the same instant cannot collide.

Structure & schema

Effective dating: links that stop being true

Give a relation a validity period, so a link that has ended drops out of lookups, rollups and anything that travels the relationship — without anyone having to remember to unlink it.

Turn it on per relation field

Dating is a setting on a Relation field, in the field editor. With it on, each link can carry a from and a to — this employee reported to that manager from January to June; this product sat in that category until the range was renamed.

Switching it on changes nothing until somebody actually dates something. An undated link is true at every instant, so existing data keeps behaving exactly as it did.

Half-open periods

A period includes its from and excludes its to. A link running to 1 July and another starting 1 July do not both cover that day — the first has already ended when the second begins.

This convention is applied in exactly one place in the product rather than restated at each call site, which is what stops half the comparisons ending up inclusive on both ends. The symptom of getting it wrong is a link that belongs to two periods for a single day, and it is precisely the kind of thing nobody notices until a total is out by one.

You choose whether periods are measured by day or by instant when you turn dating on.

Tom's link ends on 1 September and Priya's starts on 1 September, so on that day the account has exactly one owner — not two.

Overlaps are refused by default

Writing a period that overlaps an existing one on the same link is rejected unless you say otherwise. A record quietly having two parents on the same day is the kind of wrong that only ever surfaces when one report disagrees with another.

Where overlap is genuinely real — someone who honestly did report to two managers — you can soften the policy on that field to warn (allowed, but flagged) or allow (silent).

What this does today

Dated links are stored, validated and policed on write, and resolution honours the period: a link whose period has ended is not returned, so lookups, rollups and computed fields that travel that relationship stop counting it automatically.

What is not here yet is reporting as of a chosen past date — asking the workspace to show the world as it stood last March. The resolver already takes a date; nothing in the interface asks you for one. Today's behaviour is "as of now", correctly.

Structure & schema

Currency & exchange rates

What a Currency column's amounts are IN, and who decides. The currency belongs to the record, not to whoever is reading it — everyone sees the same amount on the same record. Teams working in one currency never have to think about any of this; teams holding several can say so, mark individual columns, and supply the rates to total across them.

The currency belongs to the record

A deal worth $300 is worth $300 to everyone who opens it. RowFold takes the SYMBOL from the workspace's data, never from the reader — so a colleague in London sees $300, not £300.

Your personal setting still matters, but only for how numbers are punctuated: whether that reads 1,234.50 or 1.234,50. That part genuinely is yours. The amount and its currency are not.

A currency cell is never redrawn in the reader's own symbol. Your settings change how numbers are punctuated, never what an invoice says.

Set the workspace's currency

In Settings, each workspace you administer has a Currency setting. Leave it on Follow the owner and it uses the preference of whoever owns the workspace, which is almost always right and means a new workspace needs no setup at all. Choose a currency explicitly to pin it.

Changing it never rewrites a stored amount and converts nothing. It changes what the numbers already on your records are understood to be in, so change it because it was wrong, not to convert your data.

If you hold more than one currency

Tick We record money in more than one currency in the same place. Until you do, there is one currency in the workspace and nothing anywhere asks you to pick one — that is deliberate, and it is why most teams never meet this page.

With it on, each Currency column can carry its own currency: open Edit fields on the table and choose one on the column's row, or leave it following the workspace. A column's currency is ignored while the switch is off, so turning it back off cannot leave columns quietly formatting in a currency the workspace no longer claims to use.

Exchange rates, and why you supply them

Once a workspace records several currencies, Settings gains an Exchange rates table. You enter the rates: a pair, a number, and the date it took effect — “1 GBP = 1.27 USD from 3 Aug 2026”.

RowFold does not fetch rates from a market feed, on purpose. A live rate moves every second, carries a spread the product cannot see, and would make a figure on your screen change with nobody editing anything. The rate you booked at is a fact; a rate scraped this morning is not.

Add a newer rate for the same pair whenever it moves. Rates are kept by date, so the old ones stay true for the records they applied to. A rate entered for the same pair on the same day replaces the earlier one — that is a correction, not a second fact.

Totalling a column that holds several currencies

Summing a column of dollars and pounds by adding the numbers gives you a total of nothing. So wherever RowFold adds money up — a column total on the grid, a group subtotal in a report, a KPI or chart tile on a dashboard — it converts each record at the rate in force when that record was created and adds the converted amounts. That is how transaction-date conversion works in accounting, and it means the answer does not drift as rates move.

Only the total converts. The records themselves keep the currency they were written in: a £250 deal still reads £250 in its row, next to a total that has counted it as $317. Restating the row would be the product asserting an amount nobody agreed.

If a pair has no rate, nothing is guessed. The grid says Mixed currencies instead of a number; a report shows the total it could reach and states the shortfall beneath it — “38 of 41 — 3 need a GBP → USD rate”. No unconvertible row is quietly counted as zero or treated as parity, because a total that silently covers part of a column looks complete and isn't.

Automate & connect
Automate & connect

Automations: when this happens, do that

Automations watch your data and act on it: when a record is created, updated, deleted, enters a matching state, on a schedule, or when an outside system posts to a webhook URL, they run steps — update fields, create records, send emails, call webhooks, or generate text with AI. Every run is logged with a per-step breakdown.

Pick a trigger

Open Automations in the sidebar and press New automation. Choose when it fires: a record is created, updated (optionally only when specific fields change), deleted, matches conditions, on a schedule, or a webhook is received.

Matches conditions is the “status becomes Done” trigger: it fires only when a record enters the matching state — editing a record that already matches won't re-fire it.

Schedules run every N minutes (5 minimum), daily, or weekly at a UTC time. With a table chosen, the schedule runs once per record matching your conditions (up to 100 per fire); without one it runs once per fire.

Every automation is these three parts. Leaving the middle one empty means it runs every time.

Trigger from anywhere: a webhook is received

Pick A webhook is received and, once saved, the automation gets its own inbound URL — shown in the editor with a copy button. Paste that URL into any system that can send a webhook (a form tool, a payment provider, Zapier, your own code) and every JSON POST to it fires the automation.

The payload is available to every step as {{webhook.<path>}}: a body of {"status": "paid", "customer": {"email": "a@b.com"}} gives you {{webhook.status}} and {{webhook.customer.email}}, and array items use numbers — {{webhook.items.0.name}}. The whole raw body rides along as {{webhook.body}} for forwarding.

Conditions work too, checking payload paths with the same operators — only run when status equals paid. A post that doesn't match is logged as a Skipped run, so "why didn't it fire?" is always answerable from Run history.

There is no trigger record on a webhook fire, so the steps that write into "the record" (Update the record, Generate with AI, Generate a document) aren't available — Create a record with {{webhook.…}} values is the usual shape: "when the payment provider posts, create a Payment record."

The URL is unguessable and acts as the credential — treat it like a password, and it stays stable across edits so the system you pasted it into keeps working.

Add conditions

Conditions narrow any trigger: field equals / contains / is empty / greater than…, matched all or any. Numbers and dates compare properly (“due date less than 2026-08-01” works on Date fields). Use Name (display name) to test the record's name.

Stack the steps

Steps run top to bottom; if one fails, the rest are skipped and the run is marked accordingly. Five actions are available: Update the record (set fields on the trigger record), Create a record (in any table of the workspace), Send an email (up to 10 recipients), Call a webhook (POST JSON to your URL), and Generate with AI (write model output into a field).

Every text box accepts template tokens that render per run: {{record.name}}, {{record.id}}, {{record.url}}, and {{record.<field_key>}} for any field, plus {{table.name}}, {{workspace.name}}, {{trigger.summary}}, {{now}}, and {{today}}. Unknown tokens render as empty text, and field keys are the same slugs the API uses.

An automation called “Qualify big new deals” being edited. Section one is the trigger: when a record is created, in the Deals table, where Amount is greater than 50000. Section two is the steps: update this record, setting Probability to 40.
The same three parts as the diagram above, as the editor lays them out.

Watch it run

Run history shows every execution with status (Succeeded, Failed, Partly failed, Skipped), duration, the triggering record, and each step's result. Use Run now in the editor to test against the table's newest record. Changes made by automations appear in the audit log as Automation · its-name.

Chains are guarded: an automation whose changes trigger another automation works (to 3 levels deep), then the loop guard stops the chain and logs a Skipped run explaining why. Run history is kept for 90 days.

The run history. Each row shows a green Succeeded pill, the automation's name, what set it off and on which record, and how long it took.
Every run names the record that triggered it — which is how “why did this one change?” gets an answer.

Update a linked record, and do arithmetic

An Update the record step doesn't have to change the record that triggered it. Which record to update also lists the relations on that table, so you can follow one and write to what it points at — “when a dispatch is created, update the linked part”.

Each assignment also picks an operation: Set to, Increase by or Decrease by. For the last two the value is the amount, and it can be a token — {{record.qty}} — so a dispatch of three units takes three off stock.

That combination is what lets automations do real inventory work: decrement on hand when something ships, add it back on a return, roll a counter forward.

Increases and decreases are applied by the database in a single operation, so two runs firing at the same time can't both read the same starting number and overwrite each other. Stock stays correct under concurrent dispatches.

Tick Never let it go below zero and a decrease that would go negative writes nothing and fails the step instead — you get a failed run to look at rather than a quietly negative balance.

Draft automations by asking

You can describe a rule to Ask RowFold instead of building it by hand: “when a dispatch line item is created, reduce that product’s stock by its quantity”. Ask drafts the trigger, conditions, and steps on a card; confirming creates the automation switched off, with a link straight into this editor to review and enable it. Cross-table rules use the update-linked-record step described above, including safe increment and decrement arithmetic.

Automate & connect

Channels: everything that talks to the outside

A channel is any way data crosses the edge of your workspace — in from people who have no login, or out to the systems you run. Forms, Email In mailboxes, Webhook In endpoints, chat widgets, booking pages, automation webhooks, connectors, outgoing webhooks, shared view links and API clients are all channels, and Channels lists every one of them in a single place.

What counts as a channel

Ten things, and they divide by direction rather than by which part of the app happens to build them.

Coming in: a form (a public link people fill in), Email In (an address people write to), Webhook In (a URL your own systems POST to — each JSON POST becomes a record, in a format RowFold publishes), and an automation webhook (a URL that fires an automation — for payloads whose shape the sender dictates).

Both ways: a chat widget (visitors write, you answer), a booking page (it publishes your availability and sends confirmations), a connector (a tool you already run), an API client (your own code, doing whatever its scopes allow).

Going out: an outgoing webhook (we POST the moment a record changes) and a shared view link (a read-only public page for one saved view).

Ten in all. Each is reachable by whoever holds its link or key, which is why they are worth being able to see in one list.

The question this page answers

What of ours is reachable right now, and what does it write to? Every row names the table it files into, so you can see at a glance that the form somebody published last quarter is still open and still filling up a table nobody watches.

The count at the top says how many addresses answer a stranger who has the link. That is the number worth knowing: seven of these surfaces are protected by an unguessable token rather than a login, so the address is the key. The count never changes when you filter the list — it is always about the whole workspace.

Public, Live, Paused

Three states, and the difference matters. Public means anyone holding the address gets a real answer right now. Live means the channel is running but exposes nothing of yours — an outgoing webhook reaches out to you, and an API client needs a secret as well as the client id you can see here. Paused means it answers as closed; nothing is deleted, and the address is never reused for anything else.

Adding and changing one

Forms, chat widgets and booking pages are born in a table's view bar, under the Channels group — open the table you want records filed into and add one there. Email In and Webhook In are set up from that same group, on their own pages. Connectors live in Integrations, API clients and outgoing webhooks in Developers, and an automation webhook is an automation with a “webhook received” trigger, created in the automation editor.

Channels itself is a list, not an editor. Every row links to the page that already manages that channel, so pausing, editing and deleting all happen where the rules for them live.

Who can see it

Workspace admins. The rows carry the public tokens that are the whole authentication for the anonymous surfaces, so the list is closer to a set of credentials than to a report. Members see an ask an admin note instead — which matches the view bar, where adding a channel already needs admin.

Automate & connect

Webhook In: POST records straight into a table

A Webhook In endpoint is a URL that files JSON POSTs into one table — Email In for machines. RowFold publishes the exact format on the endpoint's page, using the table's own field keys, so anything that can send an HTTP POST can create records: a script, a payment provider's custom action, an automation tool, ten lines of your own code.

What it is

Create an endpoint from a table's view bar (the Channels group) or from Channels → Add a channel, and you get a URL. Every JSON POST to it becomes a record of that table, immediately — no automation to build and no mapping to configure, because the payload's keys are the table's field keys.

Records created this way are ordinary records: AutoNumber stamps them, automations and outgoing webhooks fire for them, live grids pick them up, and the audit log names the endpoint that filed each one.

The format is published, not guessed

The endpoint's page writes out the exact body to send — a real example built from the table's live schema, with a copy button and a ready-made curl line. It is one JSON object: an optional displayName (left out, the record is named after the first field's value, the same convention as the grid) and a values object keyed by field key. It is the same envelope as POST /api/v1/tables/{id}/records, so a sender that outgrows the endpoint moves to the REST API without reshaping its payload.

Bad payloads are refused loudly: a 400 with a problems list naming each unknown key, unwritable field or malformed date — and nothing partial is stored. A retried POST carrying an Idempotency-Key header replays the original answer instead of filing twice.

What a POST may write

Any field a person could type into — including AI fields, which store text like any other. Computed fields (Lookup, Rollup, Formula, AutoNumber) have no stored value to write, attachments only move through their own upload endpoints, and a field governed by a lifecycle or approval policy is refused here for the same reason Email In refuses to map one: an anonymous URL must not move records through states. The endpoint's page lists exactly which fields are out, and why, under the example.

Relation values are record ids. Every id is checked against the relation's own target table before anything is stored — a guessed or foreign id links nothing, and the POST is told so.

Security

The URL is unguessable and acts as the credential — treat it like a password. Pausing the endpoint makes the URL answer 404 until you resume it; deleting it is permanent, though the records it created are untouched.

For senders that can compute an HMAC, tick Require signatures: each POST must then carry X-RowFold-Signature: t=<unix seconds>,v1=hex(HMAC_SHA256(secret, "<t>.<body>")) with the timestamp within five minutes, and anything unsigned or mis-signed gets a 401. It is the exact scheme RowFold's outgoing webhooks sign with, so one implementation covers both directions. The secret can be rotated at any time — that is the leak response — and rotation only breaks senders while enforcement is on.

POSTs are rate-limited per sender address, and a body is capped at 128 KB.

Webhook In or an automation webhook?

Same transport, opposite contracts. Webhook In publishes RowFold's format for one table and the sender conforms — right whenever you control the sender. An automation webhook accepts whatever shape the sender dictates (Stripe, a form tool) and the automation's steps reshape it with {{webhook.…}} tokens, run conditions, and can do things other than create a record. Pasting a URL into a system whose payload you can't change? Use the automation. Writing the sender yourself? Use this.

Both inbound kinds look the same from outside. What differs is who decides the shape of the message.
Automate & connect

The REST API, API clients, and webhooks

The Developers page manages workspace-scoped API clients for the REST API (/api/v1) and outbound webhooks that push record changes to your systems. Clients exchange an id + secret for a short-lived access token. Full endpoint reference with curl examples lives at /Developers/Docs.

Create an API client

Only workspace Admins can create clients. On Developers, name the client, choose when it expires (30 / 90 / 365 days or never), and pick its scopes — read (every GET: tables, records, audit), write (create, update, delete, and restore records), and schema (create tables and fields, and manage webhooks) — then press Create client.

You get a public Client ID (rfc_…, safe to share) and a client secret (rfsk_…) shown once — copy the secret immediately, because RowFold stores only a hash of it and can never display it again. The client is your durable credential; it never rides on API calls. Instead, exchange it for a short-lived access token:

curl -X POST https://YOUR-HOST/api/v1/auth/token -H "Content-Type: application/json" -d '{"clientId":"rfc_…","clientSecret":"rfsk_…"}'

That returns an accessToken (a signed JWT) with expiresIn seconds — about an hour. Send it as Authorization: Bearer <accessToken> (an X-Api-Key header works too) on every other call, and exchange again when it expires. A client acts on its one workspace with admin-grade access, so treat the secret like a password — keep it server-side and never ship it in client code. Revoke a client from the Developers page at any time; it then mints no new tokens, and any it already issued stop working within the hour.

Call the API

Every request goes to /api/v1 over HTTPS, and every response is JSON. After exchanging your client for an access token, confirm it with GET /api/v1/meta, which echoes the workspace it opens, its scopes, and its expiry. A first real call — list your tables and their field keys — looks like this:

curl https://YOUR-HOST/api/v1/tables -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Conventions hold everywhere: JSON is camelCase in and out, timestamps are UTC ISO-8601 (their field names end in Utc), and record values are keyed by field key — the stable slug listed by GET /tables, with Relation values as arrays of record ids. Errors always use one envelope, { "error": { "code", "message", "details" } }, with a matching status: 400 validation (details names the fields), 401 a missing, invalid, or expired access token, 402 the workspace's trial has ended, 403 the token lacks the required scope, 404 not found in this workspace, and 429 rate limited. Each access token may make 300 requests per minute (a sliding window); over that returns 429 with a Retry-After header. The token-exchange endpoint has its own tighter per-IP limit — cache your access token for its lifetime instead of exchanging on every call.

API writes behave exactly like edits made in the app: they run through the same pipeline, land in the audit log as API · your-client-name, and fire your automations and webhooks. Deletes are soft — DELETE moves a record to the Trash, and restore brings it back.

Open the interactive API reference

Open the API reference at /Developers/Docs — the complete, per-endpoint reference and a live console. Enter a client ID and secret to authorize (it exchanges them for an access token in-browser) and every endpoint gains a Try it runner that calls your own workspace, next to copy-ready samples in cURL, JavaScript, and Python. Path fields like tableId autocomplete from your workspace once you authorize; read-only calls are marked safe to run and writes are flagged because they act on real data. It is the canonical place for the exact parameters, request body, and response of every endpoint — start there whenever this overview isn't specific enough.

What you can call

The API reaches everything in a workspace. Endpoints, with the scope each needs:

  • MetaGET /meta (any scope): the workspace a token opens, its scopes, and expiry.
  • TablesGET /tables (read) lists every table with its fields and field keys; POST /tables (schema) creates a table and optional starting fields; PATCH /tables/{tableId} (schema) renames one (its slug and field keys stay stable).
  • FieldsPOST /tables/{tableId}/fields (schema) adds a field; PATCH /fields/{fieldId} (schema) renames a field or edits a Select/MultiSelect's options. A field's key never changes; Relation fields need a relatedTableId, and computed Lookup and Rollup fields can't be created through the API.
  • RecordsGET /tables/{tableId}/records (read) lists them with paging, sorting, search, and filters; POST /tables/{tableId}/records (write) creates one or a batch; GET /records/{id} (read) retrieves a record plus its inbound and outbound links; PATCH /records/{id} (write) merges changes (send only what changes; null clears a field); DELETE /records/{id} (write) soft-deletes to the Trash; POST /records/{id}/restore (write) brings it back.
  • AuditGET /audit (read): the workspace audit log, newest first, including changes made through the API.
  • WebhooksGET /webhooks (schema) lists subscriptions with their secret and health; POST /webhooks (schema) creates one; PATCH /webhooks/{id} (schema) edits the URL, events, table scope, or pauses it with "enabled": false; POST /webhooks/{id}/rotate-secret (schema) issues a fresh signing secret; DELETE /webhooks/{id} (schema) removes it.

List, filter, and batch records

Listing records is the workhorse read. GET /tables/{tableId}/records takes pageSize (1–200, default 50) and offset; each response carries total and the next offset (null at the end). Add q to search the display name, and sort to order by createdAt, updatedAt, or displayName (prefix - for descending; the default is -updatedAt).

The filter parameter is a URL-encoded JSON array of {field, op, value} conditions, combined with match=all (default) or match=any. Operators: eq, neq, contains, not_contains, empty, not_empty, gt, gte, lt, lte; target the record name with the special field __displayName. Field-value filters scan up to 5,000 rows per request, and the response sets scannedCap when it hits that boundary.

Creating supports batches: send one record object, or { "records": [ … ] } for up to 50 at once. Pass an Idempotency-Key header and RowFold replays the first response for 24 hours if the same key and body arrive again — so a retried create never duplicates a record.

Sending dates through the API

Two different kinds of time come through the API, and mixing them up is the most common integration bug.

A record date is plain wall-clock text with no zone attached: YYYY-MM-DD, or YYYY-MM-DDTHH:mm when the field carries a time. Each field’s includeTime flag in GET /api/v1/tables tells you which shape to send. The wall these clocks are on is your workspace’s time zone — a shift at 9:00 AM is 9:00 AM at the site, whoever reads it.

A timestamp RowFold generatescreatedAtUtc, updatedAtUtc, postedAt — is a real instant in UTC, in full ISO 8601. Convert those for display; never convert a record date.

Writes are read tolerantly and then normalised. Send 2026-05-18 10:00:00 and it is stored — and returned — as 2026-05-18T10:00. So what you read back may not be byte-identical to what you sent: compare dates by parsing them, never by string equality.

Two things are refused with a 400 naming the field, rather than stored:

  • Text that isn’t a date. Storing it would leave a column no date filter can ever match, and you’d find out weeks later.
  • A date carrying a zone2026-05-18T09:00Z, 2026-05-18T09:00+01:00. An offset turns the value into an instant, and turning an instant back into wall-clock time is a guess RowFold won’t make on your behalf. Convert to the workspace’s local time and send the bare form.

Parse tolerantly on the way out, too: turning Include a time off in the app never strips times already stored, so a date-only column can still hand you a timed value from before the change.

Receive webhook events

A webhook subscription POSTs each matching record change to your URL. Subscribe to any of record.created, record.updated, record.deleted, and record.restored, for all tables or a single one. Each delivery carries an X-RowFold-Event header, a unique X-RowFold-Delivery id, and an X-RowFold-Signature; update payloads include the record's previous values so your receiver can diff.

Verify every delivery. The signature header reads t=<timestamp>,v1=<hex>. Recompute an HMAC-SHA256 over timestamp + "." + rawBody using the hook's secret, compare it to v1 in constant time, and reject timestamps older than five minutes to stop replays — that proves the POST really came from RowFold. Answer with any 2xx within 10 seconds.

Deliveries run on a durable job queue that survives restarts and make up to 3 attempts — immediately, after ~30 seconds, then after ~5 minutes. A 4xx answer (other than 408/429) means your endpoint refused the payload and is not retried; a hook that fails 20 times in a row pauses itself. Every attempt — HTTP status, duration, error, and whether a retry is coming — is recorded under Recent webhook deliveries on the Developers page and kept for 30 days. Rotate the signing secret there (or with POST /webhooks/{id}/rotate-secret) and update your receiver before the next event fires; re-enabling a paused hook clears its failure counter.

The webhook on this page is the third one — RowFold calling you. The other two are ways of getting data in.
Automate & connect

Connect RowFold to Zapier

RowFold works with Zapier in both directions today, using webhooks and the REST API rather than an app you install from Zapier's directory. This article is the whole recipe: push record changes out to a Zap, let a Zap file records into a table, let a Zap fire an automation, and read or write anything through the API. The same four routes work for Make, n8n, Power Automate and anything else that speaks HTTP.

Is there a RowFold app in Zapier's directory?

Not yet. A RowFold Zapier app exists and is built, but it is private while RowFold is pre-launch — Zapier requires a publicly launched product, a live user base and a set of Zap templates before an app can be listed, so searching Zapier for “RowFold” finds nothing today. We would rather say that plainly than let you hunt for it.

None of that blocks you, and this is the part worth knowing: a listed app would be a convenience, not a capability. Everything a RowFold Zap needs — record changes out, records in, automations fired, full read and write — already ships as ordinary HTTP, and you wire it with Zapier's own Webhooks by Zapier app. The four recipes below are complete. When a directory listing does land, Zaps you build now keep working; the app would just save you pasting URLs.

One thing to check first: Zapier has long packaged Webhooks by Zapier as a premium app, so confirm your Zapier plan includes it before you start building.

1 · Send record changes out to a Zap

This is the common one — “when a deal is won, do something in another tool.”

  1. In Zapier, make a Zap with the trigger Webhooks by Zapier → Catch Hook. Copy the custom webhook URL it gives you.
  2. In RowFold, go to Developers → Webhooks and add a webhook. Paste the Zapier URL as the Payload URL, name it something you will recognise later, and pick the table.
  3. Tick the events you want: created, updated, deleted, restored, posted, unposted. Leave Payload on Full record so the Zap receives the values, not just ids.
  4. Open Filter & custom headers if you only want some changes — only when status equals Won. Filtering here rather than in the Zap means the Zap does not burn a task on every other change.
  5. Save, change a record, and Zapier's “Test trigger” will find the sample.

Deliveries are signed with X-RowFold-Signature and retried six times with backoff (immediate, ~1s, ~4s, ~30s, ~5min, ~30min). Every attempt is listed under Recent webhook deliveries on the same page, and any delivery still holding its payload can be re-sent by hand — so “did that reach Zapier?” is always answerable without leaving RowFold.

2 · Let a Zap create records in a table

The reverse direction, for when the record should just appear — a lead from a form tool, a row from a spreadsheet, an order from a store.

  1. In RowFold, open the table, then Channels → Webhook In (or go straight to Webhook In from the table's view bar) and create an endpoint. You get a URL.
  2. That page publishes the exact JSON format, using this table's own field keys. Read it — it is the contract, and it is per-table.
  3. In Zapier, add the action Webhooks by Zapier → POST. Set the URL to your endpoint, Payload Type to json, and map the fields.

The endpoint answers synchronously: 201 with the new record's id, or 400 naming each field it refused. That matters in Zapier, because a bad mapping then shows up as a red failed task with the reason in it, rather than as a Zap that reports success while nothing arrives.

Records created this way go through the same save path as any other, so AutoNumber values are stamped, automations fire and outgoing webhooks deliver — which is also how you get an accidental loop, so see the pitfalls below.

3 · Let a Zap fire an automation

Use this when the incoming payload is somebody else's shape and you want RowFold to decide what to do with it, rather than it becoming one record of one table.

  1. Build an automation with the trigger A webhook is received. Saving it mints an inbound URL, shown in the editor with a copy button.
  2. POST to it from Zapier the same way as above.
  3. Every value in the payload is available to the steps as {{webhook.<path>}} — nested values use dots, array items use numbers, and the raw body rides along as {{webhook.body}}.

The difference from Webhook In is worth holding onto. Webhook In publishes a format and you conform to it; an automation webhook takes whatever shape the sender dictates and the automation adapts. A post that fails the automation's conditions is logged as a Skipped run, so “why didn't it fire?” stays answerable from Run history. This one answers 202 immediately and runs the steps in the background.

4 · Read and write anything: the REST API

When a Zap needs to look something up, update an existing record, or work across tables, use the API directly.

  1. In Developers → API clients, create a client with the scopes you need. The secret is shown once.
  2. Exchange it for a token: POST /api/v1/auth/token with {"clientId": "rfc_…", "clientSecret": "rfsk_…"}. Note the response is camelCase, not the RFC 6749 spelling: accessToken, tokenType, expiresIn, scope.
  3. Call the API from Webhooks by Zapier → Custom Request with the header Authorization: Bearer <accessToken>.

The access token lasts one hour, which is the honest catch with this route inside Zapier: a step holding a pasted token will start failing the same day. For a Zap, prefer the webhook recipes above and keep the API for a step that fetches its own token first, or for your own code. The full reference is at /Developers/Docs, and the OpenAPI document at /api/v1/openapi.json feeds Postman and code generators without credentials.

Make, n8n and everything else

None of the four recipes is Zapier-specific — they are all just HTTP. In Make, a Custom webhook trigger stands in for Catch Hook and an HTTP module for the POST. In n8n, a Webhook node receives and an HTTP Request node writes back. Power Automate, Pipedream, Retool and a cron job running curl all work the same way.

If a tool can receive an HTTP POST, recipe 1 reaches it. If it can send one, recipes 2 and 3 reach RowFold.

Automate & connect

Public forms & Email In

Let the outside world file records: shareable forms with conditional questions, and email addresses that turn messages into records.

Create a form

Open a table's field editor and press Forms. A new form starts with every fillable field included — untick what you don't want, drag to reorder, mark answers required, and override labels or add help text per field. The share link (/f/…) works for anyone, no account needed; submissions become records instantly.

Ask only what's relevant

Any field can be conditional: only ask this when an earlier Select, Multi-select, or Yes/No answer matches — "which browser?" only when Type is Bug. Conditions are enforced on the server too: a hidden question can't block submission and its answer is discarded if a clever visitor forces one in.

Submissions are first-class records

Auto number fields stamp themselves (instant ticket numbers), automations fire (email the team, set a status), and the record-name mapping decides what shows in the grid. Optionally email every submission somewhere with Email each submission to. Forms are protected by rate limiting and a bot trap; Relation fields are deliberately not offered — a public picker would expose your records' names.

Email In: an address that files records for you

Any table can have its own email address. On the table's Email In page, create a mailbox and RowFold hands you a ready-made address like t-…@in.rowfold.comthere is nothing to set up on your side: no DNS, no mail server, no forwarding rules required to make the address work. It receives mail the moment it exists.

A new mailbox already works: the sender goes into your first Email field, the message into your first Long text field, and files into your first Attachment field. The subject always names the record. Auto numbers stamp themselves and automations fire exactly as if the record were typed in.

The classic move: forward your real support address (support@yourcompany.com) at the RowFold address, and your support queue lives in a table — numbered, filterable, automated, with AI triage one question away.

Choosing what lands where

The mapping list is the heart of the page: each row is one source and one field, and you can add as many as you like. The sources are the parts of an email — Subject, Message (quoted reply chains, "On … wrote:" trails and signature blocks stripped so the record holds just what was said) or Message with quoted history, the sender's email, name or domain, Sent to, Cc, the received date, any named email header (for senders that put order ids and references there), and attached files.

Two do more than copy text. A fixed value writes the same thing on every message — "Source = Email", "Priority = Normal" — so a mailbox can feed a queue that already has conventions. And Match sender to a record links the email to the contact, company or customer it belongs to: pick a Relation field, say which field on the other table holds their address, and RowFold links the matching record — creating it if they're new, so every email quietly builds your contact list.

Some fields can't take a value from email, and the picker says so instead of letting you find out later: anything RowFold works out itself (Auto number, Formula, Lookup, Rollup), and any field a lifecycle or approval policy governs — those decide their own value, and an email must not talk past them. A saved mapping is checked again every time mail arrives, so if a field is later retyped the mapping stops running and the page tells you why rather than writing something wrong.

The panel at the bottom shows what the last email you received actually contained, so you can pick sources against real values rather than guessing.

Find your table's address

Open any table and look next to + New record: the ✉ Email-in button shows the table's address with one-click copy, or — if no mailbox exists yet — takes admins straight to the setup page. The empty state of a new table shows the address too, so "how do records get in here?" answers itself.

Admins reach the full editor from the table's field editor via Email In (the Forms page links across to it too): change the mapping, choose who is alerted when mail arrives, pause an address, or create several mailboxes for one table.

Automate & connect

How bookings work

When somebody books time with you, RowFold writes a row in one of your tables. Everything else follows from that: the booking is on your scheduler because it has a date, in your reports because it is a record, and available to automations, views, exports and the API without any of that being built for bookings specifically. This article covers the whole round trip — the public page people book on, where the free slots come from, what happens the moment one lands, and how you change or cancel one afterwards.

A booking is a row

Everything else here follows from one fact: when somebody books time with you, RowFold writes a row in one of your tables. Not into a separate booking system you later have to reconcile. A row, in a table you can see, with columns you chose.

That is why a booking arrives already useful. It is on your scheduler because it has a date. It is in your reports because it is a record. It can trigger an automation, appear in a filtered view, go out in a CSV, or be read through the API — and none of that had to be built for bookings. It works because a booking is not special.

Two doors onto the same table

There are two surfaces, and they are opposite ends of one thing.

The booking page faces outward. It lives at a link you can send anyone, it needs no account, and it writes one booking at a time. Somebody picks a slot and a row appears.

The scheduler faces inward. It reads the whole day back and lets you run it: a column per staff member, drag to move an appointment, check somebody in, fit the walk-in standing at the counter.

Same table. Same rows. If you already have a booking page, the scheduler reads its settings and arrives configured, because that page has already answered the questions the scheduler needs to ask.

What you need before you start

One table for the bookings, with a date field that records a time of day. That is the only hard requirement.

Beyond that, the more you link, the more you get back. In practice the link to the people who deliver the work is the one that pays off most: it gives you a column each on the scheduler and lets the page offer a choice of who. A link to your services gives you durations and prices. A link to your clients gives you a history you can open from any booking. A status column lets you check people in.

None of it is mandatory. Leave the staff link off and the scheduler shows you a day instead of a column per person. Nothing breaks; it just does less.

Where the free slots come from

Availability is data, not a settings screen. There is an Availability table, and each row is a sentence: this person, this weekday, from this time to this time. So you edit opening hours in a grid, paste a whole season of them in from a spreadsheet, or have an automation close the shop — all the things you can already do to a table.

Two kinds of row. A Working hours row adds time. A Time off row takes it away, and it can name a date, or a date range, or nobody at all — leave the person blank and it closes the whole business for a bank holiday.

The page then subtracts the practical things, roughly in this order. It refuses slots that overlap a booking you already have. It adds any gap you want before and after an appointment, so a plumber gets travel time. It refuses anything sooner than your minimum notice, and anything further out than your booking window. What is left is what a visitor is offered.

If they have not asked for a particular person, the page picks whoever has the lightest recent load rather than always the first name on the list.

The moment somebody books

A record lands in your table. That is the real event; everything else is a consequence of it.

They get a confirmation email carrying a link that is theirs. From it they can move the booking to another free slot, cancel it, or add it to their own calendar. You do not have to do anything for any of that.

If you set a reminder, RowFold sends one that many hours before. Your automations fire the same way they would for any new record, so a text message, a Slack post or a row in another table is a rule you write once.

When you move or cancel one

Drag an appointment to a new time on the scheduler, or use Reschedule to send it to another day. Drop it in another person's column and it is reassigned in the same movement.

Two things happen here that are easy to miss.

The booking keeps the length it was booked with. If a haircut was 90 minutes when it was booked, it stays 90 minutes when it moves, even if you have since changed that service to two hours. Bookings you have already taken do not shift under you.

And the customer is told. A moved booking sends an email showing the old time struck through above the new one, because the first thing most people think is “was that always when it was?” A cancellation says who cancelled it. Both report back who was actually told — and where there was nobody to tell, because the booking carries no email, the scheduler says so rather than implying a message went out.

Cancel booking sets your own cancelled status, whatever you happen to call it, so the booking stays visible as a cancellation rather than disappearing. If your table has no such status the record goes to Trash, where you can get it back. Nothing here deletes anything for good.

Bookings that repeat

A repeating booking is stored once, as a rule, and drawn for whatever period you are looking at. “Every Tuesday, forever” is literally true: no hidden end date, no cap on how many it will generate.

Move or cancel one and you are asked how far the change should reach — just this one, this and every later one, or the whole repeat. Most of the time you want the middle one. It leaves everything before today exactly as it was. You are only asked when it could matter; a one-off booking just moves.

Classes, and anything shared

Twenty people at one yoga class is twenty rows at the same time with the same instructor. On an ordinary appointment table that reads as nineteen double-bookings.

Give the view a capacity — a number saying how many the session takes — and it counts seats instead. Bookings sharing a slot stop being flagged, and only real problems remain: a class with more people in it than it holds, and one instructor booked into two different things at once.

Booked by the night

Cottages, rooms, boats and hire cars are booked in days, not hours. Give the view a start date and an end date that carry no time of day, and it becomes a chart with a row per unit and a column per day.

The end date is the day the unit comes free again, not the last night. A cottage booked the 1st to the 8th is available on the 8th, and the next guest's bar starts in that same column. That is what every hotel means by check-out, and reading it the other way would report most of a busy month as double-booked.

What it does not do yet

No deposits or payments at the point of booking. The settings exist in the data, but nothing reads them.

No two-way sync with Google Calendar or Outlook. A visitor can download a calendar file for their own diary, and that is one-way.

Booked by the night

A cottage, a room, a boat or a pitch is not booked at a time, it is booked for a run of nights. Set a booking page's mode to Stays and the funnel changes: instead of a list of times, a guest sees two months of nights and drags a range across them.

The departure day is free again. Somebody leaving on the 8th and somebody arriving on the 8th is a changeover, not a clash, so the 8th is still on sale — which is the same rule the Scheduler's stays chart draws with, and the same rule Airbnb and every other platform uses. It is worth knowing because it is the difference between selling that night and losing it.

The two date fields are an arrival and a departure, and neither may record a time of day. That is not a limitation, it is what makes the booking land on the tape chart: a stay whose arrival carried an hour would drop out of the one view built to show it.

Rates, minimum stays and check-in times

Price is a number on the unit — the cottage, not a service — because in this mode the unit is the thing being bought. The page quotes rate × nights. Leave it unset and the page quotes nothing at all, which is right for enquire-only and much better than a confident £0 on a holiday let.

Only a real number field can hold it. A Lookup would re-read its source every time the page rendered, so raising your rate would silently re-price stays that were already taken and paid for.

Minimum stay is the setting most hosts reach for first — it is what stops a single night wrecking a weekend. A night that cannot fit your minimum is not offered as an arrival at all, though it is still sellable as part of a longer stay arriving earlier. Check-in and check-out times are printed on the page, the confirmation and the calendar invite; they change nothing about availability, because the whole arrival day and the whole departure day belong to that booking either way.

Automate & connect

Connectors: bring in a tool you already use

Connect an account you already have — Airtable first among them — and import its data into RowFold as real tables, fields and records.

Connect an account

Open Integrations, find the tool in the gallery and press Connect. You're sent to that vendor to sign in and approve access, and returned with the connection listed and labelled with the account it belongs to. Nothing is written back to the tool you connected — the access asked for is read-only.

A tile marked Needs setup isn't broken and isn't something you can fix: it means this RowFold deployment hasn't registered an application with that vendor yet, so there's no Connect button to press.

Which tools connect with one click

Airtable, Slack, Notion, Google Sheets, Google Drive, GitHub, Salesforce and Xero connect with nothing but your own account — press Connect, approve on their side, done.

That is eight. Another sixteen ask for an API key you generate in the tool itself, and those work today as well — paste the key and you're connected.

The remainder show Needs setup. That isn't a fault in the connector and isn't something you can clear from your side: it means this RowFold deployment hasn't yet registered an application with that vendor. They are all built, and they light up for everyone at once when the registration lands.

The integrations page: a row of category filters above a grid of connector tiles, each naming a tool and what it brings across, with a button to connect an account.
Filter by category to find yours. Anything not listed can still be reached through the API or an automation webhook.

Import from Airtable

On a connected account, press Import data. RowFold lists the bases that account can see and each gets its own Import button. Pick one and the import runs in the background — tables appear as it lands.

If a base you expected isn't listed, check what you granted on Airtable's own consent screen: access is given per base, not to everything at once.

Watching it run

Progress shows live on the connection itself: what the run is doing right now (“Importing Orders…”) and how many records have landed, updating as it goes, then finally ok, partial or failed with a record count and a timestamp. You can leave the page — the import runs in the background regardless.

partial means it finished and recorded warnings — usually fields that couldn't come across as themselves, or a page of records the vendor stopped serving. The first few are listed with a count of the rest, and running the import again picks up what a partial run missed.

What comes across, and what doesn't

Most field types map straight over: text, long text, email, URL, phone, number, currency, percent, rating, checkbox, dates (including their times), and both kinds of select with their options. Airtable's primary field becomes both the record's name and its first field. Two things that used to arrive as text are real now: links between tables are rebuilt as RowFold relations, matched on Airtable's own record ids, and attachments are downloaded into RowFold's own storage during the import — which matters, because the file links Airtable hands out expire within hours.

Two things still arrive as text, each with a warning saying so:

  • Formulas, rollups and lookups, as the value they had computed to — the expression itself doesn't travel. Rebuild the ones you need in RowFold's own formula and rollup editors; the warnings list every column that needs it.
  • Collaborators, as names rather than RowFold people.

An import brings across up to 100,000 records per table and says so plainly if a table was larger.

Running it again, and keeping it in sync

Running the same base again updates what it finds instead of duplicating it: records are matched on Airtable's own ids, new ones are created, changed ones refreshed. That is also what the schedule does — after a completed import, press Keep in sync on the run and pick hourly or daily, and the base stays mirrored while your team moves over.

The mirror's rules, plainly: the source wins on the columns the import mapped (including clearing a cell that was cleared there); columns you add in RowFold are never touched; posted records are sealed against it; attachments are copied when a record first arrives and left alone after that; and deletions never propagate — a record deleted in Airtable simply stops updating here. Stop the sync any time; the tables are yours either way.

To bring a CSV or a spreadsheet in instead, use the import wizard, which detects relations between files and can update an existing table by a match column.

Automate & connect

Text messages

RowFold can text people — notifications worth interrupting somebody for, booking confirmations and reminders, and a Send SMS step in any automation — with the consent and quiet-hours rules that come with sending on a shared number.

When RowFold texts you

Text is the one channel here that can wake somebody up, so it's deliberately not everything you allowed by email. Only the kinds worth interrupting someone for go by text — being assigned something does; a record you watch changing doesn't.

It's off until you turn it on, and having a phone number on file is not taken as agreement: a number is contact detail, consent is a separate switch in your own settings.

None of these can be routed around, including from an automation — texts go out on a sender identity shared across RowFold.

Quiet hours

By default RowFold sends no texts between 9pm and 8am in the recipient's own local time, and this is on unless it's turned off. The sender is usually a background job at whatever hour it happened to run, rather than a person who'd have thought twice — so the window is enforced centrally and a message that would land inside it waits.

Texting from an automation

Automations have a Send SMS step, so a text can be part of any workflow: a booking confirmed, a job dispatched, an approval waiting. It goes through the same rules as everything else here — opt-outs, quiet hours and the spend ceiling all still apply, and there's no way to route around them.

Opting out

Every message says how to stop. Replying STOP stops them immediately; START resumes them.

Opt-outs are held against the number itself, so somebody who stops is stopped everywhere at once rather than having to repeat it. That's deliberate: texts go out on a sender identity shared across RowFold, so one person's opt-out has to mean something globally.

What it costs

Texts are metered in segments rather than messages. A plain message fits 160 characters in one segment, but a single emoji or curly quote drops that to 70 — so a "short" message can quietly cost three times what it looks like.

There's a monthly ceiling, and the log at Settings — SMS log shows what went out, to whom, how many segments it took and whether it was delivered.

Automate & connect

Email wording & the email log

Write the emails your workspace sends, see them rendered before they go, and check afterwards whether they arrived.

Word the emails your workspace sends

Settings → Email wording lists every email RowFold sends on your behalf — form acknowledgements and replies to customers, and submission alerts, watched-record changes, mentions and approvals to your own team. Open one and write it in the editor: bold, italic, links, bullets, numbered lists, headings, quotes, a button and a divider. Leave one alone and RowFold's own wording is what goes out, so you only write the ones you care about.

Drag a field from the palette to drop a merge field into the text — it shows as a chip reading the field's name, and fills in with that record's value when the email actually sends. Merge fields work in the subject line too.

See it before it sends

Beside the editor, the same email renders twice from the same real record in your workspace: Yours and RowFold's default. Flip between them and the only thing that changes is your wording. The preview says which record it drew from, so you can tell whether a merge field is actually resolving rather than guessing.

It renders the whole email, including the parts you can't edit — the table of answers on an acknowledgement, the approve and decline buttons on an approval. That's deliberate: your wording is the opening of the message, and the parts that let somebody act on it always survive.

Every email, in and out

Settings → Email log is the record of what actually happened: everything your workspace sent, and everything that arrived at your Email In addresses. Search by subject or address, filter to sent or received, or switch to Problems only — which is the view worth opening when somebody says they never got something. Click any row to see the message exactly as it was sent.

Received mail that was dropped is logged too, with the reason. An out-of-office reply that never became a record is otherwise indistinguishable from an email that never arrived at all.

What “delivered” and “opened” really mean

Delivered means the receiving mail server accepted the message. It does not tell you whether it landed in an inbox or a spam folder, and it does not mean anybody read it.

Opened is counted by a tracking pixel, so treat it as evidence rather than proof: a mail client that blocks images never reports one, and Apple's Mail Privacy Protection loads it whether or not a human looked. Replies you send a customer from the inbox carry no pixel at all — a tracked support email is a bad look — so those rows never show an open, and that is not a fault.

Automate & connect

Connect an AI agent (MCP)

RowFold speaks MCP — the open protocol AI assistants use to reach tools — so Claude Code, Claude Desktop, Cursor and other MCP clients can work your workspace directly: exact filtered totals, search, record history, comments, attachments, and (when a connection allows it) creating, updating and trashing records. A connection acts as one member of your workspace and sees exactly what that person sees. This article covers creating a connection, wiring it into your assistant, what the agent can and cannot do, and the security model.

What an MCP connection is

MCP (Model Context Protocol) is the open standard AI assistants use to call external tools. RowFold serves it at /mcp, and the read tools it offers are the same ones RowFold's own Ask panel uses — not a separate, simpler API. That matters for one reason above all: totals are computed in the database. When your assistant asks for “the total value of open deals”, it gets an exact filtered aggregate, not a guess summed from a page of rows.

Connections are read-only unless you say otherwise. Ticking allow record writes at creation adds three more tools — create, update, and trash — which run the very same checks as RowFold's own confirmed AI edits: field permissions, the posting seal, and lifecycle rules, applied per record, with refusals skipped and the reason named. Every write tool has a dry-run preview, and updates hand back each record's previous values so the agent can undo its own change.

Create a connection

Go to Developers → AI agents (MCP) (workspace admins only). Give the connection a name — name it after the tool and person it serves, like “Dana's Cursor” — and choose which member it acts as. The agent will see exactly what that person sees: their tables, their fields, nothing hidden from them, and admin-only tools only if they are an admin.

Tick allow record writes if this agent should be able to create, update and trash records. Leave it off for a purely analytical connection — the scope widens the toolbox, never the permissions, so even a write-enabled agent can only ever change what its acts-as member could change by hand.

Creating it shows the key once. RowFold stores only a hash, so copy it before leaving the page — a lost key means revoking and creating a fresh one, which takes seconds.

Wire it into your assistant

In Claude Code, one command does it:

claude mcp add rowfold --transport http https://www.rowfold.com/mcp --header "Authorization: Bearer rfmcp_…"

In Claude Desktop, Cursor and most other MCP clients, add this to the app's MCP settings JSON:

{
  "mcpServers": {
    "rowfold": {
      "type": "http",
      "url": "https://www.rowfold.com/mcp",
      "headers": { "Authorization": "Bearer rfmcp_…" }
    }
  }
}

The create step on the Developers page prints both of these with your real host and key filled in, ready to paste. Once connected, just talk: “what's in my RowFold workspace?”, “total open pipeline by owner”, “who changed the price on the Meridian deal?”.

What the agent can do

Nineteen read tools: list tables, read a table's schema, query records (filtered and sorted in the database, including filters that travel a link — “deals whose company's region is EMEA”), keyword search, open one record with its links, exact aggregates (count, sum, average, min, max — filtered and grouped), find records near a place, find when somebody is free (working hours, existing bookings and connected calendars, naming any calendar it could not reach rather than presenting the gaps as settled), read the change history, read comments, read automation runs (workspace admins only, same bar as the run log itself), read text attachments, and prepare a CSV export.

On a write-enabled connection, four more: create records (up to 40 per call in one table, with relation links inside the batch or to existing records), update records (per-record skips with reasons; the result carries each record's previous values, and posting those back is the undo), and trash records (the restorable soft delete — nothing is destroyed). Each takes a dry_run flag that reports exactly what would happen without writing, and real writes appear in the audit trail as MCP · connection (as person) and fire automations like any other save.

Two honest edges. Relative date filters (“last 30 days”) resolve in the workspace's timezone, the same as everywhere else in RowFold. And a CSV export hands back a short-lived download link that only works in a browser signed in as the acts-as person — the export re-checks their live permissions at click time, exactly like an export from Ask.

The security model

The key is the credential: anyone holding it reads this workspace as the acts-as member, so treat it like a password. Everything else follows from the acts-as design:

  • Permissions are the person's own. Hidden fields stay hidden, no-access tables stay invisible, and there is no separate “integration permissions” model to configure or get wrong.
  • Revoke on the Developers page. The key stops answering within a minute everywhere. Removing the member from the workspace kills their connections too.
  • Requests are rate-limited per key, and CSV exports write to the workspace audit trail like any other export.
  • Trial and billing apply. A workspace whose trial has ended answers MCP requests with a payment-required error, the same rule as the REST API.
The connection acts as a person, so every permission already set up in RowFold applies — there is no second set of rules to keep in step.
Automate & connect

Syncing with Airbnb, Vrbo and Booking.com

Stop two calendars selling the same night. RowFold reads each listing's calendar link so nights booked elsewhere are blocked here, and publishes one of its own so those platforms block nights booked here.

Two links, pointing opposite ways

Airbnb, Vrbo and Booking.com all work the same way: each listing has a calendar link you can export, and a box where you can import somebody else's. There is no API a host with four cottages can reach — the pair of links is the integration.

So there are two jobs, and they are separate. Paste their export link into RowFold and the nights it holds stop being sellable here. Give them RowFold's calendar link and the nights you have taken here stop being sellable there. Do only the first and your own booking page is safe while Airbnb keeps double-selling.

Reading theirs

On Airbnb: Listing → Availability → Sync calendars → Export calendar. Vrbo and Booking.com have the same thing under a different name. Copy that link and paste it on the Calendars page for the table your bookings live in, choosing which unit it belongs to.

Treat the link like a password. Anyone holding it can read every arrival and departure on that listing, and on some platforms the guest's name with them — which is why the page is admin-only and shows only the address's host once saved.

A calendar that names no unit closes the whole table for the dates it holds. That is the right shape for bank holidays or a refurbishment, and the wrong one for a single cottage's bookings.

Sending yours

Publish a calendar view of your bookings table, tick Calendar feed on the share, and paste that .ics address into the platform's import box.

The share carries a frozen list of published columns, so a column you add later is never quietly exposed — and because the table is booked by the night, the checkout day is published as the exclusive end the platforms expect. That detail matters: read the other way, every one of your bookings would block an extra night on the changeover day.

When a sync stops working

Refreshes run about once an hour in each direction, and the platforms set their own pace — treat this as protection against double-booking rather than as instant. Nothing is fetched while somebody is looking at your booking page, so a slow platform never slows your page down.

If a link stops working, the nights it last knew about stay blocked — losing a feed must never quietly put sold nights back on sale. After a full day without a successful sync RowFold stops offering that unit publicly and says so on the page, rather than risk selling a night it can no longer vouch for. The Calendars page shows when each one last succeeded and what went wrong.

Repeating events in an imported calendar are read once only, and the page says how many it found. No rental platform emits them; guessing at the repeats would block dates nobody ever booked.

Governance
Governance

Record lifecycle: the states a record moves through

Give a table a state machine — which states exist, which moves between them are legal, what each state requires or locks, and what each state MEANS — written through an ordinary Select field, so every view, board, report and automation reads the state as a normal value.

Opt in, one table at a time

A lifecycle is added from the Lifecycle tab beside the field editor, the same place posting rules live — and it starts from the status field the table already has. The field's own options become the stages, listed with live record counts and a guessed meaning each; nothing is added to the dropdown, nothing is renamed, and no record changes. A sensible starting set of moves is generated from the meanings (step forward or back, cancel from anywhere, finish from the last stage, reopen after a failure), and every one of them is an editable checkbox afterwards.

Templates exist only for a table with no usable status field: they fill an empty Select — or add a fresh Status field for you — with their own stages. A field that already has options is never templated, so a template can't bolt its vocabulary onto a dropdown people already use.

Tables without a lifecycle behave exactly as they always have. Switching one off later keeps history legible rather than erasing it: past entries still name the states they moved through, because history references states by name.

The two look alike and answer different questions: where a record is in its life, against who still has to say yes.

The state is an ordinary field

A record's state is the value of a Select field you nominate — there is no hidden parallel status living somewhere else. This is the same decision posting rules made, for the same reason: "everything sitting in Qualified" is a board column, a saved view, a filter, a rollup and an automation trigger the moment it is an ordinary field value.

Every state you define must exist as an option on that field. The editor creates the missing ones, and the field editor then refuses to delete an option a live lifecycle uses.

The reverse can also happen: live records holding a value that isn't a stage — set before the lifecycle existed, or an option you chose to leave out. The editor lists them under Outside the lifecycle with live counts: bring a value in with one click, or open its records from the count and move them. Until then those records are exempt from every rule, and the page says so rather than leaving them silently unconstrained. Records with a blank status are reported the same way.

Legal moves, and what each state demands

This is the part a plain Select cannot do. For each state you set:

  • Which states it may move to. A move you haven't allowed is refused when someone tries it, rather than quietly recorded.
  • Required fields — what must be filled in before a record is allowed to arrive here.
  • Locked fields — what stops being editable once it does.
  • Whether a record in this state may be deleted.

What a state MEANS

Every state is mapped to one of four categories: Initial (not yet committed), Active (committed and running), Terminal · success (ended, having achieved its purpose) and Terminal · failure (ended without it).

That mapping is what lets reporting — and anything built later — reason about a state set it has never seen. A workshop's Issued, a sales team's Qualified and a claims desk's Under review are all Active, so "show me what's still running" is answerable without teaching each feature your vocabulary.

Governance

Approvals: asking, deciding, and the queue

Ask anyone to approve a record, and answer the asks aimed at you — from the Approvals queue, the notification bell, the record's Posting panel, or straight from the email. A decision can write a Select value on the record, so everything downstream reacts to it like an ordinary edit.

Ask anyone to approve anything

Open a record and use its Posting panel to ask someone for an approval: pick a person, add a note saying why, and optionally a due window. The picker offers every member of the record's workspace, whatever their role — a read-only manager signing things off is a perfectly real arrangement.

An ask can also carry a field write: choose a Select field and the values to write on approve and on reject, and the decision moves the record's own status the moment it lands. This works on any table, with no posting rules configured — and if you work alone, you can be your own approver.

Asking needs only view access to the record. Asking is the point — you are requesting a change, not making one.

A stage only opens once the one before it closes, so nobody is asked to approve something that may still change underneath them.

Where you decide

An ask reaches you in four places, and they all do exactly the same thing:

  • The Approvals queue — the rail entry with the live count badge.
  • The notification bell — Approve and Decline sit right in the notification, so a routine yes never needs a page.
  • The record itself — the Posting panel on the record page and in the peek drawer shows every ask with its state, and yours with buttons.
  • The email — see below; you don't even need to be signed in.

The queue

Approvals in the sidebar gathers every ask across every workspace into three tabs: Waiting on you, You asked, and Done. Overdue rows are flagged, each row names the workspace, table and stage, and the record's name opens a peek so you can read what you're approving without leaving the list.

On the pending tab the keyboard does the work: j and k move, A approves, R declines, O peeks at the record.

Decide from the email

Approval emails carry Review & approve and Decline buttons. Either one opens a small confirmation page showing what you're deciding; pressing the button on that page is what decides. Being asked is the authorization — the link is signed to exactly one ask and one approver, so no login is required.

Two deliberate properties: links expire after 14 days, so a forwarded old email can't decide anything; and merely opening the link never decides — corporate security scanners follow every URL in every email, and an approval that decided on click would be decided by robots. Only the explicit press on the confirmation page counts.

A no needs a reason

Approving can be one click. Declining always asks you to say why — the reason matters most when the answer is no, and it travels back to the requester and onto the record. On a table with posting rules, a rejection drops the record to Changes requested with your note attached, so the person fixing it knows what to fix.

Decisions are ordinary edits downstream

When a decision writes a Select value, it is written through the normal save path — so views regroup, boards move the card, reports recount, and automations and webhooks fire exactly as if a person had edited the field. Approval is a way of asking for a change, not a parallel universe of state.

And it is honest about failure: if the decision was recorded but the field write could not be applied, the ask says so rather than letting the workflow look further along than it is.

Keyboard shortcuts

j / k Move down / up the pending list Approvals queue
A Approve the highlighted ask Approvals queue
R Decline the highlighted ask (a reason is required) Approvals queue
O Peek at the record behind the ask Approvals queue
Governance

Posting rules: stages, quorums and the approval status field

Give a table posting rules and its records earn their way to Posted through ordered approval stages — each with its own approvers, quorum and clock — with the whole journey written through a real Select field, so views, reports and automations see approval state as an ordinary value.

One policy per table

A table has at most one set of posting rules, built by an Admin from Posting rules next to the field editor. On tables without one, none of this chrome exists — no panel, no approval status, nothing to learn. Add a policy and every record in the table gains a journey: Draft → each stage in order → Approved → Posted.

The approval status lives in a real field

Every step of the journey is written into a Select field you pick — or, if you don't pick one, a field called Approval status is created for you. The builder adds the values it needs as real options: Draft, an Awaiting … value per stage, Changes requested, Approved, Posted.

This is the design decision that makes everything else free: "everything sitting with Finance" is a saved view, a board column, a report group and an automation trigger, because approval state is an ordinary field value — not a parallel system bolted on beside your data. By default the field only changes through the flow itself; see Why you can't edit the approval status field.

Stages: who is asked, and how many must agree

Each stage names its approvers one of three ways: picked people, a People field on the record (the account manager approves their own account's records — routing no fixed list can do), or a role (any workspace Admin). Its quorum is everyone, any one, or N of M.

Within a stage, approvers are asked in parallel. Between stages the flow is strictly sequential: the next stage's people aren't asked until the previous quorum clears, so nobody ever sees an ask that might not matter. The moment a quorum is met the record advances — same instant, same transaction, no sweep to wait for.

Stages that only sometimes run

A stage can carry conditions on the record — Amount greater than 5000 pulls the CFO stage into the journey only when it should be there. Conditions are checked when the stage would open; a stage that doesn't match is skipped, and the skip is recorded so the trail never shows a silent gap.

Submitting, and what a rejection does

Submit for approval on the record opens stage one and fans out its asks. Submitting needs only view access — asking is the point. The requester can withdraw while the journey is in flight.

A rejection anywhere drops the record to Changes requested, with the approver's reason attached, and edits unfreeze so the record can be fixed. What resubmitting does is the policy's choice: restart from the first stage (the record changed, so earlier approvals are stale — the safe default) or resume at the stage that said no, keeping earlier answers for long chains where a late no shouldn't re-tax early approvers.

The last step: Posted

When the final quorum clears and every gate is green, the record is ready to post — the people who can post are told. Who that is, is the policy's call: anyone who can edit the table, or Admins only. There is also an auto-post switch for the fully hands-off pipeline, off by default because most teams want the deliberate click. What Posted means — and how to undo it — is its own article: Posted: the seal, and unposting.

One guarantee underneath all of it: what a decision means is frozen when the ask is created. Editing a stage tomorrow never rewrites a question already sitting in someone's queue today.

Governance

Gates: linked records hold the door

A gate is a condition over a record's linked records that must hold before it can be posted — "every line item is Approved", "the linked purchase order is Posted". Gates are what make posting relational: no single-table tool can promise anything about the records on the other end of a link.

What a gate says

Each gate names a route to related records and a condition they must satisfy: every linked Line Item's Status is Approved, the linked PO's Approval status is Posted, no linked Task is still Open. An invoice that carries unapproved line items simply cannot be posted, whoever is pressing the button — the gate is policy, not etiquette.

The same routes as everything else

Gates travel the exact route vocabulary that lookups, rollups and report columns use — pick the relation, drill in, tap the field. There is no separate predicate language to learn, and a route that works in a filtered rollup works in a gate.

Empty is a block, not a pass

"Every linked line item is Approved" is vacuously true of an invoice with no line items — and vacuously posting an empty invoice is almost never what anyone meant. So an every linked… gate blocks when there is nothing linked at all, unless you explicitly tick allow zero linked for gates where empty genuinely is fine.

Gates are checked when it matters

The record's Posting panel shows each gate with a live verdict, so the person shepherding a record can see exactly what is still in the way. Gates are re-evaluated at the moment of posting — a linked record that changed since the panel was drawn can't slip through — and when a linked record changes in a way that clears the last gate, the people who can post are told the record is ready.

Governance

Posted: the seal, and unposting

Posted is a seal, not a status: the record is stamped with when and by whom, and becomes read-only everywhere — the grid, the record page, the drawer, imports, automations, and the API — until someone with delete-level access unposts it, with a reason, on the record.

What the seal means

Posting stamps the record — when, and by whom — and from that moment every write path refuses it: cell edits in the grid, the record page, the peek drawer, bulk edits, imports, automation steps, and the public API (which answers with a clean 409 rather than an error page). Posted rows wear a seal glyph, and the panel on the record collapses into the seal itself: Posted · date · name.

The point is what the word starts to mean: a posted invoice is the invoice that was sent. Nobody "just fixes" a number on it three weeks later, because nobody can.

Posting stops writes, and nothing else — a sealed record keeps taking part in everything that only reads it.

What still works on a posted record

The seal locks the record's content, not its usefulness:

  • Attachments and generated documents can still be added — they are notes pinned to the seal (the signed PDF of a posted invoice), not the sealed content.
  • Other records can still link to it — a payment can point at a posted invoice.
  • Comments and the conversation stay open.
  • Reading, filtering, reporting, exporting — all unchanged. Posted records are the ones your reports should trust most.

What is refused

Edits to any field, from any direction — including the paths people forget are write paths: imports that would update matching rows, automations whose step targets a sealed record (the run log says so plainly), and API writes. Subitem changes beneath it count as edits. And a posted record cannot be deleted: the seal outranks the bin — unpost first, then delete if you must.

Unposting: the audited escape hatch

Sometimes the sealed thing is wrong, so the seal opens — deliberately, and on the record. Unposting requires delete-level access (state reversal is a delete-class act) and always requires a reason, which lands in the audit trail and in the notification the interested people receive. Then fix the record, resubmit, and post again.

Cascade sealing: parent and children together

The policy can name Relation fields whose linked records post and unpost together with the parent — post the invoice and its line items seal with it, carrying the identical stamp; unpost it and exactly that set opens again. The cascade follows only the relations the policy names, one hop, so nothing the builder didn't choose ever locks by surprise.

The period lock

Give the policy a Date field and an Admin gets Lock period: pick a day, and every unposted record dated on or before it is posted in one action — closing June the way an accounting system closes June. It is the same seal, applied in bulk, and unposting a single record afterwards works exactly as it always does.

Finding the posted

Posted at is available to saved-view filters like any field — "Posted this month" is an ordinary saved view, and "Drafts only" is its empty-check mirror. The API returns postedAt and postedBy on every record payload, both null while the record is open.

Governance

Approval timing: due windows, reminders and out of office

Every stage can carry a clock — a due window, a reminder cadence, a delay before it opens, and an escalation when the window is blown — and every person can set a delegate for when they're away. Approvals move at the speed you configured, not the speed of whoever forgot.

Due windows

Give a stage a due window and every ask it fans out carries a deadline. Overdue asks are flagged in the queue and on the record's Posting panel, so "who is this waiting on, and how long" is never a question you ask a person.

Reminders

A stage can re-nudge its pending approvers on a cadence — in-app, and by email for people whose own Reminders toggles say so. No cadence set means ask once, never nag; the queue and the bell still show the ask, but nobody's inbox pays for a slow week.

Space between stages

A stage can wait a while after the previous one clears before it opens and its people are pinged — give Legal a day with the contract before Finance is bothered at all. Until the delay elapses, the next stage's approvers see nothing, which is the point: an ask that might be withdrawn tomorrow shouldn't interrupt anyone today.

When the window blows: escalation

Each stage picks what happens when an ask goes past due:

  • Notify — tell the requester and a named person; the ask stays put.
  • Add an approver — a named person joins the round alongside the original approver.
  • Reassign — the stale ask is retired and a fresh one goes to the named person, carrying a visible for {name} trail.
  • Auto-approve / Auto-reject — the overdue ask decides itself, and writes an explanatory note saying so. There are no silent robot decisions: an auto-outcome always reads as one in the trail.

The due window is the escalation clock — one clock per stage, not separate timers to keep consistent. A stage with no due window never escalates.

Out of office

In Settings, anyone can set a delegate and an until-date. While it's active, new asks aimed at them are redirected to the delegate at the moment they're created, with a visible trail showing who they stand in for. Asks already sitting in the queue don't move — redirecting history would falsify who was asked — and when the date passes, the redirect simply stops applying. Nothing to remember to switch off.

Governance

Why you can't edit the approval status field

On a table with posting rules, the approval status Select field refuses direct edits by default — from the grid, bulk edits, imports, automations and the API alike. An "Approved" in that column therefore always means a real decision by a real person, never a hopeful hand-edit.

The hole this closes

In most tools, an approval workflow ends by writing a status cell — and that cell remains an ordinary cell, editable by anyone with edit rights. The workflow is theatre: whatever ceremony produced "Approved", a hand-edit produces the identical value, and no reader can tell the difference afterwards.

RowFold's approval status field deliberately refuses that. While the policy protects it, the value only moves through the flow itself — submitting, deciding, posting, unposting. Every surface that writes fields says no: the grid and drawer won't offer it, bulk edits and imports skip it and say so, automations that try fail with a named reason in their run log, and the API answers with a clean refusal.

Everything downstream still works

Protection is about who may write the field, not what it is. It remains an ordinary Select everywhere it's read — filters, boards, reports, automation triggers, the API — and when the flow writes it, that write fires automations and webhooks like any other edit. You lose nothing except the ability to fake it.

Turning it off

The policy has a switch, and an Admin can flip it — some teams migrating old data in bulk prefer a window where the field is writable. Leave it on once real work starts: the guarantee "this value always came from the flow" is the entire reason to trust the column, and it is not recoverable retroactively for values written while it was off.

Governance

People, roles & permissions

Manage who belongs to each workspace and what they can do there. Every member gets one of four roles as a baseline, and you can fine-tune access table by table and even field by field.

Understand the four roles

Every workspace member has exactly one role, which sets their default access to every table in that workspace:

  • Admin — full control. Views, creates, edits, and deletes records, and is the only role that can invite people, remove members, change roles, or set per-table and per-field overrides.
  • Editor — views, creates, edits, and deletes records. No member or permission management.
  • Contributor — views everything and creates new records, but cannot edit or delete existing ones.
  • Viewer — read-only. Useful for stakeholders who only need visibility.

Roles are set per workspace, so the same person can be an Admin in one workspace and a Viewer in another. Per-table overrides can raise or lower these defaults for individual tables.

See who has access

Open People & members in the left rail's Workspace section. Each member appears as a card showing their name, email, current role, and a short description of what that role allows. Your own card is tagged you.

Each card also shows a workspace count, such as In 3 workspaces — how many of your workspaces that person belongs to. Workspaces you are not a member of yourself are never counted.

Invite someone to the workspace

Scroll to Invite someone at the bottom of the People page — or press Invite person at the top of the Permissions page to get there. Choose a person under Person, pick a Role, and press + Invite.

The picker lists only people who already share a workspace with you and are not yet members here. When everyone you share a workspace with is already a member, the Invite someone section disappears. Inviting someone who is already a member changes nothing, so a double-submit is harmless.

Change a role or remove someone

On a member's card, pick a new role from the dropdown — it saves as soon as you choose. You can also change roles on the Permissions page, where each role button includes a reminder of what it allows.

Press Remove to take someone out of the workspace. You cannot change your own role or remove yourself; another Admin has to do that for you. Invitations, removals, and role changes made on the People page are recorded in the audit history.

Grant access to a whole folder

The Folder access card sets one person's access to every table in a folder at once — Full, Read and create, Read only or No access. This is what replaced giving somebody a separate workspace, and unlike a separate workspace nothing they can see loses its relationships to the rest of your data.

Access resolves in one order: an explicit override on the table wins; failing that the folder's grant applies; failing that their role decides. Marking the folder hidden removes it — and its name — from anyone without a grant.

Override access for a single table

Open Permissions, pick a person from the Members list, and find the Per-table overrides section. Each table has an override dropdown with five settings: Inherit from role, Full access, Read & create, Read only, and No access (hidden). Your selection saves the moment you make it.

Overrides work in both directions. Full access lets a Viewer create, edit, and delete in that one table, while No access (hidden) hides a table completely — even from an Editor. Choose Inherit from role to remove an override and fall back to the role's default.

The Effective column shows the result of role plus override as chips — View, Create, Edit, Delete, or Hidden — so you can confirm exactly what that person can do. Use Open → to jump into the table itself.

Work down until something answers. This is also why an admin can be shut out of one table — an explicit decision has no role left to fall back to.

Hide or lock individual fields

Click a table's name in the overrides list to expand its fields. Each field has its own dropdown: Inherit, Read only, or Hidden. A Hidden field is invisible to that person and cannot be edited; a Read only field is visible but locked.

Field overrides only tighten access — if someone cannot edit the table, every field stays read-only for them regardless of the field setting. Setting a table to No access (hidden) hides all of its fields automatically. A chip next to the table name counts how many fields have overrides, so restricted fields are easy to spot later.

Governance

Audit log & Trash

See who changed what across your workspaces, and recover deleted records from the Trash. The audit log is your activity trail; the Trash is your safety net.

Know what gets audited

RowFold writes an audit entry for every meaningful change in a workspace:

  • Records — creating a record, editing a cell, and deleting records each write an entry naming the record and its table.
  • Schema — creating or renaming a table, adding or removing a field, tables built with AI, and tables created during an import all appear as Schema entries.
  • People — inviting someone, removing them, or changing their role is logged with the person's name; invitations and role changes record the role too. These entries appear under the Schema filter.
  • Workspaces — creating a workspace writes a Created entry that names the template it was built from.

Every entry captures when it happened, who did it, and a plain-language summary of the change.

Read and filter the audit log

Click Audit log in the rail to see activity for the current workspace, newest first. The chips across the top show a live count per action — click Created, Updated, Deleted, Schema, Restored, or Impersonated to focus on one kind of change, or All to clear the filter.

Each row shows When (in your local time, down to the second), the Action, What changed with the table and record it touched, and By — who did it. The page shows the 200 most recent entries that match your filter.

The audit log for a workspace. A row of filters counts each kind of change — created 9, updated 26, deleted 2, schema 7 — above a table of entries giving the time, the kind, what changed and who did it.
Schema changes are logged beside record changes, so “who added that column?” is answerable too.

Send records to the Trash

Deleting a record never destroys it right away. Tick the checkboxes next to rows in the grid, then click Delete in the bar that appears and confirm — the records vanish from every view and report, but they move to the Trash instead of being erased.

Each deletion also writes a Deleted entry to the audit log, so you can always see who removed what.

Deleting is a move, not a destruction — and restoring puts the record back with its links intact.

Restore a record

Open the Trash to see deleted records from all your workspaces, most recently deleted first. Each row shows what the item is, where it lived (From), Deleted by, When, and an Auto-purge countdown.

Click ↶ Restore and the record returns everywhere it appeared before. Its links to other records come back with it — connections are kept intact while an item sits in the Trash. A confirmation banner tells you the restore worked.

Delete forever

To permanently remove a single item, click Delete forever on its row and confirm. This erases the record and its connections to other records, and it cannot be undone.

Empty trash purges everything in one go, also behind a confirmation. It only removes records from tables where you have delete permission — anything you can't delete stays in the Trash, and the banner tells you how many items were actually purged.

Watch the retention countdown

Every item in the Trash shows an Auto-purge countdown against a 30-day retention window. The days-left badge switches to a warning color once fewer than 7 days remain.

Restore anything you care about before its countdown runs out.

Who can do what

Anyone in a workspace can read its audit log and see its deleted records in the Trash — both pages only ever show workspaces you belong to.

Restoring and permanent deletion count as delete actions on the record's table. By default that means workspace Admins and Editors; Contributors and Viewers cannot restore or purge unless a per-table permission override grants them full access.

Account & settings
Account & settings

Settings & your account

Settings is where you shape how RowFold sees you and how it looks to you: your name and photo, how dates and money are formatted, interface preferences, notifications, data export, and account-level actions like transferring a workspace or deleting your account.

Open your settings

Click the icon beside your name at the bottom of the left rail — it shows Settings when you hover. Everything on this page belongs to your account, not to any one workspace: changes here follow you across every workspace you're a member of.

The page's side navigation jumps between cards: Profile, Formatting & locale, Preferences, Notifications, Security, Data export, and Danger zone.

Update your name and photo

Type a new name into Display name and click Save profile. Your name and initials update in the rail and everywhere teammates see you, immediately — no need to sign back in. The Email field is shown for reference and can't be edited here.

Click Upload image (or Change image if you already have a photo) to set a profile photo. It must be a PNG, JPG, WEBP, or GIF, 2 MB or smaller, and it appears right away. Until you upload one, RowFold shows your initials on a colored chip instead.

Choose how dates, numbers, and money look

The Formatting & locale card controls how dates, numbers, currencies, and times appear for you, everywhere in RowFold. Pick a Language & format, a Currency, and a Time zone, then click Save formatting.

Each menu starts on Auto — match this device. On Auto, no preference is stored: each device you use formats things using its own language and time-zone settings, and a hint under each menu shows what this device resolves to (for example en-US or Europe/London). Choose an explicit option and it follows you instead — every browser you sign in on formats the same way.

The Preview row shows a sample amount, date, and time that updates as you change the menus, so you can see exactly what you'll get before saving.

One thing the locale doesn't change: times are shown on a 12-hour clock with AM/PM, everywhere a person reads one — the calendar, the scheduler, booking pages, confirmation emails and automation messages. Your Language & format choice still sets the date pattern (11/06/2026 or 06.11.2026), because wanting a European date and wanting a 24-hour clock are separate preferences and only the first is asked about. Stored values, CSV exports, the API and anything you type into a time box are unaffected — this is how a time is displayed, not how it is kept.

The time zone your workspace works in

An admin sets the workspace's time zone in Settings. It defaults to the zone of whoever created the workspace rather than to UTC, so it is usually right before anyone touches it.

This is the clock for things that belong to a place. Record dates are stored as plain wall-clock time, and this says which wall. It is also what two other things now run on:

  • Scheduled automations. "Every day at 9am" means 9am where you work.
  • Relative date filters. "Due in the next 7 days" counts against your calendar.

Both of those used to run on UTC for everybody. This is separate from the time zone on your own profile, which governs instants — "edited 2 hours ago", when a digest was sent — and those still render in yours. Leaving your personal one on Auto follows your device.

Tune preferences and notifications

Under Preferences, four switches shape the interface across the product: Show schema graph on every workspace home, Highlight relation fields in violet, Use plain-English labels (Summary not Rollup, Hops not Walks), and Enable beta features. Click Save preferences to apply.

Under Notifications, choose Email and In-app delivery separately for Mentions on records, Workspace digest (weekly), and Date reminders, then click Save notifications.

Rewrite the emails RowFold sends for you

Settings → Email templates lets an admin rewrite the mail sent on the workspace's behalf, with a live preview against sample data, tokens for the record and the workspace, and a reset back to the original wording.

  • To your customers: form acknowledgements, ticket replies, chat transcripts.
  • To your team: new form submissions, the daily digest, watched records changing, mentions, and the four approval emails (requested, decided, reminder, escalated).

Two limits are deliberate. A customer-facing template can only reference what that surface already publishes, and a member-facing one is resolved against each recipient's own permissions — so a template can never become a way to email somebody a field they aren't allowed to see.

And RowFold's own mail is not editable: invitations, sign-in links, security and new-device alerts, verification. That isn't an omission. An admin who could rewrite a sign-in email could phish their own team with a genuine, correctly-signed RowFold message.

Sign in, stay signed in, sign out

You normally sign in with your Work email and Password, or with Google or Microsoft if your RowFold shows those buttons. Email me a sign-in link remains available as a secure one-time alternative whenever you do not have your password handy.

Keep me signed in is ticked by default and keeps you signed in on that browser for 30 days, renewing as long as you keep using RowFold; untick it and your session ends when you close the browser.

To sign out, click the icon beside the Settings icon at the bottom of the rail — it shows Sign out when you hover. You land back on the sign-in page.

Everything else about signing in lives on Settings → Security: two-factor authentication, which identity providers your account answers to, every browser currently signed in, and — if you own a workspace — what you require of your team.

Sign-in links work once and expire after 30 minutes. Opening one signs that browser in and spends the link. That is what keeps a forwarded email from becoming a way in. A spent or stale link says so plainly and offers a fresh one to the same address.

See and end your active sessions

Settings → Security lists every browser currently signed in to your account: the browser and operating system, how it signed in, the address it signed in from, and when it was last active. The one you are reading from is marked This device.

Press Sign out on any other row to end that session on its own. Sign out other sessions ends all of them but keeps you signed in here — that is the one to reach for when you spot a row you do not recognise. Sign out everywhere ends every session including this one, and also forgets your recognised devices so the next sign-in anywhere emails you; use it if you think someone else has access.

Ending a session takes effect immediately on the server you are talking to and within a minute everywhere else. You get an email whenever sessions are ended, as you do for any change to your password or two-factor setup.

Connect Google or Microsoft to your account

The Connected accounts card on Settings → Security shows which identity providers your account answers to, and offers a Connect button for the ones it does not. Connecting from here, while already signed in, is the only way to link a provider that will not vouch for your email address — RowFold matches you on the provider's own account id rather than on the address, so a provider it does not already know cannot claim an existing account by asserting its email.

Disconnect removes a link. RowFold refuses if it would leave you with no way to sign in — an account with no password and no other provider, or one whose team requires single sign-on.

Connecting a provider does not change how your current session was authenticated. If your team requires single sign-on, sign in with the provider to get a session that satisfies it.

Require single sign-on for your team

If you own a workspace, Settings → Security offers Require single sign-on. Switch it on and everyone in the workspaces you own must sign in with Google or Microsoft: password sign-in is refused for them, and anyone already signed in with a password is asked to switch within a minute. It sits beside Require two-factor for your team and the two work together.

The switch stays unavailable until it is safe to use: an identity provider must be configured, you must have connected one to your own account, and everyone on your team must have connected one too — the card names anyone who has not. This is stricter than the two-factor requirement on purpose. Somebody told to set up two-factor can always do it on the page they land on; somebody told to use single sign-on cannot, if their provider will not vouch for their address, so the switch waits for them rather than locking them out.

You are exempt from your own switch, so a provider outage can never strand the one person who can turn it off.

Export your data, transfer a workspace, or delete your account

Under Data export, Full workspace JSON downloads the schema and every record across all your workspaces, and CSV per table downloads a zip with one CSV for every table you can access. Both work at any tier. A third tile, PostgreSQL dump, is shown as a Business-tier feature and isn't active here.

The Danger zone holds the irreversible actions. Transfer hands a workspace you administer to another member: they become the Admin and you stay on as an Editor. Delete account removes your profile, memberships, and permission overrides after you type your email to confirm — shared workspaces stay intact for their other members, and it cannot be undone.

Understand the "viewing as" banner

A dark banner across the top of every page reading You're viewing as … means this browser session is a super-admin signed in as another account, usually to help with a support question. Clicking Return to your account switches the session straight back to the admin's own account.

Impersonation is deliberately visible and safe: every start and stop is written to the audit log, the impersonated session never outlives the browser session, and deleting the account is blocked until the admin returns to their own account.

The Admin console (super-admins only)

Super-admins see an extra Admin entry in the rail, marked with a SUPER badge. It opens the Admin console: every account on this RowFold instance — name, email, workspace count, and join date — with a search box that matches name or email, and a super-admin badge on allowlisted accounts.

Clicking Log in as → starts impersonating that account after a confirmation prompt. You can't impersonate yourself or another super-admin. Super-admin status itself comes from a server-side allowlist set at deployment — no account can grant it from inside the app.

Account & settings

Branding what your customers see

Public forms, acknowledgement emails and ticket replies are read by people who have never heard of RowFold and have no reason to. One settings page — logo, accent, background, typeface, organisation name — repaints every one of those surfaces across every workspace the account owns, immediately and without anyone touching a stylesheet.

Set your identity

Open Settings → Branding. Organisation name is used wherever there is no logo, in the footer of the emails you send your customers, and as the sender name on ticket replies — so it is worth setting even when you have a mark.

Logo takes a PNG, JPG, GIF or WebP up to 2 MB. It is displayed up to 44px tall on a form or a booking page, and smaller where space is tighter — in an email, on the help centre, in the chat window — so a wide lockup works far better than a square icon. SVG is refused: an SVG is a document that can carry script, and this image is rendered on pages RowFold serves to the public.

Colour and type

Accent paints buttons, focus rings and highlights; Page background is the paper behind the card. You pick one accent and stop — the hover shade and the tint are derived from it, and the button's own label colour is chosen for contrast, so navy gets a white label and a bright lime gets a near-black one. Nobody ends up with an unreadable button because they liked a yellow.

Both reach your customer emails too: a message sits on your page background rather than a stock grey, and its button takes the accent with the same contrast-checked label. Link text inside a message uses a darkened version of your accent instead — a pale brand stays readable as text, which the raw colour would not be.

Typeface offers Modern sans, Classic serif, Friendly rounded and Technical mono. All four resolve to fonts the visitor's device already has, so a branded form downloads no web font, loads no slower, and leaks no visitor's IP address to a font CDN — which matters more here than on our own pages, because these are your customers.

The RowFold badge

The Made with RowFold footer is on by default and any account can switch it off, including one still on trial. Nothing on this page is plan-gated: the promise is that there is no tier above you holding features back, and a badge you had to upgrade to remove would be the one visible thing contradicting it - on a page your own customers see.

One switch covers everywhere it shows: forms, booking pages, the help centre, the chat window, and the emails those surfaces send. It goes off everywhere at once — there is no per-surface copy of it to hunt down.

See it before anyone else does

The Preview card beside the settings renders roughly what someone filling in one of your forms will see, built from what is in the boxes right now. Nobody has to publish a form to find out what a colour looks like on it.

The page also counts how many forms the change is about to repaint, because it is worth knowing that before pressing Save branding.

Override it on one form

The form designer's Look section can differ from the account brand in three ways and no more: Use a different accent here, Show the account logo off, and the after-submit redirect. Those are the pieces a single form plausibly needs of its own; anything further would be a second branding system to keep in step with the first.

A form that overrides nothing simply follows the account, so changing the account brand moves every form with it.

Where the brand turns up

Everything a stranger can reach. On the web: the public form, your booking page and the manage-your-booking page behind it, the public help centre, and the chat widget. By email: the acknowledgement a form submitter gets with their answers echoed back, every booking confirmation, reminder, change and cancellation, the rating request after a ticket is closed, the transcript emailed at the end of a chat, and the replies your team sends.

The emails wear the same brand the pages do — accent, page background, typeface and logo — so a confirmation and the page its button opens are the same colour rather than nearly. One brand, every anonymous surface, every workspace the account owns.

Account & settings

Your plan & billing

How the trial, the plan, editors, and billing work - and where to manage all of it.

The trial, then one plan

Every account starts with a 30-day free trial of the complete product - nothing held back, no card required. The point of it is not to preview RowFold but to build something you actually run, so you can import real data, invite the people who'll use it, wire up automations and connect your other tools during the trial.

After that there is one plan: $29/month per editor, from the first one — no minimum, no bundle and no band to fall into. Three editors is $87/month; ten is $290. Pay yearly and it's two months free.

You are charged for editors, never for records, tables or relationships, and there is no tier above you holding features back. Read-only Viewers are free and unlimited - stakeholders can watch dashboards without taking a seat. If your trial ends without a subscription, nothing is deleted: your work is waiting when you subscribe.

What counts as an editor

An editor is a person who can change things: Admins, Editors, and Contributors across the workspaces you own, counted once each even if they're in several of your workspaces. Read-only Viewers are always free, so stakeholders can watch dashboards and reports without costing anything. People you've invited who haven't accepted yet are free until they create their account. Someone who only submits a public form, or emails a table's address, never gets an account at all - so they never become an editor.

Seats adjust themselves

Invite someone mid-month and the extra seat is prorated onto your next invoice; remove someone (or make them a Viewer) and the unused time comes back as prorated credit. You never file a seat-count change by hand - RowFold syncs it to Stripe automatically and reconciles nightly.

Subscribing covers your whole team

One subscription per customer: when you subscribe, everyone in the workspaces you own keeps full access - they don't each need a plan. Teammates can check Settings → Plan & billing to see whose plan covers them.

Manage everything from Settings

Settings → Plan & billing is the one place: subscribe (checkout is handled by Stripe - RowFold never sees your card), switch monthly ↔ yearly, update the card, download invoices, or cancel. Cancelling stops the next renewal; your data stays exactly as it is, and if the trial or plan lapses everything is preserved read-only until you're back.

AI fair use

Every AI feature is switched on for everyone - there is no "AI tier". What is bounded is volume, so that one runaway account can't spoil it: each month your account includes 500 AI actions per editor, pooled across everyone on your plan. Five editors therefore share 2,500, and one heavy user simply draws from the pool. Trials are pooled the same way, so you can evaluate properly.

An AI action is one thing you asked for: an Ask question (however many steps it takes behind the scenes), a build-mode turn, generating a dashboard or its summary, an AI-designed schema or hierarchy, an AI import mapping, or one run of an AI automation step. Answers that fail or fall back to the built-in analyzer never count.

Help search, field suggestions, and the weekly digest are not counted - they're part of the product, not something you spend. The allowance resets on the 1st of each month, and your current figure is on the Settings → Plan & billing card. If you run out, only the AI pauses - grids, views, reports, dashboards, automations, forms and the API all keep working exactly as before. If you genuinely need more, email support@rowfold.com and we'll sort it out; these numbers are set to be generous, not to catch people.

Account & settings

HIPAA & Business Associate Agreements

How to request a BAA so your team can store protected health information in RowFold, what the agreement covers, and why it is available on annual plans.

What a BAA is, and what it isn't

Under HIPAA, a vendor that handles protected health information (PHI) on a covered entity's behalf is a Business Associate, and that relationship is created by a signed contract - the Business Associate Agreement. It commits us to specific obligations: administrative, physical and technical safeguards, breach notification within defined timeframes, and equivalent agreements with any subprocessor that could touch your data.

It is worth knowing that HIPAA has no certification. There is no auditor who inspects a product and declares it HIPAA compliant, so any vendor showing you a "HIPAA certificate" is describing something that does not exist. The agreement is the real artefact - which is why RowFold offers one rather than a badge.

Requesting one

Go to Settings → Compliance and fill in three things: the legal entity name to put on the agreement, the email the paperwork should go to (often legal or privacy rather than you), and optionally a line about what you intend to store so our first reply is useful rather than a questionnaire.

We'll email you the agreement to review. Your request and its status stay on that card, so you can always see where it has got to.

You're covered when it's signed - not before

This is the part that matters most. Requesting a BAA does not create cover, and neither does being on an annual plan. Do not put PHI in RowFold until your agreement is signed by both sides.

The Compliance card shows exactly which state you're in - requested, sent for signature, or in place - and only the last one means you may store health data. We'd rather be blunt about this than have you discover it during an audit.

Why annual plans

A BAA commits us to obligations that outlast a monthly billing cycle, and to a customer relationship we can plan around, so it is offered alongside an annual plan. You can switch from monthly to yearly at any time from Settings → Plan & billing using the Stripe portal, and the option to request a BAA appears as soon as the switch goes through.

If the annual commitment is the only thing in the way, email support@rowfold.com and we'll talk it through.

What a BAA doesn't change

A BAA covers health data. It does not make RowFold suitable for US government data - we hold no FedRAMP authorization, which is granted after third-party assessment with an agency sponsor, and no BAA affects that. Card numbers should also never be stored in RowFold: payment details go to Stripe and never reach us.

Our full position on every regime, including SOC 2, ISO 27001 and GDPR, is on the public Compliance page.