Page builder
Compose record pages, app pages and home pages from fields, related lists, charts, list views, text, flows and installed apps — no code, versioned, assigned per profile.
The page builder composes whole pages out of components. Org owners and admins
(or a system admin) use it under Settings → Page builder; it is part of
app_platform (Professional). An organization that hasn't assigned a builder
page sees every page exactly as SalesOS ships it.
There are two kinds of page:
- Record pages — the page for one object:
LEAD,CONTACT,ACCOUNT,OPPORTUNITYorcustom:<apiName>. Regions: header (above the tabs), tabs (at least one; only the open tab is mounted) and sidebar (the rail beside the tabs). - App pages — your own pages at
/dashboard/p/<slug>, for dashboards, team hubs and launch pads. Regions: header, main and sidebar. An app page can be listed in the navigation and can replace/dashboardas the home page for chosen profiles.
Components
| Type | Pages | What it shows |
|---|---|---|
field_section | record | Chosen fields in one or two columns, read-only or editable in place |
metrics | record | Up to six headline figures from the record |
record_brief | record | A short summary block from up to four fields (not AI) |
related_list | record | Contacts, deals, tasks, cases, quotes or orders of the record, with columns, a filter, sort and a row limit |
custom_related_list | record | Custom object records that look up the record |
activity_timeline | record | Activities, notes and field changes (standard objects) |
builtin_tab | record | One of the page's own tabs, exactly as today |
builtin_rail | record (sidebar) | The page's own field rail, with inline editing |
rich_text | any | Formatted text: paragraphs, emphasis, headings, lists, links |
report_chart | any | A widget from a dashboard shared with the org or a team |
list_view | any | A few rows of a list view (system or shared saved view) with a link to the rest |
flow_launcher | any | Starts a screen flow, as a button or inline |
quick_actions | any | Buttons: edit the record, run a custom action, start a flow |
app_slot | any | An installed app's extension: record.tab / record.sidePanel on record pages, dashboard.widget on app pages |
A new record page starts as the page it replaces — every built-in tab as a
builtin_tab and the rail as builtin_rail, or the arrangement of an existing
page layout — so nothing changes until you change it.
Visibility
Every component and tab can carry visibility:
profiles— profile ids; none means everyone.formFactor—desktop,mobileorall(the md breakpoint, 768px).conditions— record pages only:{ field, operator, value }witheq,neq,contains,gt,lt,is_empty,is_not_empty, combined bymatch: all | any.
Profile rules are applied on the server: a viewer never receives components meant for other profiles. Form factor and conditions are evaluated in the browser against the record as the viewer received it. A component whose condition names a field the viewer can't read is removed on the server, so a condition can't reveal a hidden value.
Field-level security
A page can't reveal a field. When a page resolves, every field the viewer's profile can't read is taken out of sections, tiles, briefs and list columns, and the records themselves still arrive with those fields stripped by the API.
The editor's preview renders with the admin's own access and flags each placed field that some profile can't read ("Hidden from Sales: Annual revenue"), so you can see what those people will miss.
Which page a person gets
Record pages are assigned per object × profile, optionally × record type: choose a picklist field of the object to act as the record type, then assign pages to its values. For a viewer, the first match wins:
- each of the viewer's profiles, in assignment order: with the record's type, then for any type;
- the organization default (no profile): with the record's type, then any;
- otherwise the page as it is today — the existing page layout, if any, and installed apps.
The record type is read only when the viewer can see the record and read the field. Assignments take effect once the page has an active version.
Versions
A page has at most one open draft and one active version. Saving validates the whole definition against your organization (fields, relations, profiles, charts, views, installed extensions) and rejects anything that doesn't resolve. Activate publishes the draft and archives the previous version; Revert copies an archived version into a new active one. History keeps every version.
The builder
Everything is operable from the keyboard: choose a region with Add here, add components from the palette, select one to edit its properties, and use Move up / Move down / Move to… to rearrange — each move is announced, and focus stays on the moved component. Undo and Redo (Ctrl/⌘ + Z, Ctrl + Y or ⌘ + Shift + Z) cover every change since the page was opened. The Preview tab renders the page for a sample record at desktop or phone width.
Definition format
Custom fields on standard objects are cf:<apiName>. Limits: 60 components
per page, 20 per region, 12 per tab, 12 tabs, 40 fields per section, 8
columns, 3 filters, 5 conditions, 20,000 characters of rich text. Rich text is
rebuilt from an allow-list on save (links keep only an http(s), mailto: or
relative href) and sanitised again when shown.
API
Session only (not API keys or OAuth tokens); use the metadata API to manage pages programmatically.
| Method | Path | Who |
|---|---|---|
GET | /v1/page-builder/resolve/record/:objectType?recordId= | any member |
GET | /v1/page-builder/resolve/app/:slug | the page's audience, org owners/admins |
GET | /v1/page-builder/resolve/home | any member |
GET | /v1/page-builder/nav | any member |
GET | /v1/page-builder/meta?objectType= | org OWNER/ADMIN, system ADMIN |
POST | /v1/page-builder/preview | org OWNER/ADMIN, system ADMIN |
GET POST | /v1/page-builder/pages | org OWNER/ADMIN, system ADMIN |
GET PATCH DELETE | /v1/page-builder/pages/:id | org OWNER/ADMIN, system ADMIN |
PUT DELETE | /v1/page-builder/pages/:id/draft | org OWNER/ADMIN, system ADMIN |
GET | /v1/page-builder/pages/:id/versions | org OWNER/ADMIN, system ADMIN |
PUT | /v1/page-builder/pages/:id/assignments | org OWNER/ADMIN, system ADMIN |
GET | /v1/page-builder/versions/:id | org OWNER/ADMIN, system ADMIN |
POST | /v1/page-builder/versions/:id/activate · /revert | org OWNER/ADMIN, system ADMIN |
PUT | /v1/page-builder/objects/:objectType/settings | org OWNER/ADMIN, system ADMIN |
A resolve with no assigned page answers { "page": null, "source": "default" }.
recordTypeSensitive: true means the answer depends on the record, so ask
again with recordId.
Metadata
Builder pages travel in change sets and the metadata source format:
PAGE—pages/<apiName>.page.json:apiName,label,description,objectType,recordTypeField,assignments({ profile, recordType },nullfor everyone / any) anddefinition.APP_PAGE—app-pages/<apiName>.apppage.json:apiName,label,description,slug,icon,showInNav,navOrder,audienceandhome(profile names;nullfor everyone else) anddefinition.
In source, app extensions are written app/<appSlug>:<key>, profiles by name
and custom actions by apiName, so a page resolves in the target org. A deploy
creates a new active version only when the definition changed; extensions the
target hasn't installed and custom actions it lacks are left out with a
warning. PAGE_LAYOUT components keep working as before.
Page layouts
Arrange Lead, Contact, Account, Deal and custom object pages for your organization or for one profile — tab order, the field rail and where installed apps appear.
Design tokens
The SalesOS palette, accessible text colours, typography, radii and shadows for light and dark mode — as TypeScript constants, CSS custom properties and a Tailwind preset.