Contact Us Support Forum Get Email Updates
 
 

Thanks! Someone will be in touch with you shortly.

Rather just email us? Email us here.
Rather speak with someone in person?
Call any time with Experience API questions:

866.497.2676

Page archived

This is an old page. Please visit
this page or contact us instead!


Experience API v.90: Statements 101

In the technical introduction to xAPI, we outlined some basic concepts about statements. Here we’ll take a deeper look into the structure of statements, and discover their utility in capturing experiences.

At the simplest level, xAPI statement structure can be expressed in the form of “actor verb object”. An example of this sort of statement is “Sally experienced ‘Solo Hang Gliding'”. In the technical introduction, we saw the JSON format of this statement as

{
   "actor": {
       "name": ["Sally"],
       "mbox": ["mailto:sally@example.com"]
    },
    "verb": "experienced",
    "object": {
"id": "http://example.com/activities/solo-hang-gliding",
        "definition": {
            "name": { "en-US": "Solo Hang Gliding" }
        }
    }
}

Using this example as a base, let’s start to explore and expand on the elements of xAPI statements.

Parts of a xAPI Statement

Actor

As we conducted the research involved with Project Tin Can, one sentiment that we heard repeatedly in our interviews with industry leaders was this: Learning is becoming, and should become, increasingly person-centric. We discovered that people, not companies, were more interested in the long-term ownership of their experiences and results.

In xAPI, people don’t have to be solely identified by one system or ID. That’s an important step in making xAPI person-centric. Imagine a consolidated view of your activity across all the systems with which you interact. Though you tweeted using @yourhandle on Twitter, when you see the whole of your activity, you see the experience more in the terms that you tweeted, the same “you” that took ‘Solo Hang Gliding’ and the same “you” that read Hang Gliding Training Manual. The other implication is that systems, given the right data and permissions, can automatically make these connections and help develop person-centric views of the data.

With that explanation in mind, let’s look at our example actor object:

{
   "name": ["Sally"],
   "mbox": ["mailto:sally@example.com"]
}

This actor object has two properties, “name” and “mbox”. In both cases, and with actor properties in general, the values of these properties are arrays. This facilitates the consolidation of identifiers and descriptive parts of an actor. Sally may have multiple email addresses (in the “mbox” field), and, though less likely, she may go by multiple names, which all comprise a view of Sally the person. At any rate, only “mbox” uniquely describes this Sally. There may be many people out there with the name Sally, but only one of them owns the email address sally@example.com.

Let’s expand our actor object with a bit more information:

{
   "name": ["Sally"],
   "givenName": ["Sally"],
   "familyName": ["Smith"],
   "mbox": ["mailto:sally@example.com", "mailto:sallyrocks@email.com"],
   "account": [
       { 
           "accountServiceHomePage": "http://twitter.com",
           "accountName": "sallyglider434"
        }
    ]
}

In this case, we added some descriptive properties, “givenName” and “familyName”, along with some additional identifying properties, in the form of another email address “sallyrocks@email.com” and a twitter account with the handle “sallyglider434”. This flexibility in identifying people is at the core of the person-centric views that are possible with xAPI, and we’ll go into more depth about them in an upcoming “Actors 101” article. We’ll also talk about representing systems (not people) and groups as actors as well. For now, those details can be found in the Experience API specification.

Back to top ▲

Verb

Verbs in xAPI are just simple strings. But, they are also a very crucial element of statements, as they describe just what has happened between the actor and object of the statement. The current xAPI specification (0.9 at the time of this writing) provides a small list of accepted verbs, but it has been clear from the start that verbs are a key part of how expressive statements can be.

For this reason, the next revision of the specification will include rules to allow verb extension. This revision will allow arbitrary verbs, which can be formatted to link systems to more information about their meaning and intended use. The list of reserved verbs currently available include “experienced”, “attended”, “attempted”, “completed”, “passed”, “failed”, “answered”, “interacted”, “imported”, “created”, “shared”, and “voided”.

Back to top ▲

Object

Wrapping up the core statement structure, let’s consider the “object” field. Typically the object will be a xAPI activity, though it might be another actor, and in the case of voiding, another statement. For now, we’ll keep our focus on activities as objects.

While actors in xAPI are usually related to existing people, and verbs tend to have a clear existing definition, activities are more likely to be defined and provided by the systems reporting statements. All activities must be uniquely defined by an ID, and can optionally include descriptive information. Let’s take another look at the object from our example statement:

{
"id": "http://example.com/activities/solo-hang-gliding",
  "definition": {
    "name": { "en-US": "Solo Hang Gliding" }
}

This is an activity uniquely identified by its “id” field. It’s an important intention of xAPI that no two activities are ever referenced by the same ID. An ID should always correspond one to one with the logical activity it identifies. But, the definition for an activity object can be updated over time (though it shouldn’t ever be changed significantly enough to describe some other new activity). Descriptive fields in the activity definition offer a way for xAPI to natively support internationalization. Let’s add some more info to our example object as an example:

{
  "id": "http://example.com/activities/solo-hang-gliding",
  "definition": {
    "type":"course",
    "name": { 
        "en-US": "Solo Hang Gliding",
        "es":"Solo Ala Delta"
     },
     "description": {
         "en-US":"The 'Solo Hang Gliding' course provided by The Hang Glider's Club",
         "es":"El curso de 'Solo Ala Delta' siempre por el Club de Planeadores Hang"
     },
     "extensions": {
         "gliderClubId":"course-435"
     }
}

Here we’ve added a “type” field, indicating the activity is a course on solo hang gliding. We’ve also added a “description” field, which as expected, contains a short description of the course. In the case of “name” and “description”, we’ve added the spanish version (care of Google Translate). This way, reporting tools or other display layers could automatically switch the language output based on a user’s preferences.

We’ve also added to the “extensions” field, where we can put arbitrary fields that are custom to a particular application (or convention). We’ll talk more about extensions below. Full details for activity definitions can be found in the Experience API specification.

Back to top ▲

Verbs vs. Activities

Sometimes the line between a verb and an object can become blurry. In our example statement about Sally, there’s an implication that “Solo Hang Gliding” is a single well defined activity. Perhaps it’s a course or test defined by the hang gliding school from example.com. But what if we wanted to say “Sally hang-glided over Mount Magazine”? Is “hang gliding over Mount Magazine” a specific activity that Sally is “experiencing”? Or did Sally “hang glide”, with “Mount Magazine” as the object of the statement?

Usually, resolving this ambiguity will rely on the intentions in reporting the data, and the relation of these pieces to other statements. In a system that will track many activities on Mount Magazine, it may improve the data to isolate Mount Magazine as an object. You’ll also be able to more easily isolate all of Sally’s hang gliding experiences across many different objects, if you can filter on the verb “hang gliding”.

In other cases, “hang gliding over Mount Magazine” might make sense as a single activity if it’s been defined by some organization or specification, and means something very specific in terms of instruments used, path flown, and so on. In that case, what’s important is that “Sally experienced ‘Hang Gliding over Mount Magazine'” (which has been defined specifically as The Hang Glider Club’s first hang gliding test).

Back to top ▲

Context

The “context” field provides a place to add some contextual information to a statement. We can add information such as the instructor for an experience, if this experience happened as part of a team activity, or how an experience fits into some broader activity. Let’s explore some of these elements in our example statement:

{
   "actor": {
       "name": ["Sally"],
       "mbox": ["mailto:sally@example.com"]
    },
    "verb": "experienced",
    "object": {
        "type":"course",
        "id": "http://example.com/activities/solo-hang-gliding",
        "definition": {
            "name": { "en-US": "Solo Hang Gliding" }
        }
    },
    "context": {
        "instructor": {
            "name": ["Irene"],
            "mbox": ["mailto:irene@example.com"]
         },
         "contextActivities":{
             "parent": { "id": "http://example.com/activities/hang-gliding-class-a" },
             "grouping": { "id": "http://example.com/activities/hang-gliding-school" }
         }
    }
}

In this example, we’ve added a “context” object to the statement. We’re stating that “Sally took the ‘Solo Hang Gliding’ course, under the instruction of Irene, as part of Hang Gliding Class A, within the context of Hang Gliding School”. Whew, now that’s a mouthful, but we’ve added some useful information here. These pieces of context are especially useful in the way statements can be grouped when reporting. The native query API in xAPI allows us to go back and ask for all statements made under Irene’s instruction, or to see all statements made from participants of Hang Gliding Class A, or even all statements made within the Hang Gliding School. In a more sophisticated reporting tool, these elements could help us achieve a very logical grouping of the data.

Though not shown here, context objects also have an “extensions” field, allowing arbitrary data to be attached as context for the statement. This data can then be used in specialized reporting tools when the statements are retrieved. We’ll talk further about extensions below. The full set of context elements can be found in the Experience API specification.

Back to top ▲

Result

A statement can also end in some measured outcome. For example, if ‘Solo Hang Gliding’ is a course or an assessment, we could state that “Sally completed ‘Solo Hang Gliding’ with a passing score of 95%”, or “Sally completed ‘Solo Hang Gliding’ with a failing score of 2 out of 6”, or even “Sally completed ‘Solo Hang Gliding’ in 4 hours”. Let’s add a result to our example statement:

{
   "actor": {
       "name": ["Sally"],
       "mbox": ["mailto:sally@example.com"]
    },
    "verb": "completed",
    "object": {
        "id": "http://example.com/activities/solo-hang-gliding",
        "definition": {
            "name": { "en-US": "Solo Hang Gliding" }
        }
    },
    "result": {
        "completion": true,
        "success": true,
        "score": {
            "scaled": 0.95
        }
    }
}

Here we’ve stated that “Sally completed ‘Solo Hang Gliding’ with a passing score of 95%”. The “completion” field tells us that Sally is done, and the “success” field tells us that she passed. The “score” field gives us the 95% figure. In the case of “score”, the value is actually a score object, and it could be expressed in terms of a minimum, maximum, and raw value instead. This means we could report a score such as “2 out of 6”, using a minimum of 0, a maximum of 6, and a raw value of 2.

We can also record a duration in the result, which tells us how long the activity leading to the result actually took. And in the case of a statement that records an interaction between the actor and the object, the result can have the actor’s response. In that way we could say “Sally answered ‘Question A’ with the response ‘Choice B’ in 8 seconds, and was correct”. Details about interaction activities and their responses can be found in the full xAPI specification. Here again xAPI provides an “extensions” field, this time on the result object, to let applications define their own custom results. Speaking of which…

Back to top ▲

Extensions

Throughout this tour of xAPI statements, we’ve seen several occurrences of the “extensions” field. Extensions are available as part of activity definitions, as part of statement context, or as part of some statement result. In each case, they’re intended to provide a natural way to extend those elements for some specialized use. The contents of these extensions might be something valuable to just one application, or it might be a convention used by an entire community of practice.

Since “extensions” fields can contain arbitrary data, they unlock a lot of flexibility in what you can express in a statement. But, as the old adage goes, “With great power comes great responsibility”. Using extensions responsibly means a few things.

First, though you could use extensions to pack in a lot of application-specific data, but it doesn’t always mean you should. A statement shouldn’t be totally defined by its extensions, and be meaningless otherwise. xAPI statements should be capturing experiences among actors and objects, and should always strive to map as much information as possible into the built in elements, in order to leverage interoperability among xAPI conformant tools.

Second, extensions should logically relate to the part of the statement where they are present. Extensions in statement context should provide context to the core experience, while those in the result should provide elements related to some outcome. For activities, they should provide additional information that helps define an activity within some custom application or community.

With all of that in mind, let’s throw a few extensions onto our example statement:

{
   "actor": {
       "name": ["Sally"],
       "mbox": ["mailto:sally@example.com"]
    },
    "verb": "completed",
    "object": {
        "id": "http://example.com/activities/solo-hang-gliding",
        "definition": {
            "type": "assessment",
            "name": { "en-US": "Solo Hang Gliding" },
            "extensions": {
                "gliderClubId": "test-435"
            }
        }
    },
    "result": {
        "completion": true,
        "success": true,
        "extensions": {
            "averagePitch": 0.05
        }
    },
    "context": {
        "extensions": {
            "weatherConditions": "rainy"
        }
    }
}

In this case, we’ve added information to define the ‘Solo Hang Gliding’ assessment within the Hang Glider Club’s community using the “gliderClubId” field. We’ve noted an important piece of context about this experience in the form of the “weatherConditions” field. And finally, we’ve included a custom metric in the outcome of the statement using the “averagePitch” field. Even without these extra pieces of information, the core statement remains meaningful: “Sally passed ‘Solo Hang Gliding'”. The extra information just enables more meaning in specialized environments.

Back to top ▲

Other statement fields

We’ve pretty much wrapped up our tour of major elements in a xAPI statement. Here we’ll take a quick look at a few other small but important pieces of statements.

The “inProgress” flag can be thought of as changing the tense of a verb from past tense to present tense. So adding “inProgress” as true to our example statement would record that “Sally is experiencing ‘Solo Hang Gliding’ (and you’ll be hearing more about this)”.

The “timestamp” and “stored” fields are critical elements of statements. The first records when the experience occurred, while the second records when the experience was added to the xAPI LRS where this statement has been stored. The “stored” field is hence always set by the LRS, while the “timestamp” field can and should be set by the system originating the statement.

The “authority” field captures information about who or what has made this statement. The value for this field is a FOAF actor, and could represent a person such as “Sally” or “Irene”, or a thing such as “The Glider Field Application”. Knowing who made the statement is crucial information when considering statement validity, and is also useful as a form of audit trail. Much more will be said regarding authorization, authentication, and permissions in an upcoming “xAPI Security 101” article. More information can be found today by digging into the xAPI specification.

Finally, the “voided” field on a statement tells us if this statement is no longer valid information. In order to support the distributed nature of xAPI, statements are considered logically immutable. That is, once a statement has been stored in an LRS, there is no way to alter or change that statement. But it’s constricting to require that all statement are valid for all of time once made. So, to support invalidating them, as mistakes or otherwise, xAPI provides a mechanism to void some previous statement using a new statement. Details on voiding statements can be found in the xAPI specification.

That concludes our tour of xAPI statements. If you’d like to easily create some of your own statements, make sure to check out our Statement Generator

Let’s end things off with an information packed version of our example statement, which before this might have seemed quite scary, but should now be discernible:

{
   "actor": {
       "name": ["Sally"],
       "givenName": ["Sally"],
       "familyName": ["Smith"],
       "mbox": ["mailto:sally@example.com", "mailto:sallyrocks@email.com"]
    },
    "verb": "completed",
    "object": {
        "id": "http://example.com/activities/hang-gliding-test",
        "definition": {
            "type": "assessment",
            "name": { "en-US": "Hang Gliding Test" },
    "description": { "en-US": "The Solo Hang Gliding test, consisting of a timed flight from the peak of Mount Magazine" },
            "extensions": {
                "gliderClubId": "test-435"
            }
        }
    },
    "result": {
        "completion": true,
        "success": true,
        "score": {
            "scaled": 0.95
        },
        "extensions": {
            "averagePitch": 0.05
        }
    },
    "context": {
        "instructor": {
            "name": ["Irene"],
            "mbox": ["mailto:irene@example.com"]
         },
         "contextActivities":{
             "parent": { "id": "http://example.com/activities/hang-gliding-class-a" }
             "grouping": { "id": "http://example.com/activities/hang-gliding-school" }
         }
        "extensions": {
            "weatherConditions": "rainy"
        }
    },
    "inProgress": false,
    "timestamp": "2012-07-05T18:30:32.360Z",
    "stored": "2012-07-05T18:30:33.540Z",
    "authority": {
        "name": ["Irene"],
        "mbox": ["mailto:irene@example.com"]
    }
}

Back to top ▲

Other Info

In future articles, we’ll take a closer look into how xAPI handles authentication, and get a tour of other parts of the Experience API. As always, please send us your thoughts and questions as you dig into xAPI. We’re happy to provide any answers we can, and we’d love to hear about your progress as you explore the use of xAPI in your own application. If you’d like to stay informed about the latest Experience API news, get email updates from us here.