@slopit/adapter-jatos API Reference
Integration adapter for JATOS (Just Another Tool for Online Studies). Provides session recording with automatic integration into JATOS's data storage and multi-component study support.
Installation
pnpm add @slopit/adapter-jatos
When to Use This Package
Use @slopit/adapter-jatos when:
- Running experiments on a JATOS server
- Building multi-component studies
- Using JATOS for experiment hosting and data collection
Quick Start
import { SlopitRecorder } from "@slopit/adapter-jatos";
jatos.onLoad(function() {
const recorder = new SlopitRecorder();
// run trials
recorder.beginTrial("trial_1", textarea);
// ... participant completes trial ...
recorder.finishTrial(response);
// submit and end
await recorder.submitToJatos();
jatos.endStudy();
});
SlopitRecorder / JatosRecorder
Session recorder for JATOS experiments. Automatically detects JATOS worker and study IDs and integrates with JATOS's result data APIs.
Both SlopitRecorder and JatosRecorder refer to the same class.
Constructor
new SlopitRecorder(config?: JatosRecorderConfig)
new JatosRecorder(config?: JatosRecorderConfig)
The recorder automatically extracts participantId from jatos.workerId and studyId from jatos.studyId if not provided in the config.
JatosRecorderConfig
| Property | Type | Default | Description |
|---|---|---|---|
participantId | string | jatos.workerId | Participant identifier (auto-detected) |
studyId | string | jatos.studyId | Study identifier (auto-detected) |
metadata | Record<string, unknown> | - | Session-level metadata |
behavioral | BehavioralCaptureConfig | - | Default behavioral capture settings |
resultKey | string | "slopit" | Key used for slopit data in JATOS results |
const recorder = new SlopitRecorder({
resultKey: "behavioral_data",
metadata: {
condition: "experimental",
batch: "batch_1",
},
});
beginTrial(trialId, element?, trialConfig?)
Starts capturing behavioral data for a trial.
beginTrial(
trialId: string,
element?: HTMLElement,
trialConfig?: Partial<TrialConfig>
): void
const textarea = document.querySelector("textarea");
recorder.beginTrial("trial_1", textarea, {
trialType: "free-response",
stimulus: {
type: "text",
content: "Describe your experience.",
},
});
startTrialWithSelector(trialId, selector, container?)
Starts a trial with automatic element discovery. Uses a MutationObserver to wait for the element to appear in the DOM.
startTrialWithSelector(
trialId: string,
selector: string,
container?: HTMLElement | Document
): void
recorder.startTrialWithSelector(
"trial_1",
"textarea.response-input",
document.getElementById("trial-container")
);
finishTrial(response?)
Ends the current trial and returns captured data.
finishTrial(response?: string | ResponseInfo): CompletedTrial
// with text string
const trial = recorder.finishTrial("The participant's response.");
// with ResponseInfo object
const trial = recorder.finishTrial({
type: "text",
value: "Response text",
characterCount: 13,
wordCount: 2,
});
submitToJatos()
Submits session data to JATOS. Call this at the end of the component or study.
async submitToJatos(): Promise<void>
await recorder.submitToJatos();
jatos.endStudy();
appendToJatos()
Appends session data to JATOS result. Use this for incremental data submission during long experiments.
async appendToJatos(): Promise<void>
// after each block of trials
await recorder.appendToJatos();
storeInStudySession()
Stores session in JATOS study session data. Use this to share session data across components in a multi-component study.
storeInStudySession(): void
// in component 1
recorder.storeInStudySession();
jatos.startNextComponent();
loadFromStudySession()
Loads previous session data from JATOS study session. Use this in multi-component studies to retrieve data from previous components.
loadFromStudySession(): SlopitSession | undefined
// in component 2
const previousSession = recorder.loadFromStudySession();
if (previousSession !== undefined) {
console.log(`Previous session had ${previousSession.trials.length} trials`);
}
exportSession()
Exports the session data in SlopitSession format.
exportSession(): SlopitSession
getResultKey()
Gets the result key used for JATOS data storage.
getResultKey(): string
Other Methods
Inherited from BaseRecorder:
startTrial(config)- Start a new trial (usebeginTrialfor convenience)endTrial(response?, platformData?)- End current trial (usefinishTrialfor convenience)attachCapture(element, startTime?)- Attach capture to an elementdetachCapture()- Detach capture without ending trialgetCurrentTrial()- Get current trial stategetTrials()- Get all completed trialsisTrialInProgress()- Check if trial is activegetSessionId()- Get session identifierreset()- Reset for a new session
Complete JATOS Example
Single Component Study
<!DOCTYPE html>
<html>
<head>
<script src="jatos.js"></script>
<script type="module">
import { SlopitRecorder } from "@slopit/adapter-jatos";
let recorder = null;
jatos.onLoad(async function() {
// initialize recorder (auto-detects participant and study IDs)
recorder = new SlopitRecorder();
// create trial UI
document.body.innerHTML = `
`;
const textarea = document.getElementById("response");
const submitBtn = document.getElementById("submit");
// start capture
recorder.beginTrial("writing_1", textarea, {
trialType: "free-response",
stimulus: {
type: "text",
content: "Describe your ideal vacation destination.",
},
});
// handle submit
submitBtn.addEventListener("click", async function() {
// end trial
recorder.finishTrial(textarea.value);
// submit to JATOS
await recorder.submitToJatos();
// show thank you message
document.body.innerHTML = `
`;
// end study after a delay
setTimeout(function() {
jatos.endStudy();
}, 2000);
});
});
</script>
</head>
<body>
<p>Loading...</p>
</body>
</html>
Multi-Component Study
Component 1: Instructions and First Task
import { SlopitRecorder } from "@slopit/adapter-jatos";
jatos.onLoad(function() {
const recorder = new SlopitRecorder({
metadata: { component: 1 },
});
// ... run first task ...
recorder.beginTrial("task1_trial1", textarea);
// ... participant completes trial ...
recorder.finishTrial(response);
// store session for next component
recorder.storeInStudySession();
// move to next component
jatos.startNextComponent();
});
Component 2: Second Task
import { SlopitRecorder } from "@slopit/adapter-jatos";
jatos.onLoad(async function() {
const recorder = new SlopitRecorder({
metadata: { component: 2 },
});
// load data from previous component
const previousSession = recorder.loadFromStudySession();
console.log(`Previous component completed ${previousSession?.trials.length} trials`);
// ... run second task ...
recorder.beginTrial("task2_trial1", textarea);
// ... participant completes trial ...
recorder.finishTrial(response);
// submit all data
await recorder.submitToJatos();
jatos.endStudy();
});
Long Experiment with Incremental Saves
import { SlopitRecorder } from "@slopit/adapter-jatos";
jatos.onLoad(async function() {
const recorder = new SlopitRecorder();
const blocks = [
{ trials: ["t1", "t2", "t3"] },
{ trials: ["t4", "t5", "t6"] },
{ trials: ["t7", "t8", "t9"] },
];
for (const block of blocks) {
for (const trialId of block.trials) {
// run trial
await runTrial(recorder, trialId);
}
// save after each block
await recorder.appendToJatos();
console.log(`Block saved`);
}
// final submission
await recorder.submitToJatos();
jatos.endStudy();
});
async function runTrial(recorder, trialId) {
return new Promise((resolve) => {
const textarea = document.getElementById("response");
recorder.beginTrial(trialId, textarea);
document.getElementById("submit").onclick = function() {
recorder.finishTrial(textarea.value);
resolve();
};
});
}
Types
JatosRecorderConfig
Configuration for the JATOS recorder.
interface JatosRecorderConfig extends RecorderConfig {
resultKey?: string; // default: "slopit"
}
JatosModule
Interface for the global JATOS module (available as window.jatos).
interface JatosModule {
onLoad(callback: () => void): void;
submitResultData(data: unknown): Promise<void>;
appendResultData(data: string): Promise<void>;
endStudy(successful?: boolean, message?: string): void;
startNextComponent(message?: string): void;
studySessionData: Record<string, unknown>;
componentResultData: unknown;
studyResultData: unknown;
workerId: string;
studyId: string;
batchId: string;
componentId: string;
}
Platform Notes
- JATOS does not expose version information client-side; platform version is reported as "unknown"
- The
jatosglobal object must be available (loadjatos.jsfirst) submitToJatos()replaces existing result data; useappendToJatos()for incremental saves- Study session data persists across components in multi-component studies
- Use
resultKeyto customize the key under which slopit data is stored
Data Access in JATOS
After running your study:
- Go to your study in the JATOS GUI
- Click Results
- Export results as JSON or CSV
- The slopit session will be under the configured
resultKey(default: "slopit")
import json
import pandas as pd
# for JSON export
with open("results.json") as f:
results = json.load(f)
for result in results:
data = json.loads(result["data"])
slopit_session = data.get("slopit")
if slopit_session:
print(f"Session {slopit_session['sessionId']}")
for trial in slopit_session["trials"]:
print(f" Trial {trial['trialId']}: {len(trial['behavioral']['keystrokes'])} keystrokes")