By Example: How Truto Helps Engineers Build Faster Integrations - Notion
Build post-connection configuration UI for SaaS integrations with Truto's RapidForm. Declarative JSON config, cascading selects, pagination for 40K+ pages, and JSONata validation.
Notion is a powerhouse. To leverage it to the fullest, you also need a powerful integration.
With our Notion integration rollout, we believe we've exceeded expectations - the integration supports reading from over 40,000 pages. It also offers an upgrade over the standard Notion page selector by introducing the ability to select pages based on parent-child relationships, among other features.
The integration enables users to connect their Notion accounts and select the files they wish to sync. This feature is incorporated with RapidForm. RapidForm is our solution that allows your users to easily choose specific files or folders in their accounts.
This approach also helps ensure that you maintain strong data integrity and privacy by requesting access only to specific files and pages from your customers.
Enabling RapidForm will help your engineering team skip over tedious UI tasks, and save time.
How it works
- Connect a Notion account
! OAuth 2.0 connection screen for Notion featuring the Notion logo and a blue Connect button.
- Use the OAuth app provided by Truto or your OAuth app to authorize
- Chooses specific files to sync
The Notion form you see below is completely customizable.
! Truto's RapidForm UI showing a searchable checklist to select specific Notion pages for connection.
This RapidForm UI represents a significant improvement over the standard Notion page selector. Truto's RapidForm enables customization of the form field, including parent-child selectors, and provides a separate tab for viewing all selected pages. During our tests, it easily accommodated large Notion accounts with over 40,000 pages.
-
RapidForm can be initialized at any point using our Link SDK. This will enable your users to select additional files or pages at a later point in time.
-
All pages are stored as variables for easy access in RapidBridge and other places. You can learn more about variables here.
Building a Post-Connection Configuration UI with RapidForm
The OAuth handshake is just the beginning of any SaaS integration. What comes next is the harder problem: letting your users scope exactly which data they want to sync. Most teams end up building custom post-connection configuration UIs for every connector - a workspace picker for Asana, a channel selector for Slack, a page browser for Notion. Each one requires its own API calls, pagination logic, dependent dropdowns, and state management.
RapidForm is Truto's declarative answer to this. Instead of writing bespoke connector UI post-connection flows for each integration, you define a JSON configuration that describes what to collect from users. Truto handles the rendering, API calls, pagination, and persistence. One pattern works across every integration.
When to use RapidForm
- Scoping sync to specific resources: Let users pick which Notion pages, Asana projects, Zendesk tags, or Slack channels to sync - instead of pulling everything.
- Collecting integration-specific settings: Gather API keys, subdomain info, or configuration values that the OAuth flow doesn't capture.
- Enforcing data minimization: Only pull data your users explicitly approve. This matters for compliance and customer trust.
- Dynamic, dependent selections: Show projects within a workspace, or child pages within a parent - where one selection drives the next.
RapidForm JSON Configuration and Field Types
A RapidForm is defined as a JSON object with a type of "form" and an array of field definitions. Here's the structure for a Notion-style page selector:
{
"type": "form",
"config": {
"fields": [
{
"name": "pages",
"type": "multi_select",
"label": "Notion Pages",
"help_text": "Select the pages you want to sync",
"required": true,
"data_source": {
"type": "unified",
"resource": "documents/pages",
"method": "list"
},
"options": {
"value": "id",
"label": "name",
"parent": "parent_id"
}
}
]
}
}The parent attribute in options enables the parent-child grouping visible in the Notion screenshot above - Truto renders the page hierarchy so users can browse pages the way they do in Notion itself.
RapidForm supports several field types, each suited to different post-connection configuration needs:
| Type | Use Case | Example |
|---|---|---|
single_select |
Choose one option from a dropdown | Select a workspace |
multi_select |
Choose multiple options from a list | Select pages or projects to sync |
text |
Free-form text input | Enter a custom domain or filter |
password |
Sensitive input (masked) | Enter an API secret |
checkbox |
Boolean toggle | Enable or disable a sync option |
hidden |
Store computed or derived values | Session tokens, metadata |
Each field has a data_source that tells RapidForm which API to call (Unified or Proxy) and which resource and method to use. The options object maps response attributes to the label, value, and optional subtext shown in the UI.
Cascading Selects and Pagination
Real-world integrations rarely have flat option lists. Users have workspaces containing projects containing tasks, or parent pages containing child pages. RapidForm handles this with two mechanisms: field dependencies and built-in pagination.
Cascading dependencies let one field's options depend on another field's value. Here's a config where a workspace selector drives a project selector:
{
"type": "form",
"config": {
"fields": [
{
"name": "workspace_id",
"type": "single_select",
"label": "Workspace",
"help_text": "Select the workspace you want to sync",
"placeholder": "Select a workspace",
"required": true,
"data_source": {
"type": "unified",
"resource": "ticketing/workspaces",
"method": "list"
},
"options": {
"value": "id",
"label": "name",
"subText": "id"
}
},
{
"name": "collections",
"type": "multi_select",
"label": "Projects",
"depends_on": ["workspace_id"],
"help_text": "The projects to sync",
"required": true,
"disabled_text": "Please select a workspace",
"data_source": {
"type": "unified",
"resource": "ticketing/collections",
"method": "list",
"query": {
"workspace_id": "{{workspace_id}}"
}
},
"options": {
"value": "id",
"label": "name",
"subText": "id"
}
}
]
}
}How it works:
depends_onaccepts an array of field names. The dependent field stays disabled (showingdisabled_text) until its parent has a value.- The
queryobject indata_sourceuses{{workspace_id}}placeholder syntax to inject the parent field's selected value into the API call. - When a parent field changes, dependent fields reset automatically so stale selections don't persist.
- The order of fields in the
config.fieldsarray determines the order they appear in the UI.
Pagination is built in. For accounts with thousands of items - like our Notion integration handling 40,000+ pages - RapidForm paginates through results automatically. Users see a "Load more" button to fetch additional pages of data. For smaller datasets, you can enable auto-pagination to load everything as the user scrolls, but be careful with large datasets.
For multi-select fields where users might select 1,000+ items, set the high_cardinality flag to optimize how selections are stored and transmitted.
JSONata Validation Examples
Basic required/optional validation is built into each field. For more complex rules - like "select at least 5 projects" or cross-field validation - RapidForm supports custom validation using JSONata expressions.
Here's a validation that enforces a minimum selection count:
($exists(pages) and $count(pages) >= 1)
? undefined
: [{ "field": "pages", "message": "Select at least one page to sync" }]The expression receives the current form state as input and returns either undefined (validation passes) or an array of error objects targeting specific fields. This runs before the form can be submitted, giving users immediate feedback.
You can also use JSONata transform expressions to compute derived fields before saving. For example, adding a count of selected items and a timestamp:
$merge([
$,
{
"total_selected": $count(pages),
"configured_at": $now()
}
])The $merge function combines the original form data ($) with computed fields. The result is what gets persisted to the account context.
How RapidForm Persists Configuration to Account Context
Once a user submits the form, RapidForm saves all selected values as variables (also called context) on the integrated account. These variables are stored as a JSON object and are available everywhere in Truto - sync jobs, Proxy API calls, and custom automations.
For example, after a user selects three Notion pages in RapidForm, the integrated account's context includes:
{
"pages": [
{ "value": "abc-123", "label": "Product Roadmap" },
{ "value": "def-456", "label": "Engineering Wiki" },
{ "value": "ghi-789", "label": "Marketing Plans" }
]
}In a RapidBridge sync job, you reference these variables using placeholder syntax:
{
"resources": [
{
"resource": "documents/pages",
"method": "get",
"loop_on": "{{pages}}",
"id": "{{pages}}"
}
]
}The loop_on directive iterates over the selected pages, fetching each one individually. This is exactly how the 40,000-page Notion integration works - users pick what they need through RapidForm, and the sync job only pulls those pages.
The flow looks like this:
sequenceDiagram
participant User
participant RapidForm
participant Truto
participant Notion API
User->>RapidForm: Opens post-connection UI
RapidForm->>Truto: Fetch pages (Unified API)
Truto->>Notion API: GET /pages
Notion API-->>Truto: Page list (paginated)
Truto-->>RapidForm: Render page tree
User->>RapidForm: Selects pages + submits
RapidForm->>Truto: Save selections to<br>account context
Truto-->>User: Sync job uses<br>selected pages onlyEmbedding RapidForm in Your App
RapidForm renders automatically as part of Truto's account connection flow. But you can also trigger it independently at any point using the Link SDK - useful for letting users update their sync preferences after initial setup.
This means your post-connection configuration UI isn't a one-time gate. Users can come back and add or remove pages, change workspace selections, or update any configuration - without reconnecting their account. For your engineering team, this eliminates the need to build and maintain custom settings UIs for each integration.
Try out the Notion integration
Want to try out the integration? Get in touch with us at support@truto.one or book a demo.
Truto SuperQuery
This also marks the birth of Truto SuperQuery - our solution to help you filter data even when the underlying API lacks the necessary filters.
With Truto SuperQuery and Truto Real-time, businesses can fulfill all their desired use cases without any compromises. Discover more about the trade-offs between real-time and cached unified APIs here to determine which version of Truto aligns best with your specific needs.
FAQ
- What is a post-connection configuration UI in SaaS integrations?
- After a user completes OAuth and connects their account, they often need to scope what data to sync - picking specific workspaces, projects, pages, or channels. A post-connection configuration UI is the form that collects these preferences. Truto's RapidForm generates this UI from a declarative JSON config, eliminating the need to build custom forms per integration.
- How does RapidForm handle large accounts with thousands of items?
- RapidForm includes built-in pagination. For large accounts (like Notion workspaces with 40,000+ pages), users see a 'Load more' button to fetch additional results. For multi-select fields expecting 1,000+ selections, the high_cardinality flag optimizes storage and transmission.
- Can RapidForm fields depend on each other (cascading selects)?
- Yes. Use the depends_on array to specify parent fields. The child field stays disabled until the parent has a value, and the query object uses placeholder syntax like {{workspace_id}} to pass the parent's selection into the API call. Child fields reset automatically when the parent changes.
- How are RapidForm selections used in sync jobs?
- RapidForm saves all user selections as variables (context) on the integrated account. In a RapidBridge sync job, you reference these variables using placeholder syntax like {{pages}} in loop_on and id fields, so the sync job iterates over exactly the items the user selected.
- Can users update their RapidForm selections after initial setup?
- Yes. RapidForm can be opened at any time using Truto's Link SDK, independent of the initial connection flow. Users can add or remove selections without re-authenticating their account.