Tracking Registration Results

Technically, Engine does all the tracking for you, but Engine doesn't have any idea what you intend to do with the data it captures. As discussed in the overview, your system should store its own version of the registration state to display to the user in your application and for other reporting purposes. We provide a couple of ways of keeping that data in sync with the registration state in Engine.

Automatic Postbacks

Engine can be configured to send postbacks to an endpoint in your system (webhook) whenever it receives an update to the status of one of your registrations.

To configure this, set the value for ApiRollupRegistrationPostBackUrl to the URL of the endpoint in your application you've built to listen for the postbacks. Once you've done that, Engine will POST a JSON object describing the status of a registration to your application whenever it receives an update from the player about an in-progress course launch.

These postbacks will be of the same schema that is used by the API. To make it easier to handle the postback coming from Engine, you can reference the API client's classes. You can translate the body of the postback into a RusticiSoftware.Core.api.client.v2.Model.RegistrationSchema using your favorite JSON parser.

For example, the JSON response body from a registration postback would look much like this (based on the ApiRollupRegistrationFormat setting discussed later):

{
    "id": "my_test_reg_id",
    "instance": 0,
    "updated": "2020-09-29T19:19:03.107Z",
    "registrationCompletion": "COMPLETED",
    "registrationSuccess": "FAILED",
    "score": {
        "scaled": 40.0
    },
    "totalSecondsTracked": 12.0,
    "firstAccessDate": "2020-09-29T19:19:00.550Z",
    "lastAccessDate": "2020-09-29T19:19:03.107Z",
    "completedDate": "2020-09-29T19:19:03.107Z",
    "createdDate": "2020-09-29T19:18:45.247Z",
    "course": {
        "id": "my_test_course_id",
        "title": "Golf Explained - Run-time Advanced Calls",
        "version": 0
    },
    "learner": {
        "id": "my_test_learner_id",
        "firstName": "Waylon",
        "lastName": "Smithers"
    }
}

These are the namespaces you'd need to import to use the sample code.

using Newtonsoft.Json;
using RusticiSoftware.Core.api.client.v2.Model;
using System;

Then, provided that the string variable jsonString contains the JSON from the postback, this code would deserialize it into the RegistrationSchema class.

RegistrationSchema schema = JsonConvert.DeserializeObject<RegistrationSchema>(jsonString);

Console.WriteLine(schema.Id); //output = 'my_test_reg_id'
Console.WriteLine(schema.RegistrationCompletion); //output = 'COMPLETED'
Console.WriteLine(schema.Learner.FirstName); //output = 'Waylon'

These are the packages you'd need to import for the sample code.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import RusticiSoftware.Core.api.client.v2.Models.RegistrationSchema;

Then, provided that the String variable jsonString contains the JSON from the postback, this code would deserialize it into the RegistrationSchema class.

Gson gSonInstance = new GsonBuilder()
        .registerTypeAdapter(OffsetDateTime.class, (JsonDeserializer<OffsetDateTime>)
                (json, type, context) -> OffsetDateTime.parse(json.getAsString()))
        .create();

RegistrationSchema schema = gSonInstance.fromJson(jsonString, RegistrationSchema.class);

System.out.println(schema.getId()); //output = 'my_test_reg_id'
System.out.println(schema.getRegistrationCompletion()); //output = 'COMPLETED'
System.out.println(schema.getLearner().getFirstName()); //output = 'Waylon'

Note for legacy integration customers: If you want to switch to using Engine's automatic postback functionality, then you will need to make a few modifications to your integration. First, your integration layer should include an additional reference to RusticiSoftware.Engine.API.dllinclude RusticiSoftware.Api-engine.jar in the project's build path. Second, your "main" integration class (the one currently inheriting from DefaultIntegration) should instead be changed to inherit from RusticiSoftware.Engine.api.implementation.BaseApiIntegration. And lastly, our BaseApiIntegration provides its own implementation of RollupRegistration to handle the automatic postbacks, so you will need to remove your implementation of that method from your main integration class.

Postback Configuration

There are a few settings that allow you to configure the behavior of Engine's automatic postbacks. The only setting required to enable the automatic postbacks to your system is ApiRollupRegistrationPostBackUrl, but you can set any of the following to further customize the behavior.

  • ApiRollupRegistrationFormat: The level of detail in the information that is posted to you. It may be one of three values: course (course summary), activity (activity summary, the default value), or full (all detail available). If you are only reporting on top-level details (like completion, success, score, duration), then we recommend that you set this value to course to minimize the amount data that has to be POSTed from Engine to your application.

  • ApiRollupRegistrationAuthType: Indicates how to authorize against the given postback URL. You can specify either form or httpbasic, with httpbasic as the default value. If form authentication, the username and password for authentication are submitted as form fields username and password, and the registration data as the form field data. If httpbasic authentication is used, the username and password are placed in the standard Authorization HTTP header, and the registration data is the body of the message.

  • ApiRollupRegistrationAuthUser: Username to use when posting registration data.

  • ApiRollupRegistrationAuthPassword: Password to use when posting registration data.

Postback Frequency

By default, Engine's SCORM player does not immediately save data committed by the content. Instead, it checks for dirty data on a set frequency (every 10 seconds), and if any is found, it sends it back to Engine to save in the database. Whenever Engine receives these updates, it will trigger the automatic postbacks to your system mentioned above.

Some customers have found this to happen a bit too frequently, increasing the load on Engine, and also on their own system to process the registration postbacks. To combat this, you can turn down the frequency at which the player checks for dirty data during the launch, as so reduce the frequency of possible postbacks to your endpoint.

To adjust this frequency, add an entry in your Engine config file for PlayerCommCommitFrequency, and give it a value higher than the default of 10 seconds. The value should be in milliseconds, so you will want to change its value to something like 30000 or even 60000. You should be careful, though, not to set this value so high that the player posts back too infrequently. If anything happens that would unexpectedly cut the learner's connection to Engine, the learner will lose all of the progress they've accrued since the last time the player sent an update. You will want to find a sweet spot between minimizing server load and ensuring the safety of your learners' progress.

Note: For learning standards other than SCORM (AICC, xAPI, LTI), this postback frequency does not apply. Those other standards communicate progress directly to Engine at a frequency determined by the content itself.

Querying the API

At any time, you can retrieve the current state of a registration using the /registrations/{registrationId} endpoint. This endpoint will return the same JSON schema that you receive in the registration postbacks. You might use this as a way to manually refresh a registration's state when needed.

Please remember that these resources are not intended to be ad hoc reporting mechanisms. Fetching all of the information about the registrations is not a small task, and repeatedly hitting these endpoints can result in negative effects on Engine's performance.

When calling the /registrations endpoint, there are a few parameters that control how much detail about the registration is returned:

  • includeChildResults: this includes details about each activity or learning object in the course, not just the top-level summary
  • includeRuntime: includes the runtime data of the activities
  • includeInteractionsAndObjectives: this goes a step further and includes objective and runtime interaction details (questions/answers)

We disable these parameters by default, as each one adds additional processing time for creating the result. Many customers only care about the top-level details anyway, so this lets you include them only if actually needed.

API Results Limit and Paging

Although Engine and its REST API are not intended to be used for heavy reporting, some endpoints, like GET requests to /registrations and /courses, have the ability to return lengthy arrays of results. Consequently, Engine limits how many items Engine returns at once. Two settings, ApiResultLimit and ApiResultLimitSinceNotSpecified, can be used to adjust the number of items returned in one response. If the optional 'since' or 'until' range parameters are available but not used, then ApiResultLimitSinceNotSpecified determines the results limit. Otherwise, if you do send 'since' or 'until' as query parameters, then ApiResultLimit determines the results limit.

When the total number of results exceeds the limit, the response will contain an additional property called 'more':

"more":"Q5GITSQBAAAKAAAA"

If you use the original query parameters along with 'more' and its value on a subsequent GET request, you will receive the next page of results:

/api/v2/registrations?since=2020-11-02T19:52:00Z&more=Q5GITSQBAAAKAAAA

Resetting Learner Progress

There may be times when you need to reset a learner's registration state so that they basically start over fresh. This may be so the user can retake the course, or to clear out data during testing. You can trigger this clearing of progress data by doing a DELETE request to the /registrations/{registrationId}/progress endpoint.

results matching ""

    No results matching ""