3 · Identifying participants
About 15 minutes

Image: Stephen Hackett, CC BY-SA 4.0, via Wikimedia Commons.
Remember DMDX and PsyScope?
If you were in a lab around 2000, one of these was probably how you built a study:
- DMDX on Windows, written by Jonathan and Kenneth Forster and still in use, which got millisecond timing out of a PC by talking to the display hardware (Forster & Forster, 2003)
- PsyScope on the Mac, where you assembled a trial by dragging boxes around instead of writing code. It was remarkable for 1993, and the reason a generation of psychologists owned a Mac (Cohen, MacWhinney, Flatt & Provost, 1993)
- SuperLab and E-Prime, the commercial options. Both are still sold today
By the end of this chapter the study will know who is doing it and which condition they're in, read from the URL 🔗.
Two kinds of URL parameter
Look at a real study link:
There are two things going on in this URL:
flankeris a path parameter. It's part of the address itself, and it's how the URL pattern picks the study. This is the<slug:slug>we encountered in the last chapterparticipant_idandconditionare query parameters, thekey=valuepairs after the?. They carry extra information about this particular visit
Recruitment tools like Prolific add such query parameters to your study URL (unique for each participant), allowing you to know who has done your study and thus who to pay!
Read query parameters on the server
You could read query parameters in the participant's browser via JavaScript
(URLSearchParams). I'd rather achieve the same thing in the backend using Python, as we already need to do related tasks here. Keeping similar logic in the same place reduces complexity (see the KISS computer science principle), which is always a good thing.
The study_detail view you copied in chapter 2 already reads these query parameters. Here it is again, so we can look at those lines:
def study_detail(request, slug):
"""Serve a single study to a participant.
The study is identified by a *path* parameter (``slug``, matched by the URL
pattern); the participant and condition arrive as *query* parameters, e.g.
``/study/flanker/?participant_id=p01&condition=A``. We read them here on the
server and pass them into the template.
"""
study = get_object_or_404(Study, slug=slug)
# ?preview=1 runs the study but skips saving (see the template). Match "1" exactly, so
# ?preview=0 doesn't accidentally turn it on.
preview = request.GET.get("preview") == "1"
participant_id = request.GET.get("participant_id", "")
condition = request.GET.get("condition", "")
context = {
"study": study,
# maybe we want to give a collaborator our draft study but we dont
# want their data to save. Preview lets us do this.
"preview": preview,
# Every plugin. The researcher's pasted code can use any trial type
# without telling us which, so the page is given them all (see study.jspsych).
"jspsych_plugins": plugin_files(),
# Who is doing the study, and which condition they're in, read from the query string
# so the front-end never has to parse the URL itself.
"participant_id": participant_id,
"condition": condition,
}
return render(request, "study/study_detail.html", context)
See how request.GET holds various key pieces of information. From there we can look up participant_id and condition (defaulting to an empty string if they're missing) and put each one in the context as its own variable.
Hand the extracted query parameters as variables to the front-end
See how in the template the python variables we just defined are passed to JavaScript variables. Add these two lines to study/templates/study/study_detail.html, inside the <script> block and above the const jsPsych = ... line:
const PARTICIPANT_ID = "{{ participant_id|escapejs }}";
const CONDITION = "{{ condition|escapejs }}";
study/templates/study/study_detail.html on GitHub
What escapejs is doing there
Both of those values originate from the URL, so they came from whoever wrote the link, and they could have been manipulated to run dodgy code. escapejs rewrites quotes, angle brackets, backslashes
and newlines as \uXXXX escapes, so a value can't break out of its JavaScript string and run as code.
Where the Prolific IDs come from
When you set your study up on Prolific, you paste your study URL with Prolific's placeholders, and Prolific fills them in per participant:
Prolific swaps {{%PROLIFIC_PID%}} for each participant's real ID. In chapter 4b, at the end of the study we send participants back to Prolific so their submission is recorded as complete.
Prolific also passes {{%STUDY_ID%}} and {{%SESSION_ID%}}. We only read participant_id here. Note that SESSION_ID offers a security measure to check if participants manipulated the URLs provided by Prolific (for more, see Secure external URL).
Checkpoint
With the server running, open http://127.0.0.1:8000/study/flanker/?participant_id=p01&condition=A. The study looks exactly as before. To see the difference, have a look at the page source (right-click, View Page Source) and find your two new lines:
No data is saved yet. The page knows who the participant is, but when the study finishes the data just disappears. In the next chapter we sort this out!