Daniwoo· 100% Salesforce-native LMS · Available on AppExchange

SCORM in Salesforce: what actually works

Guide 8 September 2026 13 min read
BM Brice MbouaniFounder, Daniwoo
A SCORM course playing inside a Salesforce Lightning page in the Daniwoo player, with the module menu on the left and recommended content on the right.

You've got a finished course from your authoring tool, a .zip in hand, and Salesforce won't take it. You've tried Files. You've tried attaching it to a record. Nothing plays. If you search "scorm salesforce", you'll find Trailblazer Community threads asking exactly this question, some of them sitting unanswered since 2020. This article is the answer those threads never got.

I build and maintain a SCORM engine that runs inside Salesforce orgs in production, including at enterprise scale. What follows is not vendor theory. It's the architecture that makes SCORM work in Salesforce, plus four failures I've personally debugged: a zip packaged one folder too deep, a replay that silently erased a completion, a learner with a score of 100 and a status stuck on "incomplete", and iOS Safari refusing to carry authentication into a new tab.

TL;DR: Salesforce has no native SCORM runtime: you need a player app. SCORM 1.2 still powers the overwhelming majority of real-world launches (92% of SCORM Cloud registrations in 2025 were SCORM, per Rustici's SCORM Cloud data), so support it first. The failures you'll actually meet are mundane: a manifest zipped one folder too deep, a replay that silently downgrades a completion, a score of 100 with a status stuck on "incomplete", and iOS Safari refusing to pass auth to a new tab. This guide covers each one, from production experience.

This article is part of the complete guide to running an LMS inside Salesforce.

Does Salesforce support SCORM?

No. Salesforce does not support SCORM natively, in any cloud, in any edition. Salesforce Files will store your .zip, but storing is not playing. Rich text fields won't render it. Salesforce Enablement (the sales programs product) doesn't include a SCORM runtime either. To run SCORM inside Salesforce, you need a player application, typically installed from the AppExchange.

The reason is architectural, not a missing checkbox. SCORM is not a file format that a viewer can open the way a PDF reader opens a PDF. A SCORM package is a small web application that expects to be launched by a runtime environment. At launch, the course's JavaScript searches its parent frames for an API object (named API in SCORM 1.2, API_1484_11 in SCORM 2004). Through that object, the course reads and writes tracking data: status, score, session time, suspend data for resume. No API object, no tracking. Often no launch at all, because many courses refuse to start when they can't find the runtime.

That's why a file store can never be enough. Salesforce Files can hold the bytes, but it doesn't unzip the package, serve its HTML entry point, inject the runtime API, or persist the tracking calls anywhere. A SCORM player app does all four. The practical takeaway: if your evaluation checklist says "Can Salesforce host SCORM?", rewrite it as "Which SCORM player runs inside our Salesforce org, and where does the tracking data land?" The second question is the one that decides whether you can report on training natively instead of syncing data from an external LMS.

How SCORM playback actually works inside Salesforce

Every working SCORM setup in Salesforce follows the same pattern: the course content is hosted and unzipped somewhere web-servable, a player component embeds it in an iframe on a Lightning or Experience Cloud page, a JavaScript runtime intercepts the course's API calls, and the tracking data is written to Salesforce records. Once you see this pipeline, every vendor demo and every debugging session gets easier to reason about.

Here's the sequence, step by step:

  1. Upload and extraction. You upload the .zip. The platform unzips it and reads imsmanifest.xml, the package's table of contents, to find the launchable entry point (usually an HTML file).
  2. Launch. A learner opens the course. The player renders an iframe pointing at that entry point and exposes the SCORM API object where the course expects to find it.
  3. Runtime conversation. As the learner progresses, the course calls the API: initialize, set status, set score, save suspend data, commit, terminate. The runtime buffers and forwards these calls.
  4. Persistence in Salesforce. The player writes the results to Salesforce objects: a completion record per learner per course, carrying status, score, and time spent.

Step 4 is the entire point of running SCORM inside Salesforce rather than beside it. Because completions land as records in your org, they behave like any other Salesforce data: visible in standard reports, aggregated in dashboards, and available to Flow. Completion of a compliance module can trigger the same automation as a closed Opportunity. That is what a native SCORM player for Salesforce buys you over an external LMS with a connector: no sync jobs, no duplicate identity mapping, no "the LMS says complete but Salesforce doesn't know yet".

The same SCORM module playing on a branded Experience Cloud learning portal, with the learner's academy navigation on top.
The same SCORM package, playing on a branded Experience Cloud academy: one runtime, every surface.

SCORM 1.2 vs 2004 vs cmi5: what to require in 2026

Require SCORM 1.2 and SCORM 2004 support from any player you evaluate, and treat cmi5 as your forward trajectory, not your baseline. That ordering isn't nostalgia. It's what the launch data says people actually run.

In 2025, 92% of SCORM Cloud registrations were SCORM (all versions combined), with xAPI, cmi5 and AICC sharing the rest, per Rustici's SCORM Cloud data. Within that SCORM share, 1.2 remains the majority format. Rustici's earlier look at the same dataset put SCORM 1.2 at the lion's share of the millions of monthly launches on SCORM Cloud, with xAPI and cmi5 growing but still small, per Rustici's earlier analysis of the same dataset. One honest caveat: SCORM Cloud's user base skews toward teams working with standards-based content, so treat these numbers as describing that population rather than a census of all e-learning. Even with that bias, the gap is too wide to explain away.

92% SCORM
SCORM (all versions) 92%xAPI / cmi5 / AICC 8%
Share of SCORM Cloud registrations, 2025, per Rustici's SCORM Cloud data.

Why does a 2001 specification still dominate? Because SCORM 1.2 is the format every authoring tool exports by default, every LMS accepts, and every content vendor ships when in doubt. It's the USB-A of e-learning: old, limited, everywhere.

2001SCORM 1.2 20042004 2nd Ed. 20063rd Ed. 20094th Ed. 2013xAPI 2016cmi5
Two decades of e-learning standards (dates per scorm.com).

The version history, per scorm.com: SCORM 1.2 shipped in 2001. SCORM 2004 followed with its 2nd, 3rd and 4th Editions in 2004, 2006 and 2009, adding a richer status model (more on that below) and sequencing. xAPI arrived in 2013 to track learning beyond the browser, and cmi5 in 2016 to marry xAPI's flexibility with SCORM-style LMS launch semantics.

My practical recommendation for a 2026 evaluation:

  • SCORM 1.2: mandatory. It's what your content library and your vendors will actually hand you.
  • SCORM 2004: mandatory. Its separated completion and success statuses matter for compliance reporting, and newer authoring tool output increasingly uses it.
  • cmi5/xAPI: a roadmap question, not a blocker. Ask vendors where it sits on their roadmap. If you're formalizing this into procurement questions, our LMS RFP question kit has a standards section you can lift directly.

Packaging: why your zip gets rejected

In our support queue, the single most common reason a SCORM upload fails has nothing to do with Salesforce: imsmanifest.xml isn't at the root of the zip. Before you blame the player, open your zip and check the first level.

I've lost count of how many "your player rejected my course" tickets ended the same way. The symptom is always identical: the upload fails or the platform reports that no manifest was found, and the customer is certain the package is fine because "it came straight from the authoring tool". The diagnosis takes thirty seconds. Open the zip. Instead of imsmanifest.xml sitting at level zero, there's a single folder, say my-course/, and the manifest is inside it. What happened is simple: the authoring tool exported the course into a folder, and someone right-clicked that folder and compressed it. The zip now contains a folder containing a course, and a spec-compliant player looks for the manifest at the root, finds nothing, and rejects the package. The fix is equally simple: go inside the exported folder, select all the files (imsmanifest.xml and everything alongside it), and zip that selection. The manifest must be at level zero of the archive.

Before any upload, run this checklist:

  1. Open the zip and confirm imsmanifest.xml is at the root, not nested inside a folder.
  2. Confirm the entry point exists. The manifest's resource entry references a launch file (often index.html or story.html); make sure it's present at the path the manifest declares.
  3. Watch for macOS artifacts. Archives created in Finder can include __MACOSX/ folders and .DS_Store files. Most players tolerate them, but strict ones don't.
  4. Test outside Salesforce first. A neutral test environment such as SCORM Cloud's free tier tells you in one upload whether the package itself is sound. If it fails there, the problem is the package, not the player.
  5. Re-export rather than hand-edit. If the manifest itself is malformed, fix the project in the authoring tool and re-export. Hand-editing imsmanifest.xml is how one problem becomes three.

Completed vs passed: reading SCORM status correctly

"Completed" and "passed" are two different questions, and SCORM 2004 answers them with two different fields. Completed means the learner got through the content. Passed means they met the success criterion, usually a quiz score. A learner can be completed and failed (finished everything, flunked the quiz) or passed and incomplete (aced the early quiz, skipped the final pages). If your compliance report only reads one of the two, it's answering a question you didn't ask.

The two SCORM versions model this differently, and the element names matter when you're debugging:

SCORM 1.2SCORM 2004
Status element(s)cmi.core.lesson_status (one field)cmi.completion_status + cmi.success_status (two fields)
Possible valuespassed, completed, failed, incomplete, browsed, not attemptedCompletion: completed, incomplete, not attempted, unknown. Success: passed, failed, unknown
ModelCompletion and success collapsed into a single valueCompletion and success tracked independently
ConsequenceA course reports either completed or passed, rarely both; the LMS must interpretAn LMS can report "finished the content" and "met the passing score" as separate facts

Element names per the scorm.com Run-Time Reference.

SCORM 1.2 crams everything into cmi.core.lesson_status, so a course typically reports passed or completed but not both, and the LMS has to decide what each implies. SCORM 2004 fixed this by splitting the concepts, which is genuinely better for compliance reporting. It also created a new failure mode.

Here's the case that taught me to distrust raw status values. A customer escalated a learner record that made no sense: score of 100, cmi.completion_status reading incomplete, cmi.success_status reading unknown. The learner had visibly finished the course and aced the quiz, and the data said neither. My first instinct was a bug in our runtime, so I pulled the raw API call log. The runtime was innocent: the course itself never set completion or success. It dutifully wrote the score and then went silent. The root cause was upstream, in the authoring tool's publish settings. The course had been published with no completion criterion and no passing score defined, so the content had no rule telling it when to declare completed or passed. It reported what it knew (the score) and left the rest at defaults. The fix was a republish with explicit criteria: complete on X% of slides viewed, passed at Y% quiz score. Data coherent on the next attempt.

The general lessons:

  • A high score with incomplete/unknown status almost always means missing publish criteria in the authoring tool, not a broken player. Check the publish settings before opening a support ticket.
  • An LMS should reconcile defensively. Sensible rules: treat passed as implying completion for progress purposes; when a passing score is configured on the LMS side and success comes back unknown, evaluate the raw score against it; and always store the raw values alongside the interpretation so audits can see what the course actually said.
  • Decide before launch which status gates your compliance requirement: completion, success, or both. That decision belongs in your rollout plan, not in a post-audit scramble.
SCORM completion tracking inside Salesforce: learner records with separate completion status and success status, scores, progress and time spent.
Completion and success tracked as separate facts on real learner records: note the first row, completed yet failed.

Tracking that doesn't lie: the completion lock

A serious SCORM engine never lets a replay downgrade a terminal status. Once a learner is completed, passed, or failed, that state is locked: later attempts to write a lower state are logged for diagnostics but not applied. If your tracking data can silently move backwards, you don't have tracking, you have a rumor.

I learned this from a confused admin, not from the spec. A learner had completed a module weeks earlier; it showed complete in reports, everyone moved on. Then the learner did something perfectly reasonable: reopened the module to look something up. The course, as many SCORM packages do, started a fresh session and immediately wrote incomplete, which is technically correct from the course's point of view: this session was incomplete. Our engine, at the time, took the course at its word and updated the record. The completion evaporated. From the admin's chair it looked like data loss, and functionally it was: a compliance completion had been erased by the act of revisiting the content. The diagnosis was straightforward once we replayed the API calls, and the fix was a rule, not a patch: terminal states are final. The engine now refuses any transition from completed/passed/failed back to incomplete, records the attempted downgrade in a log so nothing is hidden, and keeps the learner's earned status intact. This is Daniwoo's default behavior today, precisely because we shipped without it once.

When you evaluate any SCORM player, put this scenario in your test script: complete a module, reopen it, close it partway through, then check the record. If the status moved backwards, keep shopping. And ask the harder follow-up: when a downgrade is blocked, is the attempt logged? Silent refusal is better than silent corruption, but logged refusal is what you want when an auditor asks questions. For compliance training, where a completion record may be the artifact a regulator inspects, this single behavior separates trustworthy platforms from risky ones. The scale side of this rule, why acting on terminal transitions is also what keeps tracking writes from locking up shared records, is covered in the LMS tracking at scale guide.

The iOS lesson: keep playback in one context

On mobile, never architect SCORM playback to open in a new browser tab. Keep it embedded in the same browsing context as the app the learner is already authenticated in. This rule exists because I broke it.

The symptom arrived as a vague bug report: "courses don't work on iPhone." On desktop, everything was fine. On Android, fine. On Salesforce Mobile on iOS, learners who launched a course got broken playback and no tracking. The diagnosis took a while because nothing was failing loudly; the content simply behaved as if the learner were a stranger. The root cause turned out to be a platform behavior, not a code bug: on iOS Safari, a new tab does not reliably inherit the authentication context of the page that opened it. Our player at the time popped course content into a new tab for more screen space. The parent page knew who the learner was; the new tab didn't, so protected content and tracking calls failed. The fix was architectural, not a workaround: we stopped opening new tabs and embedded playback directly in the page, inside the same browsing context where the learner's session already lives. Full-screen feel came from layout, not from a new window. Playback and tracking on iOS have been solid since.

The transferable lesson for anyone building or buying: authentication context is a per-browsing-context asset on iOS, and any architecture that hops contexts mid-session will eventually strand a user. When you evaluate a player, test the full flow on a real iPhone through the Salesforce Mobile app, not just in a desktop browser with responsive mode. If mobile learning matters to your rollout, and for field sales and service teams it usually matters most, this test belongs in your proof of concept, not your post-launch backlog.

Delivering SCORM on Experience Cloud

Yes, you can deliver SCORM on an Experience Cloud site, and it's a question the community has been asking without a good public answer since at least 2020. The mechanism is the same as internal delivery: a packaged player exposed as a component that you drop onto Experience Cloud pages. Partners, customers, and franchisees then take courses on your branded site, and their completions land in the same org as everything else.

Three things deserve attention before you commit:

  • Licensing. External learners need Experience Cloud licenses (member-based or login-based), and the player app's own licensing must cover external users. Ask the vendor explicitly; per-user pricing models differ for community users.
  • Guest users. Unauthenticated (guest) access is where plans go to die. Tracking requires knowing who the learner is, and Salesforce's guest user security model is deliberately restrictive. Plan for authenticated learners; treat guest delivery as a separate, harder problem.
  • Sharing and visibility. Decide which audiences see which courses, and verify the player respects Salesforce sharing rather than implementing its own parallel permission scheme. One security model is a feature; two is a liability.

The payoff is significant: partner enablement and customer education tracked in the same reports as internal training, with no external LMS and no identity bridge to maintain.

Reporting: SCORM data in native dashboards

Because a native player writes completions as Salesforce records, SCORM reporting is just Salesforce reporting. No connector, no nightly sync, no CSV exports from a separate LMS. This is the quiet superpower of the whole architecture, and the reason the earlier plumbing is worth getting right.

Concretely, completion records carry the learner, the course, the status, the score, and time spent. From there:

  • Standard reports and dashboards answer the operational questions: completion rate by team, overdue compliance modules, average quiz scores by region. Your admins already know how to build these; there's nothing LMS-specific to learn.
  • Flow automation turns completions into events. A completion record being created or updated can trigger the same automation as any record change: notify a manager, assign the next module, update a certification field on the Contact, or feed a readiness metric on the User.
  • Cross-object insight is where it gets interesting. Training data living next to CRM data means you can put learning activity and business outcomes on the same dashboard: course completions alongside win rates, certification status alongside case resolution times. An external LMS can't do this without an integration project; in-org data does it with a report builder.

The status semantics from earlier matter here. Build your compliance reports on the reconciled status your platform stores, know whether your requirement is completion or success, and keep raw SCORM values available for audit. A dashboard is only as honest as the tracking engine feeding it.

FAQ

Does Salesforce support SCORM natively?

Not natively. No Salesforce cloud or edition includes a SCORM runtime; Salesforce Files can store a package but cannot play it or track it. You need a SCORM player application, typically installed from the AppExchange, which embeds the content and writes tracking data to Salesforce records.

How can I upload a SCORM file into Salesforce?

Through a SCORM player app, not through Files. Install a player from the AppExchange, then use its upload interface: it unzips the package, validates imsmanifest.xml, and makes the course launchable. Before uploading, open your zip and confirm the manifest is at the root of the archive; a manifest nested one folder deep is the most common cause of rejected uploads.

Can I embed SCORM on an Experience Cloud site?

Yes, via a packaged player exposed as an Experience Cloud component. External learners take courses on your branded site and completions are tracked in your org. Verify two things up front: that your Experience Cloud licenses and the app's licensing cover external users, and that learners will be authenticated, because guest-user delivery is significantly harder to secure and track.

SCORM completed vs passed: what's the difference?

Completed means the learner finished the content; passed means they met the success criterion, such as a minimum quiz score. SCORM 2004 tracks them separately (cmi.completion_status and cmi.success_status), so a learner can be completed but failed, or passed but incomplete. SCORM 1.2 collapses both into a single cmi.core.lesson_status field. Decide which one your compliance requirement actually depends on before you build reports.

How do I track SCORM completion in Salesforce reports?

With a native player, completions are Salesforce records, so you use standard report and dashboard builders: filter by course, group by team, chart completion rates over time. You can also trigger Flows on completion records to automate notifications, follow-up assignments, or certification updates. No external BI tool or LMS export is required.

Conclusion

Salesforce won't run your SCORM zip on its own, but with a player app the combination is stronger than a standalone LMS: real playback, honest tracking, and completions that live next to your CRM data where reports and Flows can use them. The failures that will actually bite you are the four covered here: manifests zipped one level too deep, replays that downgrade completions, statuses that contradict scores, and mobile sessions that lose their authentication context. Every one of them is avoidable once you know to test for it.

See SCORM running natively in your org

Real playback, honest tracking, and completions that live next to your CRM data. Book a demo with the team that built the engine described in this article.

Book a demo

About the author. Brice Mbouani is the founder of Daniwoo and a Salesforce engineer. He designed and built the SCORM engine described in this article, which runs in production Salesforce orgs at organizations including KPMG. The four incidents recounted here are from his own debugging sessions.

Get new articles by email

Practical guidance on running learning inside Salesforce. No spam, unsubscribe anytime.

By subscribing you agree to receive emails from Daniwoo about running learning inside Salesforce. Unsubscribe at any time from any email.