**Update - 10/09/2019**
The Chrome team has decided to delay the rollout of this feature. They have confirmed that this will now go out with Chrome 80. Based on their release cadence of every 6 weeks, that should be February 4th.
Hopefully this will give customers more time to put any patches or new Engine releases through testing and into production.
_________________________________________
The Problem
In an effort to improve browser performance when navigating between pages, Google Chrome has decided to remove the ability of scripts to perform synchronous requests during the beforeunload and unload events of a page. This change will be coming to users with version 78 of Chrome, which is scheduled for release on October 22nd. Once this goes live, there is a potential that the final exit postback from Engine's SCORM player will be blocked, and some learner progress data may be lost.
Who is Affected
The short answer is: potentially every Engine customer, regardless of Engine version. However, this affects a specific launch and exit scenario that may not apply to the bulk of users.
The following conditions must be met for this issue to come into play:
- The learner must be using Google Chrome 78 (or above).
- The course must be a SCORM course.
Courses from other learning standards do not rely on the player window's exit routine to send data, and so should not be affected. It is possible, though, that some content tries to make its own synchronous requests during the unload of the content page, but that is outside of our control in Engine. - The learner must exit the course by closing, or navigating away from, the window/frame that contains Engine's SCORM player page.
Customers who launch with the SCO Launch Type set to FRAMESET may be more susceptible to this, as there is a single window with both the player, and the content inside it in an iframe.
If the learner clicks an exit button in the course or in our player UI, or closes the popup content window (if launching with SCO Launch Type set to NEW_WINDOW), then our exit routine is not triggered by the unload of the player page, and so should still complete successfully, even with this update.
Impact
When a user closes Engine’s SCORM player page, and an exit hasn't already been triggered by some other method, the player will send a final exit postback to record any last-minute changes to the state of the registration. This can also include the values from ‘rolling up’ the status to the registration-level properties for completion, success, score, and duration.
In order to guarantee that this exit postback request is sent, even when closing the browser window containing the player, Engine uses synchronous requests in the beforeunload (or possibly the unload) event of the page. With synchronous requests, the page must wait until the request completes before taking any further action, and so we are mostly assured it will finish before the page closes. Until now, this has been a reliable way of guaranteeing that this request completes.
If this exit postback is blocked, however, the registration may stay in an incomplete status, even though the user completed the course. It's also possible that other data recorded in the last few seconds of the learner's interaction with the course would be lost, even when not completed.
Mitigation
For all customers on Engine 2017.1 or above, reach out to us to get the latest maintenance release of your version. We have implemented a change to the player so that if our exit postback is blocked by Chrome, we will fallback to other mechanisms for sending the request that do work.
For customers on older versions of Engine pre-2017.1, we will work with you to either patch the player's Javascript to add this fallback mechanism, or help you start the process of upgrading Engine to a newer version that has it. Contact us: support@rusticisoftware.com.
There are also a few steps that can be taken to turn off this new behavior in Chrome itself, so that no changes are necessary to the player for now:
- Chrome has a flag that can be modified to change this behavior in a user's browser. The user can navigate to chrome://flags/#allow-sync-xhr-in-page-dismissal in the browser and enable it.
Note: in Chrome 77, there is a preview setting #enable-forbid-sync-xhr-in-page-dismissal that can be used to test the behavior before the release goes out. - This flag can also be set using the AllowSyncXHRInPageDismissal enterprise policy flag, if that's something being used by your organization.
- There is also a temporary opt-out available via GoogleOrigin Trial "Allow Sync XHR In Page Dismissal". This feature allows you to register your domain for a token that you can then include in a header when serving the player files, and it will trigger Chrome to enable the synchronous requests during page dismissal. More details about enabling and using this method are outlined in this Google page.
Replication Steps
If you want to see this issue in action, so that you can verify that a provide fix works, you would need to do the following:
- Launch a SCORM course in an affected version of Chrome, in Chrome 77 with the enable-forbid-sync-xhr-in-page-dismissal flag set to 'Enabled', or in Chrome 78/79 with the allow-sync-xhr-in-page-dismissal flag set to 'Disabled'.
- Go through the course to completion, but do not exit.
- Find the window that contains Engine's player. If you have SCO Launch Type set to 'NEW_WINDOW', then the player window will be behind the content popup window. If you have SCO Launch Type set to FRAMESET, then everything will be in the same window together.
- Close the browser tab/window that contains the player page.
- There are a few factors involved, but you may see that the top-level completion for the course is not reported properly. SCORM 2004 is more likely to exhibit this due to the sequencing rules for rollup that trigger on exit.
- A more foolproof way to verify that the exit request did not get sent properly is to check the launch history record for the registration. With the issue outlined in this article, the exit time value will be null, even though you closed the player in step 4.
If you use the API, you can hit the /launchHistory endpoint for the registration to check that value. Otherwise, you'd need to look up the scorm_registration_id from the ScormRegistration table based on your external key values, and then use that to get the latest ScormLaunchHistory record. - As an alternative way of verifying things, you could use a tool like Fiddler to capture all of the requests being made by your launch. After you close the player window in step 4 above, you should see a request to RecordResults.[jsp|aspx] with a url parameter of 'isExitScormPlayer=true'. If you don't see that request, then you know that it has been blocked by the browser.
Notes:
- Link to Chrome Platform article about this change: https://www.chromestatus.com/feature/4664843055398912