Skip to content

Online experiments with jsPsych

This page guides you through setting up, managing, and troubleshooting experiments on Pavlovia using the jsPsych framework. Follow these steps and best practices to streamline your experiment creation and minimize errors.

For ready-to-use example, please refer to the Behavioural tasks page.

Learning resources

If you're unfamiliar with jsPsych, it's a good idea to start by learning some basics.

There is plenty of documentation on the main jsPsych page. In particular, go through the tutorial section, which contains some very accessible, step-by-step instructions on how to build your script.

You can also check out the content from Christophe Bossens' workshop on online experiments with jsPsych.

The ideal workflow

JsPsych offers a framework to write your experiment in javascript. While this might sound like extra complexity, as compared to using the Psychopy builder or to scripting your experiment in Python, it offers the significant advantage of being directly readable by any browser. The code for your experiment will be written in the <script> part of a regular html document, which can then be opened like any other webpage.

A basic workflow that you might want to adopt when scripting your experiment is the following:

  1. Open your experiment folder in your editor of choice and create a new index.html file. Build your javascript code and test it locally by running it in your browser.

    Tip

    Since you'll be editing javascript, html, css, but also probably some python code at the same time, it's probably a good idea to use an editor that can handle all of these. A great option is VSCode.

  2. Once your experiment is well built and running locally, upload it to GitLab, which you can access through your Pavlovia account (Dashboard > Profile > click on your account name). You can choose to do this on your own account or the lab account. Once your experiment is created on there, it will show on your Pavlovia dashboard.

  3. From there, work on your experiment like you would work on any Git repository: make changes locally and sync your changes with GitLab. Start by adding the necessary components for your script to run on Pavlovia. These will allow your script to communicate with the Pavlovia servers, without which your experiment can't run from Pavlovia.

    Using the lab account

    To run experiments beyond piloting, you may need credits. We have a Hoplab account for this purpose. Ask Klara or Silke how to get access to it.

  4. Finish refining your code by repeating this process: make changes locally > sync them with GitLab > try your task on Pavlovia (switch to Piloting or Running to be able to try your task).

    Tip

    It can sometimes be cumbersome to go through the complete local change > commit > test loop just to test out a minor code change. An elegant alternative is to use flags in your code that will activate or de-activate the Pavlovia components. The latter are just two: a init and a finish event. Set these behind an if statement, and you'll be able to switch from online to local with one flag, so that you can go back to trying your code locally before syncing your changes (see an example here).

Common trial types — code examples

Below are minimal examples for common trial types using jsPsych 7. These can be adapted and combined to build a full experiment.

Image display with keyboard response

<!-- Load the required plugins -->
<script src="https://unpkg.com/@jspsych/plugin-image-keyboard-response"></script>

<script>
var image_trial = {
    type: jsPsychImageKeyboardResponse,
    stimulus: 'img/my_stimulus.png',
    choices: ['f', 'j'],
    prompt: '<p>Press F for category A, J for category B</p>',
    stimulus_height: 400,  // in pixels
    response_ends_trial: true
};
</script>

Fixation cross

var fixation = {
    type: jsPsychHtmlKeyboardResponse,
    stimulus: '<p style="font-size: 48px;">+</p>',
    choices: "NO_KEYS",
    trial_duration: 500
};

Survey with Likert scale

<script src="https://unpkg.com/@jspsych/plugin-survey-likert"></script>

<script>
var likert_trial = {
    type: jsPsychSurveyLikert,
    questions: [
        {
            prompt: "How confident are you in your response?",
            labels: ["Not at all", "Slightly", "Moderately", "Very", "Extremely"],
            required: true
        }
    ]
};
</script>

Timeline with randomisation

var stimuli = [
    { stimulus: 'img/stim_01.png', correct_response: 'f' },
    { stimulus: 'img/stim_02.png', correct_response: 'j' },
    { stimulus: 'img/stim_03.png', correct_response: 'f' }
];

var trial = {
    type: jsPsychImageKeyboardResponse,
    stimulus: jsPsych.timelineVariable('stimulus'),
    choices: ['f', 'j'],
    data: {
        correct_response: jsPsych.timelineVariable('correct_response')
    }
};

var block = {
    timeline: [fixation, trial],
    timeline_variables: stimuli,
    randomize_order: true
};

For more examples and a full plugin reference, see the jsPsych documentation.


Common pitfalls on Pavlovia

Resource preloading

Pavlovia needs to download all media files before the experiment starts. If files are missing or paths are incorrect, the experiment will hang on the loading screen.

  • Use the jsPsychPreload plugin to explicitly preload images, audio, and video:

    var preload = {
        type: jsPsychPreload,
        images: ['img/stim_01.png', 'img/stim_02.png'],
        show_progress_bar: true
    };
    
  • Make sure all file paths are relative and match the exact case (Pavlovia's server is case-sensitive, unlike most local setups).

Data saving

If the experiment crashes or the participant closes the browser, data may be lost. To mitigate this:

  • Use jsPsych.data.get().csv() in the on_finish callback to send data to Pavlovia.
  • The Pavlovia plugin handles saving automatically, but make sure you call jsPsychPavlovia with the completedCallback at the end of your timeline.
  • Consider saving intermediate data with periodic pipe calls for long experiments.

File paths and naming

  • Avoid spaces and special characters in file names.
  • Keep all stimulus files in a subfolder (e.g., img/, audio/) and reference them with relative paths.
  • Double-check that the file structure on GitLab matches your local setup — files that exist locally but were not committed will cause errors on Pavlovia.

Troubleshooting

Problem Likely cause Solution
Experiment stuck on loading screen Missing resource files or incorrect paths Check browser console (F12) for 404 errors; verify file paths and case sensitivity
Data not saved after completion Pavlovia finish plugin not in timeline Ensure jsPsychPavlovia with action: 'save' is the last entry in your timeline
Experiment works locally but not on Pavlovia Local-only code or missing Pavlovia init/finish Check that jsPsychPavlovia init and finish events are included (see Pavlovia docs)
Timing seems off Browser rendering delays Use the jsPsychBrowserCheck plugin; avoid relying on frame-level precision for online experiments
"Unexpected token" errors JavaScript syntax issue Check browser console; common causes are trailing commas, missing semicolons, or ES6 syntax not supported by older browsers

Using jsPsych plugins

jsPsych's modular plugin system is one of its strengths. To add a plugin:

  1. Find the plugin in the plugin list or search for community plugins on npm.
  2. Include the script in your HTML <head> section (via CDN or local file):

    <script src="https://unpkg.com/@jspsych/plugin-html-button-response"></script>
    
  3. Use it in your timeline by referencing the plugin name (e.g., jsPsychHtmlButtonResponse).

Tip

When using multiple plugins, load them all in the <head> section before your experiment script. This prevents "plugin not found" errors.