Helpful guides and examples to make life easier.
task-data-raw
folderIn this guide, we discuss how to create, configure, and upload content to an AWS bucket to host your task website.
Imagine a bucket as a sophisticated GitHub or Google Drive folder that gives you the ability to host an experiment website and save data from that experiment. This tutorial should take 30-45 min the first time, but with practice you can finish the whole sequence in less than 10 min.
You can find out more about buckets in general on AWS’s documentation.
Make sure AWS is configured, which means your account is working with permissions to create and edit buckets in S3.
Log into the AWS Console and navigate to S3. To do this, you can use the search bar to search for s3.
For your new task, you’ll ultimately create 2 buckets. The goal of 2 buckets is to separate data records based on the experiment phase (and reduce confusion). The 2 buckets are:
yourtask-yourName-month-year-pilot
yourtask-yourName-month-year
Example: pilot - amplification-sad-amit-march-21-pilot
; “real” experiment = amplification-sad-amit-march-21
Now we will make a bucket. Click the Create bucket.
Enter your bucket name under Bucket name.
If your new bucket’s settings are similar to a pre-existing bucket’s settings, simply navigate to Copy settings from existing bucket and select your bucket-to-copy from there. You may still have to uncheck Block all public access, but you are now done with this step.
If you are making a new bucket with settings from scratch, proceed with the following.
.
├── external-html/
│ └── consent.html
├── index.html
├── jspsych/
└── stimuli/
├── 1.jpg
├── 2.jpg
└── 3.jpg
img/
, jspsych/
, etc will not be in the bucket, resulting in a broken website. .html
of your main task file here.error.html
file that AWS will route
to in case of errors in server-side logic that happen from time to time.Now click on Permissions.
name-of-bucket
needs to be replaced by the actual name of your
bucket!) :{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::name-of-bucket/*"
}
]
}
task-data-raw
folderWe save to a bucket called task-data-raw
. So, if the task is called
potato
, we save data to a folder located
within-bucket: task-data-raw/potato
.
To save data from a task, whether it is in pilot, or the actual task, you must use the AWS Browser SDK. There are two ways to use the SDK. The most common way is through a direct script link in the main HTML file:
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.713.0.min.js"></script>
Next, add the saveDataToS3() javascript function to your task as well:
/*
* You must use this cognitoIdentityPool string value and
* the "task-data-raw" value for DATA_BUCKET. The DIRECTORY value
* will change based on the task.
*/
const cognitoIdentityPool = "us-east-1:0f699842-4091-432f-8b93-a2d4b7bb5f20";
const DATA_BUCKET = "task-data-raw";
const DIRECTORY = "your-task-bucket-name-with-stage-goes-here";
/*
* Save data at any point to S3 using this function.
* It takes as arguments the string identifier of a participant
* and the data in CSV form from the jsPsych data getter.
*/
function saveDataToS3(id, csv) {
AWS.config.update({
region: "us-east-1",
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: cognitoIdentityPool
}),
});
// You can change anything after the first `/` here, but only if
// you know the intended behavior of changing this.
const filename = `${DIRECTORY}/${id}.csv`;
const bucket = new AWS.S3({
params: { Bucket: DATA_BUCKET },
apiVersion: "2006-03-01",
})
const objParams = {
Key: filename,
Body: csv
}
bucket.putObject(objParams, function(err, data) {
if (err) {
console.log("Error: ", err.message);
} else {
console.log("Data: ", data);
}
});
}
You will then reference this saving function within on_finish
or on_start
tags within
your jsPsych timeline when you would like to save data to S3. Remember to pass
in a participant identifier and the data to be saved in CSV format. This will
look like:
...,
on_finish: function() {
const id = "<whatever-the-subject-id-is>"
const csv = jsPsych.data.get().csv()
saveDataToS3(id, csv)
}
...
It’s very important that you follow this pattern. The on_finish
or on_start
piece of jsPsych
structures should use a generic function that contains the saveDataToS3
function. Do not directly call this function outside of these tags unless you understand what you are doing.
Now, you must create a CloudFront distribution for the S3 bucket. This will allow us to publish the task securely under the hbssurvey.com
domain name.
example-task-name-and-phase.hbssurvey.com
.
amplification-sad-amit-march-21-pilot
, a good web address name is amplification-s-pilot.hbssurvey.com
amplification-race-pilot
was changed to amplification-r-pilot.hbssurvey.com
because we did not want to spoil participants on the fact that this task contained elements related to race.*.hbssurvey.com (a715bbbd-ad62-49a0-8c75-9fdb9d542633)
Once these steps are completing, AWS will begin deploying the task. Typically, the wait should be less than ten minutes (in extreme cases it can take a few hours). Once ready, you’ll be able to navigate to your deployed task website.
With a CloudFront deployment of a task, the final step to making it ready for participants
is to create a subdomain on our lab’s study domain (e.g., new-task-name-and-phase.hbssurvey.com
).
You will need your CloudFront deployment’s URL to complete this step. You can find the CloudFront URL on the CloudFront home page. The URL will look similar to
dbmsd35c91.cloudfront.net
.
hbssurvey.com
URL you gave to the task during the CloudFront phase. This should match exactly the
name you give to the CloudFront distribution. So, if your CloudFront distribution URL was amplification-s-pilot.hbssurvey.com
, then amplification-s-pilot
into the textbox.dbmsd35c91.cloudfront.net
). Congratulations! You’re done!
Now you will find your task at the hbssurvey.com
address that you configured for it. Proceed to this tutorial to learn how to prepare your task to go live on the web!
SaveDataToS3
function without passing in arguments (for Sequential and Amplification Tasks)Make sure function saveDataToS3
is in the functions.js
file and not the main HTML file.
Modify the function so that id
refers to the global Face.ID
variable. Now saveDataToS3
can be called without passing in arguments.
function saveDataToS3() {
id = Face.ID
csv = jsPsych.data.get().csv()
AWS.config.update({
region: "us-east-1",
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: cognitoIdentityPool
}),
});
const filename = `${DIRECTORY}/${id}.csv`;
const bucket = new AWS.S3({
params: { Bucket: DATA_BUCKET },
apiVersion: "2006-03-01",
})
const objParams = {
Key: filename,
Body: csv
}
bucket.putObject(objParams, function(err, data) {
if (err) {
console.log("Error: ", err.message);
} else {
console.log("Data: ", data);
}
});
}
saveDataToS3
function. Not that sometimes the function fails to work with on_finish
and instead we use on_start
.var imageDescription = {
type: 'survey-text',
questions: [{prompt: "Please describe the picture in your own words"}],
preamble: function() {
var curr_stim = imageTestDescription.shift()
return '<img src='+curr_stim+'></img>';
},
on_finish: function(data){
saveDataToS3()
Face.description = JSON.parse(data.responses).Q0; } //save description
};
var attentionCheck = { //function for the attention check
timeline: [askTypeWord],
loop_function: checkTyping,
on_start: function(data){
saveDataToS3()}
};
var connectSurvey = {
type: 'image-button-response',
stimulus: "",
choices: ['Begin Survey'],
on_finish: function(data){
saveDataToS3()}
};
checkUser
function (temporarily until we construct a new one), change the order of items pushed into collective_emotion_estimation
timelinevar participant_id = { //to check if participants have entered ID (number/character, no punctuation allowed)
timeline: [enter_id],
loop_function: checkID,
// loop_function: checkUser
};
collective_emotion_estimation.push(checkPhone, participant_id, imageDescription);