Data and Forms
Vincent Depassier · August 30, 2026
A published App is static. Everything live in it — a product list, a member's own orders, a submitted form — is fetched from the browser through the API Gateway. This page is about how that connection is set up, and about the one rule that keeps it safe.
The runtime config
An App carries a small block of configuration that its published shell fetches when it boots. That block holds:
Field | What it is |
Gateway URL | Where to send requests |
Publishable key | A browser-safe |
Table map | Logical name → table id |
Automation map | Logical name → automation id |
Webhook map | Logical name → endpoint id |
The published site fetches this by subdomain, over an anonymous endpoint, and it returns only values that are safe in a browser. Nothing secret is ever part of it, because everything in it is one View Source away from being read.
Why the maps exist
You could hardcode a table id in a page. Then you copy the App to a second workspace for a client, and every id is wrong.
The maps give you a level of indirection. Your pages ask for products; the config says which table id that means here. The same App, pointed at a different workspace's config, works without a single edit to a page.
Name the logical keys after what they mean to the site, not after the table's current title. products, posts, team — those stay right when someone renames the table.
The credential
An App can generate its own gateway credential, and it is worth letting it: the generated key is scoped to exactly the tables currently mapped and locked to the App's own origin.
Both halves matter:
Scoped to the mapped tables means the key cannot read a table the site never mentions. Your
orderstable stays invisible to a marketing site's key even though both live in the same workspace.Locked to the origin means the key is useless from anywhere but your site. Someone who copies it out of your page source cannot use it from their own page.
If you map a new table later, regenerate the key. Otherwise the site asks for something the key is not allowed to see, and the request is refused — which reads like a bug and is actually the protection working.
What a publishable key can do
A pk_ key is public by design. Anyone who opens your site can read it, so treat it as published the moment you deploy.
That is fine, provided its permissions are honest about that. The scopes on it should be the ones you would be comfortable printing on a billboard: read on public tables, insert on the table behind a contact form. Not update. Not delete. Not the tables with people's data in them.
Would I be comfortable if a stranger made this exact request by hand? If no, that permission does not belong on a publishable key.
Anything you would not put on a billboard belongs behind an automation instead: the App calls the endpoint, the automation does the work with a server key the browser never receives, and returns only the answer.
Reading data
With the config in place, a page queries the gateway with PraxQL — the same query language the rest of the platform uses, documented under API Gateway. A collection page runs one query and renders the rows; a detail page runs one query for one row.
Filtering, sorting and pagination all happen in the query, not in the page, which means a list of ten thousand rows never becomes ten thousand rows of HTML.
Forms
Forms are not a separate engine inside Apps. A form block embeds a Praxsuite form, and submissions land where every other submission of that form lands — the same table, the same automations, the same notifications.
This is the part people usually rebuild by accident. If a form already exists in the workspace, the App should embed it rather than posting rows itself: you get validation, the submission record and any automation wired to it, for free.
Content only some visitors see
On a private or mixed App, a signed-in visitor holds an end-user token. Requests made with that token are filtered by that person's gateway roles — so "show me my orders" is not a filter your page applies, it is a filter the gateway applies before answering.
That distinction is the whole security model. A page that fetches everything and hides the other rows in the browser has not hidden anything at all; the data was already in the response. Let the row filter on the role do the work.
The rule
Nothing secret goes into an App. Not an API key for a third-party service, not a server gateway key, not a token, not a password, not a connection string. A published App is a set of files anyone can download and read, including the ones your build never meant to be interesting.
When a page needs to do something with a secret, it calls an automation that holds the secret in the Vault, and receives only the result.
Next
Publishing and versions — getting the site out
PraxQL — the query language pages use to read data
Credentials and principals — what a publishable key is, in full
Automations — where server-side work belongs