
Building Omnistudio Omniscript
- 1.9k installs
- 763 repo stars
- Updated July 24, 2026
- forcedotcom/sf-skills
building-omnistudio-omniscript is an agent skill that OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital experiences, mult.
About
building omnistudio omniscript OmniStudio OmniScript Creation and Validation Expert OmniStudio OmniScript builder for declarative step based guided digital experiences OmniScripts are the OmniStudio analog of Screen Flows multi step interactive processes that collect input orchestrate server side logic Integration Procedures DataRaptors and present results to the user all without code Scoring 120 points across 6 categories Thresholds 90 Deploy 67 89 Review 67 Block fix required In scope Creating OmniScripts from requirements element selection and PropertySetConfig design dependency analysis Integration Procedures DataRaptors data flow tracing 120 point validation scoring deployment and activation Out of scope Building FlexCards use building omnistudio flexcard creating Integration Procedures directly use building omnistudio integration procedure mapping full dependency trees use analyzing omnistudio dependencies deploying metadata to org use deploying metadata Input Description Default Type Process category e g ServiceRequest Enrollment None required SubType Specific variation e g NewCase UpdateAddress None required Language Locale for the OmniScript English Purpose Business proce.
- name: building-omnistudio-omniscript
- description: "OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital exp
- Expert OmniStudio OmniScript builder for declarative, step-based guided digital experiences. OmniScripts are the OmniStu
- Follow building-omnistudio-omniscript SKILL.md steps and documented constraints.
- Follow building-omnistudio-omniscript SKILL.md steps and documented constraints.
Building Omnistudio Omniscript by the numbers
- 1,929 all-time installs (skills.sh)
- +6 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #629 of 16,659 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
building-omnistudio-omniscript capabilities & compatibility
- Capabilities
- name: building omnistudio omniscript · description: "omnistudio omniscript creation and · expert omnistudio omniscript builder for declara · follow building omnistudio omniscript skill.md s
- Use cases
- orchestration
What building-omnistudio-omniscript says it does
name: building-omnistudio-omniscript
description: "OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital experiences, multi-step forms, or interactive processes that orchestrate Integratio
Expert OmniStudio OmniScript builder for declarative, step-based guided digital experiences. OmniScripts are the OmniStudio analog of Screen Flows: multi-step, interactive processes that collect input
npx skills add https://github.com/forcedotcom/sf-skills --skill building-omnistudio-omniscriptAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.9k |
|---|---|
| repo stars | ★ 763 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 24, 2026 |
| Repository | forcedotcom/sf-skills ↗ |
When should an agent use building-omnistudio-omniscript and what problem does it solve?
OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital experiences, multi-step forms, or interactive processes that orchestrate Integration Procedures a
Who is it for?
Developers invoking building-omnistudio-omniscript as documented in the skill source.
Skip if: Skip when requirements fall outside building-omnistudio-omniscript documented scope.
When should I use this skill?
OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital experiences, multi-step forms, or interactive processes that orchestrate Integration Procedures a
What you get
Outputs aligned with the building-omnistudio-omniscript SKILL.md workflow and stated deliverables.
- OmniProcess JSON
- OmniScript Step definitions
Files
building-omnistudio-omniscript: OmniStudio OmniScript Creation and Validation
Expert OmniStudio OmniScript builder for declarative, step-based guided digital experiences. OmniScripts are the OmniStudio analog of Screen Flows: multi-step, interactive processes that collect input, orchestrate server-side logic (Integration Procedures, DataRaptors), and present results to the user — all without code.
Quick Reference
Scoring: 120 points across 6 categories. Thresholds: ✅ 90+ (Deploy) | ⚠️ 67-89 (Review) | ❌ <67 (Block - fix required)
---
Scope
- In scope: Creating OmniScripts from requirements, element selection and PropertySetConfig design, dependency analysis (Integration Procedures, DataRaptors), data flow tracing, 120-point validation scoring, deployment and activation
- Out of scope: Building FlexCards (use
building-omnistudio-flexcard), creating Integration Procedures directly (usebuilding-omnistudio-integration-procedure), mapping full dependency trees (useanalyzing-omnistudio-dependencies), deploying metadata to org (usedeploying-metadata)
---
Required Inputs
Gather these before building:
| Input | Description | Default |
|---|---|---|
| Type | Process category (e.g., ServiceRequest, Enrollment) | None — required |
| SubType | Specific variation (e.g., NewCase, UpdateAddress) | None — required |
| Language | Locale for the OmniScript | English |
| Purpose | Business process this OmniScript guides | None — required |
| Target org | Org alias for deployment | Current default org |
| Data sources | Objects/APIs to query or update | Identify from requirements |
---
Core Responsibilities
1. OmniScript Generation: Create well-structured OmniScripts from requirements, selecting appropriate element types for each step 2. Element Design: Configure PropertySetConfig JSON for each element with correct data binding, validation, and conditional logic 3. Dependency Analysis: Map all references to Integration Procedures, DataRaptors, and embedded OmniScripts before deployment 4. Data Flow Analysis: Trace data through the OmniScript JSON structure — from prefill through user input to final save actions
---
CRITICAL: Orchestration Order
analyzing-omnistudio-dependencies → building-omnistudio-datamapper → building-omnistudio-integration-procedure → building-omnistudio-omniscript → building-omnistudio-flexcard (you are here: building-omnistudio-omniscript)
OmniScripts consume Integration Procedures and DataRaptors. Build those FIRST. FlexCards may launch OmniScripts — build FlexCards AFTER. Use analyzing-omnistudio-dependencies to map the full dependency tree before starting.
---
Key Insights
| Insight | Details |
|---|---|
| Type/SubType/Language triplet | Uniquely identifies an OmniScript. All three values are required and form the composite key. Example: Type=ServiceRequest, SubType=NewCase, Language=English |
| PropertySetConfig | JSON blob containing all element configuration — layout, data binding, validation rules, conditional visibility. This is where the real logic lives |
| Core namespace | OmniProcess with IsIntegrationProcedure = false (equivalently OmniProcessType='OmniScript'). Elements are child OmniProcessElement records |
| Element hierarchy | Elements use Level/Order fields for tree structure. Level 0 = Steps, Level 1+ = elements within steps. Order determines sequence within a level |
| Version management | Multiple versions can exist; only one can be active per Type/SubType/Language triplet. Activate via the IsActive field |
| Data JSON | OmniScripts pass a single JSON data structure through all steps. Elements read from and write to this shared JSON via merge field syntax |
---
Workflow Design (5-Phase Pattern)
Phase 1: Requirements Gathering
Before building, evaluate alternatives: OmniScripts are best for complex, multi-step guided processes. For simple single-screen data entry, consider Screen Flows. For data display without interaction, consider FlexCards.
Ask the user to gather:
- Type: The process category (e.g.,
ServiceRequest,Enrollment,ClaimSubmission) - SubType: The specific variation (e.g.,
NewCase,UpdateAddress,FileAppeal) - Language: Typically
Englishunless multi-language support is required - Purpose: What business process this OmniScript guides the user through
- Target org: Org alias for deployment
- Data sources: Which objects/APIs need to be queried or updated
Then: Check existing OmniScripts to avoid duplication, identify reusable Integration Procedures or DataRaptors, and map the dependency chain.
Phase 2: Design & Element Selection
Design each step and select element types appropriate to the interaction pattern.
Container Elements
| Element Type | Purpose | Key Config |
|---|---|---|
| Step | Top-level container for a group of UI elements; each Step is a page in the wizard | chartLabel, knowledgeOptions, show (conditional visibility) |
| Conditional Block | Show/hide a group of elements based on conditions | conditionType, show expression |
| Loop Block | Iterate over a data list and render elements for each item | loopData (JSON path to array) |
| Edit Block | Inline editing container for tabular data | editFields, dataSource |
Input Elements
| Element Type | Purpose | Key Config |
|---|---|---|
| Text | Single-line text input | label, placeholder, pattern (regex validation) |
| Text Area | Multi-line text input | label, maxLength, rows |
| Number | Numeric input with optional formatting | label, min, max, step, format |
| Date | Date picker | label, dateFormat, minDate, maxDate |
| Date/Time | Date and time picker | label, dateFormat, timeFormat |
| Checkbox | Boolean toggle | label, defaultValue |
| Radio | Radio button group for single selection | label, options (static or data-driven) |
| Select | Dropdown selection | label, options, optionSource (static/data) |
| Multi-select | Multiple item selection | label, options, maxSelections |
| Type Ahead | Search/autocomplete input | label, dataSource, searchField, minCharacters |
| Signature | Signature capture pad | label, penColor, backgroundColor |
| File | File upload | label, maxFileSize, allowedExtensions |
| Currency | Currency input with locale formatting | label, currencyCode, min, max |
| Email input with format validation | label, placeholder | |
| Telephone | Phone number input with masking | label, mask, placeholder |
| URL | URL input with format validation | label, placeholder |
| Password | Masked text input | label, minLength |
| Range | Slider input | label, min, max, step |
| Time | Time picker | label, timeFormat |
Display Elements
| Element Type | Purpose | Key Config |
|---|---|---|
| Text Block | Static content display (HTML supported) | textContent, HTMLTemplateId |
| Headline | Section heading | text, level (h1-h6) |
| Aggregate | Calculated summary display | aggregateExpression, format |
| Disclosure | Expandable/collapsible content | label, defaultExpanded |
| Image | Image display | imageURL, altText |
| Chart | Data visualization | chartType, dataSource |
Action Elements
| Element Type | Purpose | Key Config |
|---|---|---|
| DataRaptor Extract Action | Pull data from Salesforce | bundle, inputMap, outputMap |
| DataRaptor Load Action | Push data to Salesforce | bundle, inputMap |
| Integration Procedure Action | Call server-side Integration Procedure | ipMethod (Type_SubType), inputMap, outputMap, remoteOptions |
| Remote Action | Call Apex @RemoteAction or REST | remoteClass, remoteMethod, inputMap |
| Navigate Action | Page navigation or redirection | targetType, targetId, URL |
| DocuSign Envelope Action | Trigger DocuSign envelope | templateId, recipientMap |
| Email Action | Send email | emailTemplateId, recipientMap |
Logic Elements
| Element Type | Purpose | Key Config |
|---|---|---|
| Set Values | Variable assignment and data transformation | elementValueMap (key-value pairs) |
| Validation | Input validation rules with custom messages | validationFormula, errorMessage |
| Formula | Calculate values using formula expressions | expression, dataType |
| Submit Action | Final submission of collected data | postMessage, preTransformBundle, postTransformBundle |
Phase 3: Generation & Validation
Run scripts/check-duplicate-omniscript.sh <Type> <SubType> <Language> <org> to verify no duplicate Type/SubType/Language exists.
Build the OmniScript: 1. Create the OmniProcess record with Type, SubType, Language, and OmniProcessType='OmniScript' 2. Create OmniProcessElement child records for each Step (Level=0) 3. Create OmniProcessElement child records for each element within Steps (Level=1+, ordered by Order field) 4. Configure PropertySetConfig JSON for each element 5. Wire action elements to their Integration Procedures / DataRaptors
Validation (STRICT MODE):
- BLOCK: Missing Type/SubType/Language, circular OmniScript embedding, broken IP/DataRaptor references, missing required PropertySetConfig fields
- WARN: Steps with no elements, input elements without validation, missing error handling on actions, unused data paths, deeply nested elements (>4 levels)
Validation Report Format (6-Category Scoring 0-120):
Score: 102/120 ---- Very Good
-- Design & Structure: 22/25 (88%)
-- Data Integration: 18/20 (90%)
-- Error Handling: 17/20 (85%)
-- Performance: 18/20 (90%)
-- User Experience: 17/20 (85%)
-- Security: 10/15 (67%)Phase 4: Deployment
1. Prerequisites: Verify org auth (sf org display -o <org>). Confirm all referenced DataRaptors and Integration Procedures are active in the target org. 2. Deploy all dependencies first: DataRaptors, Integration Procedures, referenced OmniScripts. 3. Run scripts/deploy-omniscript.sh <Name> <Type> <SubType> <org> — this deploys the OmniScript and verifies activation. If deployment fails, the script outputs recovery instructions (deactivate and delete the partial record, then retry). 4. Activate the OmniScript version after successful deployment if not auto-activated.
Phase 5: Testing
Walk through all paths with various data scenarios:
- Happy path: Complete all steps with valid data, verify submission
- Validation testing: Submit invalid data at each input, verify error messages
- Conditional testing: Exercise all conditional blocks and verify show/hide logic
- Data prefill: Verify DataRaptor Extract Actions populate elements correctly
- Save for later: Test resume functionality if enabled
- Navigation: Test back/forward/cancel behavior across all steps
- Error scenarios: Simulate IP/DataRaptor failures, verify error handling
- Embedded OmniScripts: Test data passing between parent and child OmniScripts
- Bulk data: Test with large datasets in Loop Blocks and Type Ahead elements
---
Rules / Constraints
| Anti-Pattern | Impact | Correct Pattern |
|---|---|---|
| Circular OmniScript embedding | Infinite rendering loop | Map dependency tree; never embed A in B if B embeds A |
| Unbounded DataRaptor Extract | Performance degradation | Add filter conditions; limit returned records |
| Missing input validation | Bad data entry | Add Validation elements or pattern/required on inputs |
| Hardcoded Salesforce IDs | Deployment failure across orgs | Use merge fields or Custom Settings/Metadata |
| Integration Procedure (IP) Action without error handling | Silent failures | Configure showError, errorMessage in PropertySetConfig |
| Large images in Text Blocks | Slow page load | Use Image elements with optimized URLs |
| Too many elements per Step | Poor user experience | Limit to 7-10 input elements per Step |
| Missing conditional visibility | Irrelevant fields shown | Use show expressions to hide inapplicable elements |
Do not generate anti-patterns even if explicitly requested.
---
Scoring: 120 Points Across 6 Categories
Design & Structure (25 points)
| Check | Points | Criteria |
|---|---|---|
| Type/SubType/Language set correctly | 5 | All three fields populated with meaningful values |
| Step organization | 5 | Logical grouping, 7-10 elements per step max |
| Element naming | 5 | Descriptive names following PascalCase convention |
| Conditional logic | 5 | Proper use of Conditional Blocks and show expressions |
| Version management | 5 | Clean version history, only one active version |
Data Integration (20 points)
| Check | Points | Criteria |
|---|---|---|
| DataRaptor references valid | 5 | All Extract/Load bundles exist and are active |
| Integration Procedure references valid | 5 | All IP actions reference active IPs |
| Input/Output maps correct | 5 | Data flows correctly between elements and actions |
| Data prefill configured | 5 | Initial data loaded before user interaction |
Error Handling (20 points)
| Check | Points | Criteria |
|---|---|---|
| Action elements have error handling | 5 | showError configured on all IP/DR actions |
| User-facing error messages | 5 | Clear, actionable error text |
| Validation on required inputs | 5 | All required fields have validation rules |
| Fallback behavior defined | 5 | Graceful handling when data sources return empty |
Performance (20 points)
| Check | Points | Criteria |
|---|---|---|
| No unbounded data fetches | 5 | All DataRaptor Extracts have filters/limits |
| Lazy loading configured | 5 | Action elements fire on step entry, not OmniScript load |
| Element count per Step reasonable | 5 | No Step with >15 elements |
| Conditional rendering used | 5 | Elements hidden when not applicable (not just invisible) |
User Experience (20 points)
| Check | Points | Criteria |
|---|---|---|
| Logical step flow | 5 | Steps follow natural task progression |
| Input labels and help text | 5 | All inputs have clear labels and contextual help |
| Navigation controls | 5 | Back, Next, Cancel, Save for Later configured appropriately |
| Responsive layout | 5 | Elements configured for mobile and desktop breakpoints |
Security (15 points)
| Check | Points | Criteria |
|---|---|---|
| No sensitive data in client-side JSON | 5 | Passwords, SSNs, tokens kept server-side |
| IP actions use server-side processing | 5 | Sensitive logic in Integration Procedures, not client OmniScript |
| Field-level access respected | 5 | Data access matches user profile/permission set |
---
CLI Commands
See scripts/cli-reference.sh for the full command reference. Common commands:
# List active OmniScripts
sf data query -q "SELECT Id,Name,Type,SubType,Language,IsActive,VersionNumber FROM OmniProcess WHERE IsActive=true AND OmniProcessType='OmniScript' LIMIT 50" -o <org>
# Query elements for a specific OmniScript
sf data query -q "SELECT Id,Name,ElementType,Level,Order FROM OmniProcessElement WHERE OmniProcessId='<id>' ORDER BY Level,Order LIMIT 200" -o <org>
# Check OmniScript versions
sf data query -q "SELECT Id,VersionNumber,IsActive,LastModifiedDate FROM OmniProcess WHERE Type='<Type>' AND SubType='<SubType>' AND OmniProcessType='OmniScript' ORDER BY VersionNumber DESC LIMIT 10" -o <org>---
Cross-Skill Integration
| From Skill | To building-omnistudio-omniscript | When |
|---|---|---|
| analyzing-omnistudio-dependencies | -> building-omnistudio-omniscript | "Analyze dependencies before building OmniScript" |
| building-omnistudio-datamapper | -> building-omnistudio-omniscript | "DataRaptor ready, build the OmniScript that uses it" |
| building-omnistudio-integration-procedure | -> building-omnistudio-omniscript | "IP ready, wire it into the OmniScript action" |
| From building-omnistudio-omniscript | To Skill | When |
|---|---|---|
| building-omnistudio-omniscript | -> building-omnistudio-flexcard | "Build FlexCard that launches this OmniScript" |
| building-omnistudio-omniscript | -> deploying-metadata | "Deploy OmniScript to target org" |
| building-omnistudio-omniscript | -> analyzing-omnistudio-dependencies | "Map full dependency tree before deployment" |
| building-omnistudio-omniscript | -> building-omnistudio-integration-procedure | "Need a new IP for this OmniScript action" |
| building-omnistudio-omniscript | -> building-omnistudio-datamapper | "Need a DataRaptor for data prefill" |
---
Gotchas
| Issue | Resolution |
|---|---|
| Multi-language OmniScript | Create separate versions per Language with shared Type/SubType; use translation workbench for labels |
| Embedded OmniScript data passing | Map parent data JSON keys to child OmniScript input via prefillJSON; test data round-trip |
| Large Loop Block datasets | Paginate or limit DataRaptor results; consider server-side filtering in Integration Procedure (IP) |
| OmniScript in FlexCard flyout | Ensure FlexCard passes required context data; test flyout sizing |
| Community/Experience Cloud deployment | Verify OmniScript component is available in Experience Builder; check guest user permissions |
| Save & Resume (Save for Later) | Configure saveNameTemplate, saveExpireInDays; test resume with partial data |
| Versioning conflicts | Deactivate old version before activating new; never have two active versions for same Type/SubType/Language triplet |
| Custom LWC in OmniScript | Register LWC as OmniScript-compatible; follow omniscript-lwc namespace conventions |
| Namespaced orgs | If deploying into a managed OmniStudio package org, prefix bundle names and API names with the appropriate namespace (e.g., omnistudio__) |
OmniProcessType cannot be set on create | OmniProcessType is computed from IsIntegrationProcedure (false for OmniScripts); do not set it directly |
For common runtime troubleshooting (element not rendering, data not prefilling, IP action failing silently), see references/best-practices.md Section 8.
---
Notes
API: 66.0 | Mode: Strict (warnings block) | Scoring: Block deployment if score < 67
Required upstream skills: building-omnistudio-datamapper, building-omnistudio-integration-procedure
Optional skills: deploying-metadata, building-omnistudio-flexcard, analyzing-omnistudio-dependencies
Creating OmniScripts programmatically: Use REST API (sf api request rest --method POST --body @file.json). Required fields: Name, Type, SubType, Language, VersionNumber. OmniScripts default to IsIntegrationProcedure=false — do NOT set OmniProcessType directly (it is computed). The sf data create record --values flag cannot handle JSON textarea fields like PropertySetConfig. Create child OmniProcessElement records via REST API for each Step and element.
---
Output Expectations
Deliverables produced by this skill:
- OmniScript JSON (
assets/omni-process-omniscript.jsontemplate) — OmniProcess record ready for REST API creation - Step element JSON (
assets/omni-process-element-step.jsontemplate) — OmniProcessElement record for each Step (Level=0) - Element JSON (
assets/omni-process-element-text-block.jsonand similar) — OmniProcessElement records for child elements (Level=1+) - Validation report — 120-point score across 6 categories with pass/warn/block threshold result
---
Reference File Index
| File | When to read |
|---|---|
references/element-types.md | Phase 2 — Element selection: read before configuring PropertySetConfig for any element type |
references/best-practices.md | Phase 2-5 — Design patterns: read for step design, data prefill, validation, navigation, performance, and troubleshooting guidance |
assets/omni-process-omniscript.json | Phase 3 — Generation: use as the OmniProcess record template when building the OmniScript via REST API |
assets/omni-process-element-step.json | Phase 3 — Generation: use as the Step (Level=0) OmniProcessElement record template |
assets/omni-process-element-text-block.json | Phase 3 — Generation: use as the Text Block element template; adapt for other display element types |
scripts/check-duplicate-omniscript.sh | Phase 3 — Run before creating a new OmniScript to verify no duplicate Type/SubType/Language exists |
scripts/deploy-omniscript.sh | Phase 4 — Run to deploy OmniScript and verify activation; includes prerequisite checks and error recovery |
scripts/cli-reference.sh | Any phase — Full CLI command reference for querying, retrieving, deploying, and verifying OmniScripts |
{
"OmniProcessId": "{{ParentProcessId}}",
"Name": "{{StepName}}",
"Type": "Step",
"Description": "{{Description}}",
"IsActive": true,
"Level": 0,
"SequenceNumber": {{SequenceNumber}},
"PropertySetConfig": "{\"label\":\"{{StepLabel}}\",\"chartLabel\":\"\",\"errorMessage\":{\"custom\":[],\"default\":null},\"instructionKey\":\"\",\"knowledgeOptions\":{\"dataCategoryCriteria\":\"\",\"keyword\":\"\",\"publishStatus\":\"Online\",\"typeFilter\":\"\"},\"conditionType\":\"Hide if True\",\"show\":null,\"HTMLTemplateId\":\"\",\"remoteClass\":\"\",\"remoteMethod\":\"\",\"remoteOptions\":{},\"remoteTimeout\":30000,\"validationRequired\":\"Submit\"}"
}
{
"OmniProcessId": "{{ParentProcessId}}",
"Name": "{{ElementName}}",
"Type": "Text Block",
"Description": "{{Description}}",
"IsActive": true,
"Level": 1,
"SequenceNumber": {{SequenceNumber}},
"ParentElementId": "{{ParentStepId}}",
"PropertySetConfig": "{\"HTMLTemplateId\":\"\",\"dataJSON\":false,\"hide\":false,\"label\":\"{{Label}}\",\"readOnly\":false,\"show\":null,\"textBlock\":\"{{HTMLContent}}\"}"
}
{
"Name": "{{Type}}_{{SubType}}",
"Type": "{{Type}}",
"SubType": "{{SubType}}",
"Language": "English",
"VersionNumber": 1,
"IsActive": false,
"IsIntegrationProcedure": false,
"Description": "{{Description}}",
"PropertySetConfig": "{\"persistentComponent\":true,\"trackingCustomData\":{},\"enableLWCRuntime\":true,\"autoSaveOnStepNext\":false,\"autoFocus\":false,\"showConfirmation\":true,\"allowCancel\":true,\"cancelRedirectPageName\":\"\",\"cancelRedirectTemplateUrl\":\"\",\"cancelSource\":\"\",\"consoleTabLabel\":\"\",\"elementTypeToHTMLTemplateList\":[],\"knowledgeArticleTypeQueryFieldsMap\":{},\"lpiLayout\":\"\",\"message\":{},\"pubsub\":false,\"rtpSeed\":false,\"seedDataJSON\":{},\"sessionTimeout\":120,\"ssm\":false,\"timeTracking\":false}",
"WebComponentKey": "{{Type}}/{{SubType}}/English/1"
}
Credits & Acknowledgments
This skill reflects patterns and conventions established within the Salesforce OmniStudio platform and its practitioner community.
---
<!-- Parent: building-omnistudio-omniscript/SKILL.md -->
OmniScript Best Practices
Applies to: OmniStudio OmniScripts (OmniProcessType='OmniScript')
Companion: See element-types.md for PropertySetConfig reference per element type---
Table of Contents
1. Step Design Patterns 2. Data Prefill Strategies 3. Validation Patterns 4. Navigation Patterns 5. Performance Optimization 6. Embedding vs Linking OmniScripts 7. Naming Conventions 8. Error Handling 9. Testing Strategies 10. Security Considerations
---
1. Step Design Patterns
Wizard-Style (Multi-Step Sequential)
The default and most common pattern. Each Step represents a phase of the process, with linear forward progression.
When to use:
- Guided intake forms (service requests, applications, enrollments)
- Multi-phase data collection where later steps depend on earlier inputs
- Processes that benefit from chunking to reduce cognitive load
Design rules:
- Limit each Step to 7-10 input elements (cognitive load threshold)
- Group related fields together within a Step
- Place data-fetching actions (DataRaptor Extract, IP Action) at the beginning of the Step they serve
- Use descriptive Step labels that orient the user (e.g., "Contact Information", "Review & Submit")
- The final Step should be a review/confirmation screen
Example structure:
Step 1: "Account Selection" -> Type Ahead (account search) + DataRaptor Extract (prefill)
Step 2: "Service Details" -> Select, Text, Date inputs for the request
Step 3: "Attachments" -> File upload + Text Area for notes
Step 4: "Review & Submit" -> Text Blocks displaying collected data + Submit ActionSingle-Page (All Elements Visible)
All elements rendered on a single Step with no navigation between pages.
When to use:
- Simple forms with 5 or fewer inputs
- Quick-action modals launched from FlexCards
- Inline editing scenarios
Design rules:
- Use a single Step element containing all inputs
- Omit navigation buttons (no Next/Previous needed)
- Keep the total element count low to avoid scroll fatigue
- Consider whether a FlexCard with inline editing would be simpler
Conditional Branching
Steps are shown or hidden based on user input or data conditions.
When to use:
- Processes where the path varies by user selection (e.g., "New" vs "Existing" customer)
- Compliance workflows where certain sections only apply to specific scenarios
- Multi-product intake where product type determines required fields
Design rules:
- Use the
showproperty on Steps with conditional expressions - Reference data JSON values using merge field syntax:
%ShowStep3%or{ShowStep3} - Set controlling values early in the flow (Step 1 or data prefill)
- Test all permutations of the conditional paths
- Document the branching logic in Step descriptions
{
"show": {
"group": {
"operator": "AND",
"rules": [
{
"field": "CustomerType",
"condition": "=",
"data": "New"
}
]
}
}
}Hub-and-Spoke
A central Step allows navigation to sub-sections, each completing independently.
When to use:
- Complex case management with multiple independent sections
- Forms where the user may complete sections in any order
- Processes requiring non-linear data entry
Design rules:
- Central hub Step with Navigate Actions to each spoke
- Each spoke completes and returns to the hub
- Track section completion status in the data JSON
- Display completion indicators on the hub Step
---
2. Data Prefill Strategies
DataRaptor Extract Prefill
Use DataRaptor Extract Actions at the beginning of a Step to populate elements with existing Salesforce data.
Best practice:
- Place the Extract Action as the first element in the Step (lowest Order value)
- Configure
executionConditionFormulato skip the fetch if data already exists - Map Extract output keys to match element names for automatic binding
- Filter the Extract query to return only the needed fields
{
"bundle": "DR_ExtractAccountDetails",
"inputMap": {
"AccountId": "%SelectedAccountId%"
},
"outputMap": {
"AccountName": "AccountName",
"BillingAddress": "BillingAddress"
}
}Integration Procedure Prefill
Use IP Actions for complex prefill that requires server-side logic, aggregation, or external API calls.
Best practice:
- Set
remoteOptions.preTransformBundleif data needs shaping before display - Use
executionConditionFormulato avoid re-fetching on back navigation - Cache results in the data JSON so subsequent Steps can reference them without additional calls
Contextual Prefill (Launch Parameters)
OmniScripts can receive data when launched from FlexCards, Lightning pages, or URLs.
Best practice:
- Document all expected launch parameters in the OmniScript description
- Validate that required parameters are present; show an error Step if missing
- Use Set Values elements to normalize parameter formats before processing
Save & Resume Prefill
When "Save for Later" is enabled, the OmniScript restores the full data JSON on resume.
Best practice:
- Configure
saveNameTemplatefor meaningful save identifiers - Set
saveExpireInDaysto prevent stale saved instances - Test that all elements re-render correctly from saved JSON
- Handle edge cases where referenced data may have changed between save and resume
---
3. Validation Patterns
Element-Level Validation
Configure validation directly on input elements via PropertySetConfig.
| Property | Purpose | Example |
|---|---|---|
required | Field must have a value | "required": true |
pattern | Regex pattern match | "pattern": "^[A-Z]{2}\\d{6}$" |
min / max | Numeric range | "min": 1, "max": 100 |
minLength / maxLength | Text length range | "minLength": 5, "maxLength": 255 |
minDate / maxDate | Date range | "minDate": "TODAY", "maxDate": "+30" |
Validation Elements
Use Validation elements for cross-field and business rule validation.
Best practice:
- Place Validation elements at the end of a Step, before the navigation connector
- Write clear, user-actionable error messages
- Reference multiple fields in the validation formula for cross-field checks
- Group related validations in a single Validation element when possible
{
"validationFormula": "%EndDate% > %StartDate%",
"errorMessage": "End date must be after the start date."
}Step-Level Validation
Prevent the user from advancing to the next Step until all validations pass.
Best practice:
- Combine
requiredproperties on inputs with Validation elements for complex rules - Use the Step's
validationRequiredproperty to enforce completion - Display inline validation messages near the field, not only at the top of the page
Server-Side Validation
Use Integration Procedure Actions for validations that require database lookups or external checks.
Best practice:
- Display a loading indicator during server-side validation
- Handle timeout and error responses gracefully
- Cache validation results to avoid redundant server calls on back-navigation
---
4. Navigation Patterns
Standard Linear Navigation
Default back/forward progression through Steps.
Configuration:
allowSaveForLater: Enable save & resume functionalitycancelAction: Define behavior when user clicks Cancel (redirect URL or close modal)showStepChart: Display step progress indicatorstepChartPlacement: Position the step chart (top, left, right)
Conditional Step Skipping
Skip Steps that are not relevant based on collected data.
Best practice:
- Use the
showproperty on Steps rather than Navigate Actions for conditional paths - The OmniScript engine automatically skips hidden Steps during forward navigation
- Test that skipped Steps do not contribute invalid data to the JSON
Custom Navigation Buttons
Override default Next/Previous with Navigate Actions for non-linear flows.
Best practice:
- Maintain a consistent button layout across Steps
- Label navigation buttons with the destination Step name, not generic "Next"
- Disable the Previous button on the first Step
- Consider whether non-linear navigation will confuse the user
Cancel and Exit
Best practice:
- Prompt for confirmation before discarding entered data
- Offer "Save for Later" alongside Cancel when appropriate
- Redirect to a meaningful page after cancellation (not a blank screen)
---
5. Performance Optimization
Lazy Loading Elements
Configure action elements to execute only when their containing Step becomes visible.
Best practice:
- Set
executionConditionFormulaon DataRaptor Extract and IP Actions - Use Step-level activation triggers rather than OmniScript-level
onLoadactions - Prefetch only the data needed for the first Step on initial load
Conditional Visibility vs Conditional Rendering
| Approach | Behavior | Performance Impact |
|---|---|---|
show on elements | Element is not rendered in DOM | Lower memory, faster rendering |
| CSS visibility | Element is rendered but hidden | Higher memory, same load time |
Best practice:
- Use the
showproperty for elements that may not be needed at all - Avoid rendering large data tables or Loop Blocks that the user may never see
Data Volume in Loop Blocks
Loop Blocks render elements for each item in a data array. Large arrays degrade performance.
Best practice:
- Limit the data array to 50 items or fewer for interactive Loop Blocks
- Implement server-side pagination via Integration Procedures for large datasets
- Use Type Ahead elements instead of Loop Blocks when the user needs to search/select from a large list
Minimize Action Element Count
Each action element (DataRaptor, IP, Remote Action) represents a server round-trip.
Best practice:
- Combine multiple data fetches into a single Integration Procedure where possible
- Fetch all data needed for a Step in one action, not one action per field
- Use Set Values to derive calculated fields client-side instead of calling the server
Image and Static Content
Best practice:
- Host images on a CDN or Salesforce Static Resource rather than embedding base64 in Text Blocks
- Minimize HTML complexity in Text Block elements
- Use the Image element type instead of
<img>tags in Text Blocks
---
6. Embedding vs Linking OmniScripts
Embedding (Child OmniScript)
An OmniScript rendered inside another OmniScript as a reusable sub-process.
When to embed:
- The sub-process is a self-contained unit reused across multiple parent OmniScripts
- The parent needs data from the child's interaction (child data merges into parent JSON)
- The user should not leave the parent context
Design rules:
- Pass required data from parent to child via
prefillJSONmapping - Configure the child to suppress its own navigation when embedded
- Test data merge behavior: child data is added to the parent JSON under the child element's name
- Avoid embedding more than 2 levels deep (parent -> child -> grandchild is the practical limit)
- Watch for name collisions between parent and child data JSON keys
Linking (Navigate Action)
A Navigate Action redirects to a separate OmniScript in a new context.
When to link:
- The processes are independent and do not share a data context
- The user is transitioning from one workflow to a different one
- The target OmniScript is also used standalone (not just as a sub-component)
Design rules:
- Pass context data via URL parameters or the Navigate Action's
paramsproperty - The linked OmniScript starts fresh with its own data JSON
- Handle the return navigation (redirect back to the originating page if needed)
Decision Matrix
| Factor | Embed | Link |
|---|---|---|
| Data sharing needed | Yes | No |
| Reused as standalone | Sometimes | Yes |
| User stays in context | Yes | No |
| Performance concern | Adds to page weight | Separate page load |
| Depth > 2 levels | Avoid | Preferred |
---
7. Naming Conventions
OmniScript Type/SubType
- Type: Business domain or process category. Use
PascalCase. Examples:ServiceRequest,MemberEnrollment,ClaimProcessing - SubType: Specific variation or action. Use
PascalCase. Examples:CreateNew,UpdateAddress,FileAppeal - Language: Use standard locale codes. Default:
English
Element Names
- Use
PascalCasefor all element names - Prefix action elements with their type:
DRExtract_AccountInfo,IP_ValidateEligibility,Nav_ReturnToCase - Name Steps with the section they represent:
Step_ContactInfo,Step_ReviewSubmit - Name input elements descriptively:
FirstName,PreferredContactMethod,RequestedStartDate
Data JSON Keys
- Match element names for automatic binding
- Use consistent casing throughout the OmniScript
- Avoid special characters, spaces, and reserved words in key names
- Document the data JSON schema for complex OmniScripts
---
8. Error Handling
Action Element Errors
Every DataRaptor, Integration Procedure, and Remote Action element should handle failures.
Best practice:
- Set
showError: trueand provide a meaningfulerrorMessagein PropertySetConfig - Use
responseJSONPathto extract specific error details from the response - Implement a fallback Step that displays when critical actions fail
- Log errors server-side via an IP Action for monitoring
User Input Errors
Best practice:
- Show inline error messages immediately on invalid input (not only on Step advance)
- Use red visual indicators and position error text near the offending field
- Provide specific guidance on how to fix the error (not just "Invalid input")
Network and Timeout Errors
Best practice:
- Configure
remoteTimeouton IP Actions for long-running operations - Display a loading indicator during server calls
- Offer a retry option when transient errors occur
- If the OmniScript cannot continue, display a clear message with a support contact
---
9. Testing Strategies
Manual Testing Checklist
- [ ] Walk through all Steps with valid data (happy path)
- [ ] Attempt to advance with missing required fields
- [ ] Enter invalid data for each validated input
- [ ] Exercise all conditional branches (show/hide Steps and elements)
- [ ] Test with prefilled vs empty launch parameters
- [ ] Test Save for Later and Resume
- [ ] Verify data is correctly submitted/saved
- [ ] Test Cancel behavior and confirmation prompt
- [ ] Check rendering on mobile viewport
- [ ] Verify with different user profiles/permission sets
Integration Testing
- [ ] Verify all DataRaptor Extract Actions return expected data
- [ ] Verify all DataRaptor Load Actions create/update records correctly
- [ ] Verify all IP Actions execute and return expected responses
- [ ] Test with integration failures (disable a DataRaptor, verify error handling)
- [ ] Test with large data volumes in Loop Blocks
Cross-Browser and Device Testing
- [ ] Desktop: Chrome, Firefox, Safari, Edge
- [ ] Mobile: iOS Safari, Android Chrome
- [ ] Tablet: verify responsive layout breakpoints
- [ ] Community/Experience Cloud: verify guest and authenticated rendering
---
10. Security Considerations
Data Exposure
- OmniScript data JSON is client-side. Sensitive data (SSNs, passwords, tokens) should be processed server-side in Integration Procedures and never stored in the client JSON.
- Use
maskValueon sensitive input elements to prevent shoulder-surfing. - Strip sensitive fields from the data JSON before the Submit Action using Set Values.
Access Control
- OmniScript visibility is controlled by the page or component it is placed on, not by the OmniScript itself.
- Ensure Integration Procedures enforce record-level and field-level security (FLS).
- Do not rely on hiding Steps or elements as a security mechanism; the data JSON can be inspected client-side.
Input Sanitization
- Validate all user input before passing to DataRaptor Load or IP Actions.
- Use
pattern(regex) on text inputs to restrict input format. - Server-side IPs should validate input independently; do not trust client-side validation alone.
---
11. Common Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
| OmniScript not rendering | OmniScript is inactive or element hierarchy is broken | Check IsActive=true on the OmniProcess record; verify all Steps (Level=0) and child elements are correctly parented |
| Data not prefilling | DataRaptor Extract output mapping mismatch or wrong JSON path | Verify DataRaptor Extract output key names exactly match element names; check JSON path syntax in outputMap |
| IP action failing silently | Integration Procedure input shape mismatch or IP is inactive | Test the IP independently with the same inputMap payload; verify IP is active; check showError: true is set on the action element |
| Steps not showing | Conditional visibility expression on the Step evaluates incorrectly | Review the show expression on the Step element; log data JSON values to verify the controlling field is set |
---
Key Takeaways
1. Keep Steps focused: 7-10 elements maximum per Step. Split complex processes into more Steps rather than cramming elements. 2. Prefill early, validate often: Load data at the start of each Step and validate before allowing progression. 3. Error handling is not optional: Every server call needs a failure path. Every required input needs validation. 4. Performance is a design constraint: Lazy-load data, limit Loop Block iterations, and minimize server round-trips. 5. Embed sparingly, link freely: Embedding couples OmniScripts tightly. Reserve it for genuine sub-processes. 6. Security is server-side: The client JSON is not a trust boundary. Sensitive logic belongs in Integration Procedures.
<!-- Parent: building-omnistudio-omniscript/SKILL.md -->
OmniScript Element Type Reference
Applies to: OmniStudio OmniScripts (OmniProcessType='OmniScript')
Companion: See best-practices.md for design patterns and usage guidanceEach OmniScript element is stored as an OmniProcessElement child record. The ElementType field identifies the type, and the PropertySetConfig field contains a JSON blob with all configuration.
---
Table of Contents
1. Container Elements 2. Input Elements 3. Display Elements 4. Action Elements 5. Logic Elements 6. Common PropertySetConfig Properties
---
1. Container Elements
Step
Top-level container representing a page/screen in the OmniScript wizard. All other elements are children of a Step.
| Property | Type | Required | Description |
|---|---|---|---|
label | String | Yes | Display label shown in the step chart |
chartLabel | String | No | Shortened label for the step chart indicator |
show | Object | No | Conditional visibility expression |
knowledgeOptions | Object | No | Knowledge article sidebar configuration |
validationRequired | Boolean | No | Require all child validations to pass before advancing |
allowSaveForLater | Boolean | No | Enable save & resume on this Step |
errorMessage | String | No | Custom message when Step validation fails |
instruction | String | No | Help text displayed at the top of the Step |
cancelLabel | String | No | Custom label for the Cancel button |
nextLabel | String | No | Custom label for the Next button |
previousLabel | String | No | Custom label for the Previous button |
completeLabel | String | No | Custom label for the final Submit button |
showPersistentComponent | Array | No | Components visible across Steps (e.g., summary sidebar) |
{
"label": "Contact Information",
"chartLabel": "Contact",
"validationRequired": true,
"instruction": "Please provide your contact details.",
"nextLabel": "Continue to Service Details",
"show": {
"group": {
"operator": "AND",
"rules": [
{ "field": "HasContactInfo", "condition": "=", "data": "false" }
]
}
}
}Level: 0 (always top-level) Order: Determines the Step sequence in the wizard
---
Conditional Block
Groups elements that appear or disappear together based on a condition.
| Property | Type | Required | Description |
|---|---|---|---|
conditionType | String | Yes | "group" for complex conditions, "simpleFormula" for formula |
show | Object | Yes | Condition expression (same syntax as Step show) |
label | String | No | Display label for the block |
{
"conditionType": "group",
"show": {
"group": {
"operator": "AND",
"rules": [
{ "field": "CustomerType", "condition": "=", "data": "Business" }
]
}
}
}Level: 1+ (child of a Step)
---
Loop Block
Iterates over a data array and renders its child elements for each item.
| Property | Type | Required | Description |
|---|---|---|---|
loopData | String | Yes | JSON path to the data array (e.g., %LineItems%) |
label | String | No | Display label |
repeat | String | No | Merge field referencing array length or explicit count |
allowAdd | Boolean | No | Allow user to add items to the loop |
allowDelete | Boolean | No | Allow user to remove items from the loop |
minItems | Number | No | Minimum required items |
maxItems | Number | No | Maximum allowed items |
{
"loopData": "%OrderLines%",
"allowAdd": true,
"allowDelete": true,
"minItems": 1,
"maxItems": 20,
"label": "Order Line Items"
}Level: 1+ (child of a Step)
---
Edit Block
Provides inline editing of tabular data with row-level add/edit/delete.
| Property | Type | Required | Description |
|---|---|---|---|
editFields | Array | Yes | Fields available for editing |
dataSource | String | Yes | JSON path to the data array |
label | String | No | Table heading |
columns | Array | No | Column definitions (label, field, width) |
allowAdd | Boolean | No | Allow adding rows |
allowDelete | Boolean | No | Allow deleting rows |
{
"dataSource": "%ContactList%",
"editFields": ["FirstName", "LastName", "Email", "Phone"],
"columns": [
{ "label": "First Name", "field": "FirstName", "width": "25%" },
{ "label": "Last Name", "field": "LastName", "width": "25%" },
{ "label": "Email", "field": "Email", "width": "30%" },
{ "label": "Phone", "field": "Phone", "width": "20%" }
],
"allowAdd": true,
"allowDelete": true
}Level: 1+ (child of a Step)
---
2. Input Elements
Common Input Properties
All input elements share these base properties:
| Property | Type | Required | Description |
|---|---|---|---|
label | String | Yes | Field label displayed to the user |
required | Boolean | No | Whether the field must have a value |
readOnly | Boolean | No | Display value without allowing edit |
defaultValue | Mixed | No | Default value on load |
placeholder | String | No | Placeholder text in the empty field |
helpText | String | No | Tooltip or help text |
show | Object | No | Conditional visibility expression |
accessibleInPreview | Boolean | No | Include in review/confirmation Step |
hide | Boolean | No | Hide from display (still in data JSON) |
debounce | Number | No | Milliseconds to debounce input changes |
maskValue | Boolean | No | Mask the displayed value (for sensitive data) |
---
Text
Single-line text input.
| Property | Type | Description |
|---|---|---|
pattern | String | Regex pattern for validation |
patternErrorMessage | String | Error shown when pattern fails |
minLength | Number | Minimum character count |
maxLength | Number | Maximum character count |
inputType | String | HTML input type override (text, email, tel, url) |
{
"label": "First Name",
"required": true,
"placeholder": "Enter your first name",
"minLength": 2,
"maxLength": 80,
"pattern": "^[a-zA-Z\\s'-]+$",
"patternErrorMessage": "Name may only contain letters, spaces, hyphens, and apostrophes."
}---
Text Area
Multi-line text input.
| Property | Type | Description |
|---|---|---|
rows | Number | Number of visible text rows |
maxLength | Number | Maximum character count |
richText | Boolean | Enable rich text editing |
{
"label": "Description",
"rows": 4,
"maxLength": 32000,
"placeholder": "Describe the issue in detail..."
}---
Number
Numeric input with formatting.
| Property | Type | Description |
|---|---|---|
min | Number | Minimum value |
max | Number | Maximum value |
step | Number | Increment step |
format | String | Display format (e.g., "0,0.00") |
precision | Number | Decimal precision |
{
"label": "Quantity",
"required": true,
"min": 1,
"max": 9999,
"step": 1,
"format": "0,0",
"defaultValue": 1
}---
Currency
Currency input with locale formatting.
| Property | Type | Description |
|---|---|---|
currencyCode | String | ISO currency code (e.g., "USD") |
min | Number | Minimum value |
max | Number | Maximum value |
precision | Number | Decimal precision |
{
"label": "Requested Amount",
"required": true,
"currencyCode": "USD",
"min": 0.01,
"max": 1000000,
"precision": 2
}---
Date
Date picker input.
| Property | Type | Description |
|---|---|---|
dateFormat | String | Display format (e.g., "MM/DD/YYYY") |
minDate | String | Earliest selectable date ("TODAY", "-30", "2025-01-01") |
maxDate | String | Latest selectable date ("TODAY", "+365") |
{
"label": "Requested Start Date",
"required": true,
"dateFormat": "MM/DD/YYYY",
"minDate": "TODAY",
"maxDate": "+365"
}---
Date/Time
Combined date and time picker.
| Property | Type | Description |
|---|---|---|
dateFormat | String | Date display format |
timeFormat | String | Time display format ("HH:mm", "hh:mm A") |
minDate | String | Earliest selectable date |
maxDate | String | Latest selectable date |
{
"label": "Appointment Date & Time",
"dateFormat": "MM/DD/YYYY",
"timeFormat": "hh:mm A"
}---
Time
Time-only picker.
| Property | Type | Description |
|---|---|---|
timeFormat | String | Time display format |
minuteInterval | Number | Interval for minute selection (e.g., 15, 30) |
{
"label": "Preferred Time",
"timeFormat": "hh:mm A",
"minuteInterval": 15
}---
Checkbox
Boolean toggle input.
| Property | Type | Description |
|---|---|---|
defaultValue | Boolean | Initial checked state |
checkLabel | String | Label displayed next to the checkbox |
{
"label": "Terms and Conditions",
"checkLabel": "I agree to the terms and conditions",
"required": true,
"defaultValue": false
}---
Radio
Radio button group for single selection.
| Property | Type | Description |
|---|---|---|
options | Array | Static options [{ "name": "label", "value": "val" }] |
optionSource | Object | Data-driven options from a DataRaptor or data JSON |
orientation | String | "horizontal" or "vertical" |
{
"label": "Contact Preference",
"required": true,
"orientation": "vertical",
"options": [
{ "name": "Email", "value": "Email" },
{ "name": "Phone", "value": "Phone" },
{ "name": "Mail", "value": "Mail" }
]
}---
Select
Dropdown selection input.
| Property | Type | Description |
|---|---|---|
options | Array | Static options [{ "name": "label", "value": "val" }] |
optionSource | Object | Data-driven options configuration |
multiselect | Boolean | Allow multiple selections (use Multi-select element instead) |
{
"label": "State",
"required": true,
"options": [
{ "name": "California", "value": "CA" },
{ "name": "New York", "value": "NY" },
{ "name": "Texas", "value": "TX" }
]
}---
Multi-select
Multiple item selection input.
| Property | Type | Description |
|---|---|---|
options | Array | Static options |
optionSource | Object | Data-driven options configuration |
maxSelections | Number | Maximum number of selections allowed |
minSelections | Number | Minimum number of selections required |
{
"label": "Interested Products",
"options": [
{ "name": "Product A", "value": "ProdA" },
{ "name": "Product B", "value": "ProdB" },
{ "name": "Product C", "value": "ProdC" }
],
"maxSelections": 3
}---
Type Ahead
Search/autocomplete input that queries a data source as the user types.
| Property | Type | Description |
|---|---|---|
dataSource | String | DataRaptor bundle or IP to query |
searchField | String | Field to search against |
displayField | String | Field to display in results |
valueField | String | Field to store as the selected value |
minCharacters | Number | Minimum characters before search fires |
maxResults | Number | Maximum results to display |
debounce | Number | Milliseconds to debounce search requests |
inputMap | Object | Additional parameters to pass to the data source |
{
"label": "Search Account",
"dataSource": "DR_SearchAccounts",
"searchField": "Name",
"displayField": "Name",
"valueField": "Id",
"minCharacters": 3,
"maxResults": 10,
"debounce": 300,
"inputMap": {
"RecordType": "Customer"
}
}---
Email input with built-in format validation.
| Property | Type | Description |
|---|---|---|
placeholder | String | Placeholder text |
pattern | String | Override regex (default email pattern is built-in) |
{
"label": "Email Address",
"required": true,
"placeholder": "name@example.com"
}---
Telephone
Phone number input with optional masking.
| Property | Type | Description |
|---|---|---|
mask | String | Input mask pattern (e.g., "(999) 999-9999") |
placeholder | String | Placeholder text |
{
"label": "Phone Number",
"mask": "(999) 999-9999",
"placeholder": "(555) 123-4567"
}---
URL
URL input with built-in format validation.
| Property | Type | Description |
|---|---|---|
placeholder | String | Placeholder text |
pattern | String | Override regex for URL validation |
{
"label": "Website",
"placeholder": "https://www.example.com"
}---
Password
Masked text input for sensitive values.
| Property | Type | Description |
|---|---|---|
minLength | Number | Minimum password length |
maxLength | Number | Maximum password length |
pattern | String | Complexity regex |
patternErrorMessage | String | Error when pattern fails |
{
"label": "Temporary PIN",
"required": true,
"minLength": 6,
"maxLength": 6,
"pattern": "^\\d{6}$",
"patternErrorMessage": "PIN must be exactly 6 digits."
}---
Range
Slider input for selecting a value within a range.
| Property | Type | Description |
|---|---|---|
min | Number | Minimum value |
max | Number | Maximum value |
step | Number | Increment step |
showValue | Boolean | Display the selected value |
{
"label": "Satisfaction Rating",
"min": 1,
"max": 10,
"step": 1,
"showValue": true,
"defaultValue": 5
}---
Signature
Signature capture pad for e-signatures.
| Property | Type | Description |
|---|---|---|
penColor | String | Drawing color (hex or name) |
backgroundColor | String | Pad background color |
width | Number | Pad width in pixels |
height | Number | Pad height in pixels |
clearLabel | String | Label for the clear button |
{
"label": "Customer Signature",
"required": true,
"penColor": "#000000",
"backgroundColor": "#FFFFFF",
"width": 400,
"height": 150,
"clearLabel": "Clear Signature"
}---
File
File upload input.
| Property | Type | Description |
|---|---|---|
maxFileSize | Number | Maximum file size in bytes |
allowedExtensions | String | Comma-separated allowed extensions |
maxFiles | Number | Maximum number of files |
uploadLabel | String | Custom upload button label |
{
"label": "Supporting Documents",
"maxFileSize": 5242880,
"allowedExtensions": "pdf,jpg,png,docx",
"maxFiles": 5,
"uploadLabel": "Upload Document"
}---
3. Display Elements
Text Block
Static content display. Supports HTML and merge fields.
| Property | Type | Description |
|---|---|---|
textContent | String | HTML content to display |
HTMLTemplateId | String | Reference to an HTML template |
sanitize | Boolean | Sanitize HTML content |
{
"textContent": "<p>Welcome, <strong>%FirstName%</strong>. Please review the following information.</p>",
"sanitize": true
}---
Headline
Section heading element.
| Property | Type | Description |
|---|---|---|
text | String | Heading text |
level | Number | Heading level (1-6, maps to h1-h6) |
{
"text": "Account Details",
"level": 2
}---
Aggregate
Calculated summary display based on data in the OmniScript JSON.
| Property | Type | Description |
|---|---|---|
aggregateExpression | String | Calculation expression |
format | String | Display format |
dataType | String | Result data type ("number", "currency", "percent") |
{
"label": "Total Amount",
"aggregateExpression": "SUM(%OrderLines:Amount%)",
"format": "$0,0.00",
"dataType": "currency"
}---
Disclosure
Expandable/collapsible content section.
| Property | Type | Description |
|---|---|---|
label | String | Clickable section header |
defaultExpanded | Boolean | Initial expand state |
{
"label": "Additional Information",
"defaultExpanded": false
}---
Image
Image display element.
| Property | Type | Description |
|---|---|---|
imageURL | String | URL to the image |
altText | String | Alternative text for accessibility |
width | String | Display width (px or %) |
height | String | Display height (px or %) |
{
"imageURL": "/resource/CompanyLogo",
"altText": "Company Logo",
"width": "200px"
}---
Chart
Data visualization element.
| Property | Type | Description |
|---|---|---|
chartType | String | Chart type ("bar", "pie", "line", "donut") |
dataSource | String | JSON path to chart data |
labelField | String | Field for chart labels |
valueField | String | Field for chart values |
title | String | Chart title |
{
"chartType": "pie",
"dataSource": "%CoverageBreakdown%",
"labelField": "CoverageType",
"valueField": "Amount",
"title": "Coverage Distribution"
}---
4. Action Elements
DataRaptor Extract Action
Executes a DataRaptor Extract to pull data from Salesforce.
| Property | Type | Required | Description |
|---|---|---|---|
bundle | String | Yes | DataRaptor Extract bundle name |
inputMap | Object | No | Input parameters mapped from data JSON |
outputMap | Object | No | Output mapping to data JSON keys |
executionConditionFormula | String | No | Formula to conditionally execute |
showError | Boolean | No | Display error on failure |
errorMessage | String | No | Custom error message |
responseJSONPath | String | No | Path to extract from response |
sendOnlyIfNotEmpty | Boolean | No | Skip if input values are empty |
{
"bundle": "DR_ExtractAccountDetails",
"inputMap": {
"AccountId": "%SelectedAccountId%"
},
"outputMap": {
"AccountName": "AccountName",
"BillingStreet": "BillingStreet",
"BillingCity": "BillingCity",
"BillingState": "BillingState",
"BillingPostalCode": "BillingPostalCode"
},
"executionConditionFormula": "IF(%SelectedAccountId% != '', true, false)",
"showError": true,
"errorMessage": "Unable to retrieve account details. Please try again."
}---
DataRaptor Load Action
Executes a DataRaptor Load to write data to Salesforce.
| Property | Type | Required | Description |
|---|---|---|---|
bundle | String | Yes | DataRaptor Load bundle name |
inputMap | Object | No | Input parameters from data JSON |
executionConditionFormula | String | No | Conditional execution formula |
showError | Boolean | No | Display error on failure |
errorMessage | String | No | Custom error message |
{
"bundle": "DR_CreateServiceRequest",
"inputMap": {
"AccountId": "%SelectedAccountId%",
"Subject": "%RequestSubject%",
"Description": "%RequestDescription%",
"Priority": "%RequestPriority%"
},
"showError": true,
"errorMessage": "Failed to create the service request. Please contact support."
}---
Integration Procedure Action
Calls a server-side Integration Procedure.
| Property | Type | Required | Description |
|---|---|---|---|
ipMethod | String | Yes | IP identifier ("Type_SubType" format) |
inputMap | Object | No | Input parameters from data JSON |
outputMap | Object | No | Output mapping to data JSON keys |
remoteOptions | Object | No | Execution options (chainable, preTransform, postTransform) |
executionConditionFormula | String | No | Conditional execution formula |
showError | Boolean | No | Display error on failure |
errorMessage | String | No | Custom error message |
remoteTimeout | Number | No | Timeout in milliseconds |
responseJSONPath | String | No | Path to extract from response |
preTransformBundle | String | No | DataRaptor to transform input before sending |
postTransformBundle | String | No | DataRaptor to transform output after receiving |
{
"ipMethod": "Eligibility_CheckMember",
"inputMap": {
"MemberId": "%MemberId%",
"ServiceDate": "%RequestedDate%"
},
"outputMap": {
"IsEligible": "EligibilityResult",
"PlanName": "MemberPlan",
"CopayAmount": "EstimatedCopay"
},
"remoteOptions": {
"preTransformBundle": "DR_TransformEligibilityInput",
"postTransformBundle": "DR_TransformEligibilityOutput"
},
"remoteTimeout": 30000,
"showError": true,
"errorMessage": "Eligibility check failed. Please verify member ID and try again."
}---
Remote Action
Calls an Apex @RemoteAction method or REST endpoint.
| Property | Type | Required | Description |
|---|---|---|---|
remoteClass | String | Yes | Apex class name |
remoteMethod | String | Yes | Method name |
inputMap | Object | No | Input parameters |
outputMap | Object | No | Output mapping |
remoteOptions | Object | No | Execution options |
showError | Boolean | No | Display error on failure |
{
"remoteClass": "CustomEligibilityService",
"remoteMethod": "checkEligibility",
"inputMap": {
"memberId": "%MemberId%"
},
"outputMap": {
"result": "EligibilityResult"
},
"showError": true
}---
Navigate Action
Navigates to another page, OmniScript, or URL.
| Property | Type | Required | Description |
|---|---|---|---|
targetType | String | Yes | "OmniScript", "URL", "Record", "FlexCard" |
targetId | String | Conditional | Record ID or OmniScript Type_SubType_Language |
URL | String | Conditional | Target URL (when targetType is "URL") |
params | Object | No | Parameters to pass to the target |
openInNewTab | Boolean | No | Open in a new browser tab |
{
"targetType": "OmniScript",
"targetId": "ServiceRequest_FollowUp_English",
"params": {
"CaseId": "%CreatedCaseId%",
"AccountId": "%SelectedAccountId%"
}
}---
Email Action
Sends an email using a Salesforce email template.
| Property | Type | Required | Description |
|---|---|---|---|
emailTemplateId | String | Yes | Email template ID or developer name |
recipientMap | Object | No | Recipient field mappings |
senderAddress | String | No | Override sender address |
{
"emailTemplateId": "ServiceRequestConfirmation",
"recipientMap": {
"toAddress": "%ContactEmail%",
"whatId": "%CreatedCaseId%"
}
}---
DocuSign Envelope Action
Triggers a DocuSign envelope for e-signature.
| Property | Type | Required | Description |
|---|---|---|---|
templateId | String | Yes | DocuSign template ID |
recipientMap | Object | Yes | Signer mappings |
prefillTabs | Object | No | Pre-populated tab values |
{
"templateId": "abc123-template-id",
"recipientMap": {
"signer1": {
"name": "%CustomerName%",
"email": "%CustomerEmail%"
}
}
}---
5. Logic Elements
Set Values
Assigns values to data JSON keys. Used for data transformation, defaults, and computed values.
| Property | Type | Required | Description |
|---|---|---|---|
elementValueMap | Object | Yes | Key-value pairs to set in the data JSON |
executionConditionFormula | String | No | Conditional execution |
{
"elementValueMap": {
"FullName": "CONCAT(%FirstName%, ' ', %LastName%)",
"SubmissionDate": "TODAY()",
"Status": "Submitted",
"RequestId": "CONCAT('SR-', %CaseNumber%)"
}
}---
Validation
Validates data using a formula expression. Blocks Step advancement when validation fails.
| Property | Type | Required | Description |
|---|---|---|---|
validationFormula | String | Yes | Formula that must evaluate to true to pass |
errorMessage | String | Yes | Error displayed when validation fails |
{
"validationFormula": "%EndDate% > %StartDate%",
"errorMessage": "End date must be after the start date."
}Multiple conditions example:
{
"validationFormula": "AND(%Age% >= 18, %Age% <= 120)",
"errorMessage": "Age must be between 18 and 120."
}---
Formula
Calculates a value using a formula expression and stores the result in the data JSON.
| Property | Type | Required | Description |
|---|---|---|---|
expression | String | Yes | Formula expression |
dataType | String | No | Result type ("number", "text", "boolean", "date") |
decimalPlaces | Number | No | Decimal precision for number results |
{
"label": "TotalWithTax",
"expression": "%SubTotal% * (1 + %TaxRate% / 100)",
"dataType": "number",
"decimalPlaces": 2
}---
Submit Action
Final submission action that processes collected data. Typically the last element in the last Step.
| Property | Type | Required | Description |
|---|---|---|---|
postMessage | String | No | Success message displayed after submission |
postSuccessMessage | String | No | Message shown on the post-submit screen |
preTransformBundle | String | No | DataRaptor to transform data before submission |
postTransformBundle | String | No | DataRaptor to transform data after submission |
submitLabel | String | No | Custom label for the submit button |
validationRequired | Boolean | No | Re-validate all Steps before submitting |
redirectPageName | String | No | Page to redirect after submission |
redirectTemplateUrl | String | No | URL template for redirect |
{
"postMessage": "Your service request has been submitted successfully.",
"preTransformBundle": "DR_PrepareSubmission",
"postTransformBundle": "DR_ProcessResponse",
"submitLabel": "Submit Request",
"validationRequired": true,
"redirectTemplateUrl": "/case/%CreatedCaseId%"
}---
6. Common PropertySetConfig Properties
These properties apply across multiple element types.
Conditional Visibility (show)
Controls whether an element is rendered.
{
"show": {
"group": {
"operator": "AND",
"rules": [
{ "field": "CustomerType", "condition": "=", "data": "Business" },
{ "field": "AnnualRevenue", "condition": ">", "data": "1000000" }
]
}
}
}Operators: AND, OR Conditions: =, !=, >, <, >=, <=, contains, starts with, ends with, is null, is not null
Nested Groups
{
"show": {
"group": {
"operator": "OR",
"rules": [
{ "field": "Status", "condition": "=", "data": "Active" },
{
"group": {
"operator": "AND",
"rules": [
{ "field": "Status", "condition": "=", "data": "Pending" },
{ "field": "HasApproval", "condition": "=", "data": "true" }
]
}
}
]
}
}
}Merge Fields
Reference data JSON values in element configuration using %FieldName% syntax.
| Syntax | Description |
|---|---|
%FieldName% | Direct reference to a data JSON key |
%Step1:FieldName% | Qualified reference with Step prefix |
%LoopBlock:CurrentItem:FieldName% | Reference within a Loop Block iteration |
%ParentOmni:FieldName% | Reference to parent OmniScript data (when embedded) |
%UserInfo:FirstName% | Current user information |
Layout Properties
| Property | Type | Description |
|---|---|---|
colSize | Number | Column width (1-12 grid system) |
offset | Number | Column offset (1-12) |
horizontalAlign | String | "left", "center", "right" |
verticalAlign | String | "top", "middle", "bottom" |
Data Binding
| Property | Type | Description |
|---|---|---|
JSONPath | String | Custom JSON path for storing the element value |
responseJSONPath | String | Path to extract from action response |
inputMap | Object | Maps data JSON values to action input parameters |
outputMap | Object | Maps action output to data JSON keys |
---
Quick Reference: Element Type to OmniProcessElement.ElementType
| Display Name | ElementType Value | Category |
|---|---|---|
| Step | Step | Container |
| Conditional Block | Conditional Block | Container |
| Loop Block | Loop Block | Container |
| Edit Block | Edit Block | Container |
| Text | Text | Input |
| Text Area | Text Area | Input |
| Number | Number | Input |
| Currency | Currency | Input |
| Date | Date | Input |
| Date/Time | Date/Time | Input |
| Time | Time | Input |
| Checkbox | Checkbox | Input |
| Radio | Radio | Input |
| Select | Select | Input |
| Multi-select | Multi-select | Input |
| Type Ahead | Type Ahead | Input |
Email | Input | |
| Telephone | Telephone | Input |
| URL | URL | Input |
| Password | Password | Input |
| Range | Range | Input |
| Signature | Signature | Input |
| File | File | Input |
| Text Block | Text Block | Display |
| Headline | Headline | Display |
| Aggregate | Aggregate | Display |
| Disclosure | Disclosure | Display |
| Image | Image | Display |
| Chart | Chart | Display |
| DataRaptor Extract Action | DataRaptor Extract Action | Action |
| DataRaptor Load Action | DataRaptor Load Action | Action |
| Integration Procedure Action | Integration Procedure Action | Action |
| Remote Action | Remote Action | Action |
| Navigate Action | Navigate Action | Action |
| Email Action | Email Action | Action |
| DocuSign Envelope Action | DocuSign Envelope Action | Action |
| Set Values | Set Values | Logic |
| Validation | Validation | Logic |
| Formula | Formula | Logic |
| Submit Action | Submit Action | Logic |
#!/bin/bash
# Verify no duplicate Type/SubType/Language exists before creating a new OmniScript.
# Usage: ./check-duplicate-omniscript.sh <Type> <SubType> <Language> <org>
# Example: ./check-duplicate-omniscript.sh ServiceRequest NewCase English myOrg
TYPE="${1:?Usage: $0 <Type> <SubType> <Language> <org>}"
SUBTYPE="${2:?}"
LANGUAGE="${3:?}"
ORG="${4:?}"
sf data query \
-q "SELECT Id,Name,Type,SubType,Language,IsActive,VersionNumber FROM OmniProcess WHERE Type='${TYPE}' AND SubType='${SUBTYPE}' AND Language='${LANGUAGE}' AND OmniProcessType='OmniScript' LIMIT 10" \
-o "${ORG}"
#!/bin/bash
# OmniScript CLI command reference. Not meant to be run directly.
# Copy individual commands as needed. Replace <org>, <id>, <Type>, <SubType>, <Name> with actual values.
# List active OmniScripts
sf data query -q "SELECT Id,Name,Type,SubType,Language,IsActive,VersionNumber FROM OmniProcess WHERE IsActive=true AND OmniProcessType='OmniScript' LIMIT 50" -o <org>
# Query all elements for a specific OmniScript (ordered by hierarchy)
sf data query -q "SELECT Id,Name,ElementType,PropertySetConfig,Level,Order FROM OmniProcessElement WHERE OmniProcessId='<id>' ORDER BY Level,Order LIMIT 200" -o <org>
# Retrieve OmniScript metadata from org
sf project retrieve start -m "OmniScript:<Name>" -o <org>
# Deploy OmniScript metadata to org
sf project deploy start -m "OmniScript:<Name>" -o <org>
# Check all versions of a specific OmniScript
sf data query -q "SELECT Id,VersionNumber,IsActive,LastModifiedDate FROM OmniProcess WHERE Type='<Type>' AND SubType='<SubType>' AND OmniProcessType='OmniScript' ORDER BY VersionNumber DESC LIMIT 10" -o <org>
# Verify active version after deployment
sf data query -q "SELECT Id,Name,Type,SubType,Language,IsActive,VersionNumber FROM OmniProcess WHERE Type='<Type>' AND SubType='<SubType>' AND OmniProcessType='OmniScript' AND IsActive=true LIMIT 5" -o <org>
#!/bin/bash
# Deploy an OmniScript and verify activation.
# Usage: ./deploy-omniscript.sh <Name> <Type> <SubType> <org>
# Example: ./deploy-omniscript.sh ServiceRequest_NewCase_English ServiceRequest NewCase myOrg
# Run AFTER deploying all dependencies (DataRaptors, Integration Procedures).
NAME="${1:?Usage: $0 <Name> <Type> <SubType> <org>}"
TYPE="${2:?}"
SUBTYPE="${3:?}"
ORG="${4:?}"
echo "Step 1: Verify prerequisites — check org auth"
sf org display -o "${ORG}" || { echo "ERROR: Org '${ORG}' is not authenticated. Run: sf org login web --alias ${ORG}"; exit 1; }
echo "Step 2: Deploy OmniScript metadata"
sf project deploy start -m "OmniScript:${NAME}" -o "${ORG}"
if [ $? -ne 0 ]; then
echo "ERROR: Deployment failed. To recover:"
echo " 1. Check the error message above for the specific cause."
echo " 2. If a partial OmniProcess record was created, deactivate and delete it:"
echo " sf data delete record -s OmniProcess -w \"Name='${NAME}'\" -o ${ORG}"
echo " 3. Fix the issue and re-run this script."
exit 1
fi
echo "Step 3: Verify activation"
sf data query \
-q "SELECT Id,Name,Type,SubType,Language,IsActive,VersionNumber FROM OmniProcess WHERE Type='${TYPE}' AND SubType='${SUBTYPE}' AND OmniProcessType='OmniScript' AND IsActive=true LIMIT 5" \
-o "${ORG}"
Related skills
Forks & variants (1)
Building Omnistudio Omniscript has 1 known copy in the catalog totaling 508 installs. They canonicalize to this original listing.
- forcedotcom - 508 installs
FAQ
What is building-omnistudio-omniscript?
OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital experiences, multi-step forms, or interactive processes that orchestrate Inte
When should I use building-omnistudio-omniscript?
OmniStudio OmniScript creation and validation with 120-point scoring. Use when building guided digital experiences, multi-step forms, or interactive processes that orchestrate Inte
Is building-omnistudio-omniscript safe to install?
Review the Security Audits panel on this page before production use.