What suspend data is
SCORM gives a course exactly one place to store its own state between sessions: cmi.suspend_data, a single string. The bookmark element (lesson_location in 1.2, cmi.location in 2004) is tiny and meant for "which page"; everything else — quiz answers in progress, visited pages, branch decisions, video positions, shuffled question order — gets serialised into suspend data by the authoring tool or converter. The LMS stores the string verbatim and hands it back when the learner resumes. It has no idea what is inside it, and it does not promise to warn you when it will not fit.
The caps, by version and edition
| Specification | Cap on cmi.suspend_data |
|---|---|
| SCORM 1.2 | 4,096 characters |
| SCORM 2004 2nd Edition | 4,000 characters |
| SCORM 2004 3rd / 4th Edition | 64,000 characters |
Three practical notes. The 2004 2nd Edition cap is smaller than 1.2's — migrating a course "up" to 2004 can shrink its storage if the platform is 2nd Edition. Characters are not bytes: state stored as JSON with multi-byte characters can hit platform limits earlier than a character count suggests, because some LMSs enforce the limit on the stored byte length of their database column. And the cap applies to the whole string on every write — there is no appending; the course rewrites the full state each time.
How the failure actually looks
Almost no platform returns an error when the string is too long — the conformant response would be error 405 or a failed SetValue, but the common real-world behaviours are worse: silently truncating the string at the cap, or accepting it in the session and storing a truncated copy. Either way the failure appears one session later, in someone else's words: "the course forgot my progress", "it sent me back to the start", "my quiz answers disappeared halfway through". By then the truncated state often no longer parses (truncated JSON is invalid JSON), so the course falls back to a fresh start — which is why the symptom is usually a total reset rather than a partial one.
Because the failure is delayed and learner-specific, it does not show up in a quick author-side test of page one. It shows up when a learner gets far enough into the course for the state to outgrow the cap. The way to catch it before shipping is to measure: our conformance report shows peak suspend-data size against the cap for the target version (the check reads, for example, "3.1 KB of 64 KB"), and the free tester shows every write as it happens.
What courses put in there
Converted and authored courses typically store: the full visited-page map (often one entry per page, the biggest consumer in long courses), in-progress and submitted answers per question, question order for shuffled banks, media positions, and completion flags per section. A 90-page handbook conversion with a 25-question assessment sits naturally in the 3–6 KB range — fine for 2004 3rd/4th, over the line for 1.2. This is one of the five questions that should decide which SCORM version you build.
Staying under the cap
In descending order of effect:
Store less, not smaller. Drop per-page timestamps and redundant flags; a visited map plus current position reconstructs most of what long formats store. Completion of a linear section can be derived from position instead of stored per page.
Encode compactly. A JSON object with named keys ("{"page_12":{"visited":true}}") is several times the size of a bitfield or a compact positional string. Base64-packed bitfields for visited maps and answer states are the standard trick; some tools additionally compress before encoding.
Do not store what the LMS already stores. Score, status, location, and interactions have their own elements. Duplicating them in suspend data spends the budget twice.
Build for the right version. If measured state genuinely needs more than 4 KB and the destination platform supports 2004 3rd/4th Edition, build 2004 — that is the honest fix, not aggressive encoding.
Related: exit and entry
Suspend data only comes back if the attempt was suspended. In 1.2 the course must set cmi.core.exit to suspend before finishing (in 2004, cmi.exit, and a nav request of suspendAll); the LMS then reports entry as resume on the next launch and returns the stored string. Courses that leave exit empty end the attempt on some platforms — the suspend data is gone even though it was written correctly and was under the cap. When "lost progress" is not a size problem, it is nearly always this: an exit value problem. The full failure catalogue is in why SCORM completions go missing.