SfSkills Domains Docs GitHub

Home / omnistudio / omniscript-session-state

omniscript-session-state

Use when an OmniScript must persist mid-flow state across refresh, navigation, multi-device resume, or abandonment recovery. Covers session objects, staging data, OmniScript tracking, and resume URLs. NOT for OmniScript UI step layout — use omnistudio/omniscript-design-patterns. NOT for general Flow pause/resume — use flow/pause-elements-and-wait-events.

Open the skill folder on GitHub


OmniScript Session State

Long-running OmniScripts — onboarding, quote configuration, compliance questionnaires, benefits applications — lose users when a refresh wipes progress. OmniStudio ships native Save for Later, and most teams either under-use it (rebuilding a session store that was not needed) or over-use it (putting regulated PII into a store they cannot lawfully delete from). This skill covers the one constraint that decides between those, plus the four platform behaviours that make save-and-resume fail in production after passing in test.


The Decision That Determines Everything Else

Can you delete this state on your own schedule?

OmniScriptSavedSession is a real standard object — present in the object reference from API 51.0 through 67.0 — and it is marked:

"This object and associated records are only for internal use. Don't perform any create, edit, or delete operations on this object."

So native Save for Later is a store you can populate but cannot lawfully manage. This sits in the object reference rather than in the Save for Later documentation, which is why teams find it during an audit rather than during design.

SituationStore
Retention obligation, cross-session queries, or a guest audiencea custom object you own
Authenticated, low sensitivity, "let the user come back"native Save for Later — a configuration, not a project

Building a custom store for the second case is over-engineering. Using the native store for the first case is an audit finding.


Four Behaviours That Fail Only In Production

These come from OmniScript Save for Later — Considerations and Limitations (see the sourcing caveat in references/well-architected.md).

1. Saved sessions are bound to the OmniScript version. Sessions are tied to the definition version active when they were created. Deactivate and reactivate an OmniScript and previously saved sessions do not resume as the same instance — a new instance is created, and older saved instances remain stored in the system. A routine defect fix is therefore a data-loss event for every in-flight user, plus a permanent addition to a store you cannot purge. Treat any activation change with in-flight sessions as a migration.

2. Save fails above 4,194,304 characters (4 MB) — and the network payload is significantly larger than the visible Data JSON, so inspecting the debug panel understates it. The failure signature is characteristic: fine in test, fine through step 4, intermittent at step 8, consistently failing at step 11, for the users with the most entered data.

3. Save configuration must be on the parent OmniScript. In an embedded composition (isOmniScriptEmbeddable = true on the children), configuring save on a child is a silent no-op. The designer accepts it; nothing persists.

4. Two users on one session is unsupported — and not blocked. Editing and saving the same session by multiple Community users is not supported; a second user's save can cause data inconsistencies or save errors when the original user resumes. The second save is accepted, so the damage surfaces later, to a different user, and gets diagnosed as flakiness.


Keep The Payload To The Answers

The 4 MB ceiling is fixed, so the only lever is what goes under it.

CategoryTreatment
The user's answerspersist
Lookup data — catalogs, code tables, picklist option setsre-fetch on resume from a cacheable Integration Procedure
File contentstore the document, keep an id
Derived values recomputable from answersprune

Typical reduction is an order of magnitude, and resume gets faster as a side effect. Measure the real request payload at the last step, not the Data JSON at a middle step.


Platform Cache Is Not A Session Store

"Session state" and "session cache" share a word, and the word is doing far too much work. Session cache's documented properties disqualify it for user input:

PropertyConsequence
Max TTL 28,800 s (8 hours)no multi-day resume
Expires at TTL or when the user session expires, whichever comes firstlogout destroys it
"Cache isn't persisted. There's no guarantee against data loss."eviction is normal operation
"Data in the cache isn't encrypted."PII in plaintext
Max single cached item 100 KBlong scripts may not fit

Cache accelerates reads the script performs. It does not hold what the user typed.


Custom Session Object Shape

When you own the store, the schema decision that matters is which fields you encrypt — because Shield encryption restricts SOQL filtering.

Application_Session__c
    Answers_JSON__c    Long Text Area   ENCRYPTED    <- the payload
    SSN_Token__c       Text             tokenized, not the value
    ExpiresAt__c       DateTime         PLAINTEXT    <- the purge filters here
    Status__c          Picklist         PLAINTEXT    <- and here
    Version__c         Number           concurrency detection
    LastSavedAt__c     DateTime

The fields you filter on are never the fields you encrypt. The purge job then deletes rows whose sensitive contents it never has to read.

On save, compare the in-memory Version__c to the stored value: match → write and increment; mismatch → route to an explicit conflict branch. Never silently overwrite.


In the URL      : an opaque random token indexing a server-side row
Never in the URL: answers in any encoding; PII; a raw session record Id;
                  anything still valid tomorrow
On the server   : store a HASH of the token, bound to its subject,
                  expiring in hours not days, single-use where the flow allows
On the page     : set a referrer policy — any outbound link can otherwise
                  leak the token in the Referer header

Base64 is a rename, not an encryption. And Experience Cloud session lifetime and OmniScript session lifetime are independent: the platform can log a user out while the script still believes it has a session, so the resume path must verify identity rather than assume it.


  1. Answer the deciding question first: does a retention obligation, a

    cross-session query, or a guest audience attach to this state? If yes, you need a custom object — native Save for Later cannot be lawfully purged.

  2. Define the state schema as the user's answers only. Everything the script

    fetched to display those answers is a re-fetch on resume, not a persisted value. Measure the request payload at the final step against the 4 MB ceiling.

  3. Configure save on the parent OmniScript and at step boundaries — not

    on a child, and not on input change. Each save posts the whole payload.

  4. Design the resume path: opaque token in the URL, hash stored server-side,

    short expiry, referrer policy on the page, explicit re-authentication branch for Experience Cloud and guest flows.

  5. Model concurrency explicitly. Handoff between users is a record-ownership

    change, not a shared session. If concurrent editing is genuinely required, use a custom object with a Version__c field and a conflict branch.

  6. Set retention as a compliance decision confirmed with the data owner, and

    give the object a plaintext ExpiresAt__c plus a scheduled purge that references it. For guest flows, purge session state in the same job as the intake row so the two cannot drift.

  7. Plan every OmniScript activation change as a migration when in-flight

    sessions exist: count them, decide whether the change can wait, notify users before the deploy, and record orphaned-instance growth as a retention risk.


Review Checklist


Worked Examples (see references/examples.md)

Common Gotchas (see references/gotchas.md)

Top LLM Anti-Patterns (full list in references/llm-anti-patterns.md)


Official Sources Used

See references/well-architected.md for the full source list, including an explicit caveat about which Save for Later facts could not be fetched directly.

Package files