Send xAPI from Apex

The xAPI Statement class enables the assembly and transmission of complex xAPI statements to your LRS. You can find the class definition here.

Example General Experience Statement

In this example, we create and transmit an xAPI statement using specific values. In your implementation, you will extract information from your Salesforce data schema. The locale that was specified during setup will be used by the statement fields that require it.

Instantiate an xAPI Statement.

  1. MetaxAPI.XapiStatement statement = new MetaxAPI.XapiStatement();

Set the actor’s name and use MBox for user identification. For other user identification cases, you can use setActorOpenId, setActorAccount, and setActorMboxSha1Sum.

  1. statement.xapiActor.setName('xAPI Tester');
  2. statement.xapiActor.setMbox('tester@globebyte.com');

Set the verb id and its display name.

  1. statement.xapiVerb.setId('http://adlnet.gov/expapi/verbs/experienced');
  2. statement.xapiVerb.setDisplay('Read the course introduction');

Set the object id and name.

  1. statement.xapiObject.setId('https://globebyte.com/pathway/course/hr/code/234');statement.xapiObject.setName('HR on-boarding course');

Add a context hierarchy. For more complex context structures, including extensions and statement references, refer to the full class documentation.


  1. statement.xapiContext.setActivityId('https://globebyte.com/pathway/course/hr/code/234');
  2. statement.xapiContext.setActitivtyName('HR on-boarding course');
  3. statement.xapiContext.setActivityType('https://globebyte.com/pathway/course');
  4. statement.xapiContext.addActivity('category');

Finally, validate the statement before sending it synchronously. If you are not concerned about the outcome, you can use sendAsync. sendSync will return a boolean (true/false) to indicate whether the send was successful or not. If it returns false, the send was not successful, in which case an error message will have been written to the apex debug log, you can access the log using these instructions.

  1. Boolean isValid = statement.validate();
  2.  
  3. if (isValid) {
  4.   System.debug('Sending statement...');
  5.   try {
  6.     Boolean isSent = statement.sendSync();
  7.     System.debug('Statement send returned ' + isSent);
  8.   }
  9.   catch (Exception error) {
  10.     System.debug(LoggingLevel.ERROR, 'Exception occurred: ' + error.getMessage());
  11.   }
  12. } else {
  13.   System.debug ('Statement not valid, did not send.');
  14. }

Below is an example of a full statement.

  1. MetaxAPI.XapiStatement statement = new MetaxAPI.XapiStatement();
  2.  
  3. statement.xapiActor.setName('xAPI Tester');
  4.  
  5. /*
  6.  * Only one of Mbox, Account, OpenId or MboxSha1Sum can be set in a statement.
  7.  */
  8. statement.xapiActor.setMbox('tester@globebyte.com');
  9. //statement.xapiActor.setAccount('123456', 'https://www.globebyte.com');
  10. //statement.xapiActor.setOpenId('https://www.globebyte.com/user');
  11. //statement.xapiActor.setMboxSha1Sum('1234567890123456789012345678901234567890');
  12.  
  13. statement.xapiVerb.setId('http://adlnet.gov/expapi/verbs/experienced');
  14. statement.xapiVerb.setDisplay('Read the course introduction');
  15. statement.xapiObject.setId('https://www.globebyte.com/content/write-xapi-statement');
  16. statement.xapiObject.setName('Maths for beginners');
  17. statement.xapiObject.setDescription('This course teaches the fundamentals of multiplication, addition and subtraction.');
  18.  
  19. /*
  20.  * Following is an example of a simple context activity of type parent.
  21.  */
  22. statement.xapiContext.setActivityId('http://www.globebyte.com/meetings/series/267');
  23. statement.xapiContext.addActivity('parent');
  24.  
  25. /*
  26.  * Following is an example of a more complex context activity of type category.
  27.  */
  28. statement.xapiContext.setActivityId('http://www.globebyte.com/meetings/categories/teammeeting');
  29. statement.xapiContext.setActivityName('team meeting');
  30. statement.xapiContext.setActivityType('http://globebyte.com/expapi/activities/meetingcategory');
  31. statement.xapiContext.addActivity('category');
  32.  
  33. /*
  34.  * Following is an example of a context activity hierarchy of two activities of type other.
  35.  */
  36. statement.xapiContext.setActivityId('http://www.globebyte.com/meetings/occurances/34257');
  37. statement.xapiContext.addActivity('other');
  38. statement.xapiContext.setActivityId('http://www.globebyte.com/meetings/occurances/342572');
  39. statement.xapiContext.addActivity('other');
  40.  
  41. statement.xapiContext.setRegistration('ec531277-b57b-4c15-8d91-d292c5b2b8f7');
  42. statement.xapiContext.setInstructorName('Andrew Downes');
  43. statement.xapiContext.setInstructorAccount('13936749', 'http://www.globebyte.com');
  44. statement.xapiContext.setPlatform('Example virtual meeting software');
  45. statement.xapiContext.setLanguage('tlh');
  46. statement.xapiContext.setStatement('6690e6c9-3ef0-4ed3-8b37-7f3964730bee');
  47. statement.xapiResult.setSuccess(true);
  48. statement.xapiResult.setCompletion(true);
  49. statement.xapiResult.setResponse('We agreed on some example actions.');
  50. statement.xapiResult.setDuration('PT1H0M0S');
  51. statement.xapiResult.addExtension('http://globebyte.com/profiles/meetings/resultextensions/minuteslocation', 'X:\\meetings\\minutes\\examplemeeting.one');
  52. statement.xapiResult.setScoreScaled(1);
  53. statement.xapiResult.setScoreRaw(1);
  54. statement.xapiResult.setScoreMin(1);
  55. statement.xapiResult.setScoreMax(1);
  56.  
  57. statement.setVersion('1.0.3');
  58.  
  59. Boolean isValid = statement.validate();
  60.  
  61. if (isValid) {
  62.   System.debug('Sending statement...');
  63.   try {
  64.     /*
  65.      * If using this code in an invocable method use sendAsync() otherwise use sendSync().
  66.      */
  67.     Boolean isSent = statement.sendSync();
  68.     System.debug('Statement send returned ' + isSent);
  69.     //statement.sendAsync();
  70.   }
  71.   catch (Exception error) {
  72.     System.debug(LoggingLevel.ERROR, 'Exception occurred: ' + error.getMessage());
  73.   }
  74. } else {
  75.   System.debug ('Statement not valid, did not send.');
  76. }

Sending Outcomes

The class supports reporting or taking action based on assessment submissions or measured admission process outcomes by using methods like setResultCompletion or setResultResponse, as well as handling scores.

Authority and Platform

Processing xAPI data for reporting purposes can be intricate. You can utilize setAuthority and setVersion to aid in filtering inbound learning telemetry processing.

More Information

For more information and implementation details, browse the documentation below:

Setting up Globebyte xAPI Send xAPI from a flow Form action fields Send xAPI from Apex Logging and defaults xAPIStatement class reference