Participant API

The participant API is a way to read and log data specific to a participant. The API will only be accessible for participants that have agreed to participate in a study and that have once logged into their participant landing page. They will then be authenticated using their participant cookie for the participant API.

You can find information on how to practically use the participant API in the remote study use-case. Here, we just give an overview of the different possibilities.

Participants

Before we start with the API methods and detailed functionality, there are two ways to access the API: (1) allowing anonymous, unregistered participants, and (2) only allowing registered participants. The first option is great if you would like to distribute a link to your API-supported website and you would like visitors to directly interact with the page, without any registration steps. The second option is better for more controlled study, that is, when you need all participants registered in the system and you don't want anonymous participation.

Anonymous participation

If you prefer anonymous participation with an uncontrolled number of participants, you need to use the following HTML blueprint to embed the API script code. Note that this requires you to specify the project ID, in which the participants should be registered: replace the <PROJECT-ID> with the numerical project ID. A second thing you need to do is you need to set the project to allow for self-sign-up of participants. You can do this on the project page under "study management". First activate study management, then tick the box "New participants can sign-up to this project".

<!DOCTYPE html>
<html>
<head>
    <!-- this script loads the Participant API -->
    <script src="/api/v1/<PROJECT-ID>/anonymousParticipation.js" type="text/javascript"></script>
</head>
<body>

    <!-- the HTML body -->

    <script type="text/javascript">

        // here you can access the Participant API,
        // see below for methods you can use

    </script>
</body>
</html>

If successful, you will always have a participant present in your HTML page, because previously unregistered visitors will be automatically assigned an anonymous participant profile with their own participant ID.

Registered participation

If you are running a study with a limited number of (pre-registered) participants, it is better to use the following API embedding. This ensures that you can check in your custom JavaScript code whether a registered participant is visiting the site or not. Only in the first case, the full API will be available. If the visitor is not a registered participant, accessing the API methods will result in an error.

<!DOCTYPE html>
<html>
<head>
    <!-- this script loads the Participant API -->
    <script src="/api/v1/participation.js" type="text/javascript"></script>
</head>
<body>

    <!-- the HTML body -->

    <script type="text/javascript">

        // here you can access the Participant API,
        // see below for methods you can use

    </script>
</body>
</html>

Participant-specific API functions

All Participant API methods can only access (i.e., read and write) data that is specific to a single participant -- the participant that is browsing the page. This API cannot change or retrieve any other data. The Participant API first contains the participant ID:

// the internal id of the participant (long value)
DF.participant.id

Logging diary entries

The participant API first contains a flag whether it is possible to add diary entries in a Diary dataset in the project (only if the Diary dataset exists). Then you can use the diaryEntry function to store a diary entry for the current participant.

// check whether there is an active Diary dataset
// and entries can be added (true, false)
DF.participant.canAddDiaryEntry

// store a diary entry with title and entry text
// (you might need to get both from a text field or text prompt)
DF.participant.diaryEntry("this is the title", "this is the diary entry itself...")

Accessing user profiles

Then, the API allows to read and write participant profiles into an Entity dataset in the project (only if the Entity dataset exists).

// store data in an Entity dataset in the project
// in an item identified by the participant id
var data = {
    // example data
    xPosition: 100,
    yPosition: 120,
    color: "blue",
    active: true
}
DF.participant.setProfile(data)

// retrieve profile data for this participant from an Entity dataset
DF.participant.getProfile(function(data) {
    // extract profile data from data (example based on data in previous example)
    // do something with the data...
    if(data.active) {
        console.log(data.color)
    }
})

Accessing participant data

You can retrieve participant-related data from any dataset in the project. This means, only from datasets that can be filtered on participant ID (or a device ID that is associated to the participant).

// set start and end time for filtering on time
var start = new Date('2021-02-15').getTime()
var end = new Date('2021-03-15').getTime()

// retrieve participant data from the dataset with ID 2, filtered by start and end time in CSV format
DF.participant.getDataCSV(2, start, end, function(data) {
    console.log(data);
})

// retrieve participant data from the dataset with ID 2, filtered by start and end time in Json format
DF.participant.getDataJson(2, start, end, function(data) {
    console.log(data);
})

// retrieve data without filtering either by using -1 for the time values
DF.participant.getDataCSV(2, -1, -1, function(data) { ... })

// or by taking the time filtering out of the function call
DF.participant.getDataCSV(2, function(data) { ... })

Device-specific API functions

There are two functions of the API that are more related to the web page they are currently visiting than themselves. Therefore these two functions are sorted under DF.device.

Logging data

Since a participant might be in the same cluster as a device, this API also allows to log data on behalf of this one device that is directly linked to a participant. If there is no device linked to a participant ("in the same cluster as participant"), then this functionality will not be available for that participant.

// check whether there is an active IoT dataset
// and data items can be logged (true, false)
DF.device.canLogData

// log data for this participant's associated device,
// that is, a single device in the same cluster as the participant
var data = {
    xPosition: 450,
    yPosition: 540,
    color: 'blue',
    active: true
}
DF.device.logData(data, 'some activity')

// or in one line:
DF.device.logData({xPosition: 450, yPosition: 540, color: 'blue', active: true}, 'some activity')

Uploading images

You can upload canvas graphics as images for participants. You need to provide the canvas image data as a "Blob" to the uploadImage function and the image will be rendered and stored as a .png file.

// check whether there is an active Media dataset
// and data images can be uploaded (true, false)
DF.device.canUploadImage

// let's assume you have a <canvas> element in the HTML somewhere with id="mycanvas"
const canvas = document.getElementById('mycanvas');

// render canvas as a blob and upload it to media dataset
canvas.toBlob(function(blob) {
    DF.device.uploadImage(blob);
});

You can find a full example with the anonymous participation option below. Don't forget to replace <PROJECT-ID> with the correct project ID.

<!DOCTYPE html>
<html>
    <head>
        <!-- this script loads the anonymous Participant API -->
        <script src="/api/v1/<PROJECT-ID>/anonymousParticipation.js" type="text/javascript"></script>
    </head>
    <body>
        <!-- the HTML body -->
        <canvas id="mycanvas"></canvas>

        <!-- scripting -->
        <script type="text/javascript">
        // create a canvas with a green rectangle
        const canvas = document.getElementById('mycanvas');
        const ctx = canvas.getContext('2d');
        ctx.fillStyle = 'green';
        ctx.fillRect(10, 10, 150, 100);

        // check if the participant can upload images
        // this is checking whether there is a media dataset and it can be accessed
        if(DF.device.canUploadImage) {
            // render canvas as a blob and upload it to media dataset
            canvas.toBlob(function(blob) {
                DF.device.uploadImage(blob);
            });
        }
        </script>
    </body>
</html>