Skip to content

Commit 3c19d49

Browse files
gureckisclaude
andcommitted
feat: add SPARK recruitment service support for adolescent participants
SPARK is a Hartley Lab recruitment service that passes subject_ID, participant_ID, age, and gender via URL params. Completion redirects to spark.hartleylab.org. Includes dev mode card, thanks page redirect, deploy Slack notification, and documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5505eaa commit 3c19d49

9 files changed

Lines changed: 126 additions & 1 deletion

File tree

.github/workflows/deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,5 +263,6 @@ jobs:
263263
"mturk_url": "https://${{ secrets.EXP_DEPLOY_HOST }}/e/${{ steps.dotenv_github.outputs.VITE_CODE_NAME }}/#/welcome/mturk/",
264264
"sona_url": "https://${{ secrets.EXP_DEPLOY_HOST }}/e/${{ steps.dotenv_github.outputs.VITE_CODE_NAME }}/#/welcome/sona/?survey_code=%SURVEY_CODE%",
265265
"sona_paid_url": "https://${{ secrets.EXP_DEPLOY_HOST }}/e/${{ steps.dotenv_github.outputs.VITE_CODE_NAME }}/#/welcome/sona_paid/?survey_code=%SURVEY_CODE%",
266+
"spark_url": "https://${{ secrets.EXP_DEPLOY_HOST }}/e/${{ steps.dotenv_github.outputs.VITE_CODE_NAME }}/#/welcome/spark/?subject_ID=%SUBJECT_ID%&participant_ID=%PARTICIPANT_ID%&age=%AGE%&gender=%GENDER%",
266267
"citizen_url": "https://${{ secrets.EXP_DEPLOY_HOST }}/e/${{ steps.dotenv_github.outputs.VITE_CODE_NAME }}/#/welcome/citizen/"
267268
}

docs/coding/configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@ VITE_SONA_PAID_CREDIT_TOKEN = ''
301301
- `VITE_SONA_PAID_CREDIT_TOKEN` is the SONA payment token for automatic payment
302302
granting
303303

304+
Note: SPARK does not require any environment variables. The SPARK completion URL
305+
(`https://spark.hartleylab.org/completed`) is configured directly in
306+
`src/core/config.js` since it is not secret.
307+
304308
#### Code Version Options (`.env.github.local`)
305309

306310
The `.env.github.local` file contains information about the latest git commit

docs/labconfig.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ Next, select "Webhook" as the type of workflow you are creating.
269269
Click add variables and add the following variable names to your workflow
270270
`deploy_base`, `deploy_base_codename`, `github_username`,`github_hash`,
271271
`qr_code`, `prolific_url`, `cloudresearch_url`, `mturk_url`, `sona_url`,
272-
`sona_paid_url`, `citizen_url`. This
272+
`sona_paid_url`, `spark_url`, `citizen_url`. This
273273
screenshot shows only a subset being added:
274274

275275
![Slack config](/images/labconfig-slack3.png)
@@ -293,6 +293,7 @@ add the variables to the message):
293293
- MTurk URL: mturk_url
294294
- SONA (credit) URL: sona_url
295295
- SONA (paid) URL: sona_paid_url
296+
- SPARK URL: spark_url
296297
- Citizen URL: citizen_url
297298
298299
QR Code: qr_code

docs/recruit/recruitment.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,58 @@ In the developer tools sidebar, you can select "sona" or "sona_paid" from the
338338
you test the full flow including the thanks/credit page without needing an
339339
actual SONA participant.
340340

341+
## SPARK
342+
343+
[SPARK](https://spark.hartleylab.org) is a recruitment service from the Hartley
344+
Lab designed for adolescent participants of various ages. Unlike SONA, SPARK
345+
does not require environment variables or credit tokens — completion is handled
346+
by redirecting participants back to the SPARK platform.
347+
348+
::: tip
349+
SPARK is available to Hartley Lab members and collaborators. Contact the
350+
Hartley Lab for access.
351+
:::
352+
353+
### URL parameters
354+
355+
SPARK passes the following URL parameters when directing a participant to your
356+
study:
357+
358+
- `subject_ID` (required) — the SPARK subject identifier
359+
- `participant_ID` — the participant identifier
360+
- `age` — the participant's age
361+
- `gender` — the participant's gender
362+
363+
These parameters are stored in `api.private.recruitmentInfo` and can be
364+
accessed anywhere in your experiment code. For example, you can use
365+
`api.private.recruitmentInfo.age` and `api.private.recruitmentInfo.gender` in
366+
`src/user/components/InformedConsentText.vue` to display age-appropriate consent
367+
forms (e.g., showing a parental consent form for participants under 18).
368+
369+
The study URL format is:
370+
371+
```
372+
https://your-deploy-host/e/your-code-name/#/welcome/spark/?subject_ID=XXXX&participant_ID=XXXX&age=XX&gender=XXXX
373+
```
374+
375+
### How completion works
376+
377+
When a participant finishes the study, the thanks page provides a button that
378+
redirects them to:
379+
380+
```
381+
https://spark.hartleylab.org/completed/${subject_ID}
382+
```
383+
384+
This marks the participant's session as complete in the SPARK system.
385+
386+
### Testing in developer mode
387+
388+
In the developer tools sidebar, you can select "spark" from the **Service**
389+
dropdown to simulate SPARK recruitment during development. The SPARK card in the
390+
recruitment chooser will launch with test parameters so you can verify the full
391+
flow including the thanks/completion redirect.
392+
341393
## Crowd-sourcing
342394

343395
In the future the lab might make a citizen science recruitment portal. To

src/builtins/thanks/ThanksView.vue

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,41 @@ onMounted(() => {
301301
</TitleTwoCol>
302302
</div>
303303

304+
<!-- SPARK recruitment service completion -->
305+
<div v-if="api.getRecruitmentService() == 'spark'">
306+
<TitleTwoCol leftFirst leftWidth="w-1/3" :responsiveUI="api.config.responsiveUI">
307+
<template #title>
308+
<h1 class="text-3xl font-bold mb-4">
309+
<i-fa6-solid-square-check class="inline mr-2" />&nbsp;Thanks for your contribution to science!
310+
</h1>
311+
<p class="text-lg mb-8">
312+
Please click the button below to return to SPARK and mark your participation as complete. We really
313+
appreciate your time.
314+
</p>
315+
</template>
316+
<template #left>
317+
<div class="text-left text-muted-foreground">
318+
<h3 class="text-lg font-bold mb-2">Study Complete</h3>
319+
<p class="text-sm text-muted-foreground">
320+
Click the button to return to SPARK and confirm your completion of this study.
321+
</p>
322+
</div>
323+
</template>
324+
<template #right>
325+
<div class="border border-border text-left bg-muted p-6 rounded-lg">
326+
<Button
327+
variant="default"
328+
as="a"
329+
:href="`${appconfig.spark.completionUrl}/${api.private.recruitmentInfo.subject_ID}`"
330+
>
331+
Return to SPARK
332+
<i-fa6-solid-arrow-right />
333+
</Button>
334+
</div>
335+
</template>
336+
</TitleTwoCol>
337+
</div>
338+
304339
<!-- Web recruitment service completion -->
305340
<div v-if="api.getRecruitmentService() == 'web'">
306341
<TitleTwoCol leftFirst leftWidth="w-1/3" :responsiveUI="api.config.responsiveUI">

src/core/config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ export default {
103103
experimentId: import.meta.env.VITE_SONA_PAID_EXPERIMENT_ID,
104104
creditToken: import.meta.env.VITE_SONA_PAID_CREDIT_TOKEN,
105105
},
106+
spark: {
107+
completionUrl: 'https://spark.hartleylab.org/completed',
108+
},
106109
firebaseConfig: {
107110
apiKey: import.meta.env.VITE_FIREBASE_APIKEY,
108111
authDomain: import.meta.env.VITE_FIREBASE_AUTHDOMAIN,

src/core/stores/smilestore.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ const initBrowserEphemeral = {
204204
'#/welcome/citizensci/?CITIZEN_ID=XXXXX&CITIZEN_STUDY_ID=123RVWYBAZW00EXAMPLE&CITIZEN_SESSION_ID=AZ3456EXAMPLE',
205205
sona: '#/welcome/sona/?survey_code=SONA_TEST_12345',
206206
sona_paid: '#/welcome/sona_paid/?survey_code=SONA_PAID_TEST_67890',
207+
spark:
208+
'#/welcome/spark/?subject_ID=SPARK_TEST_001&participant_ID=SPARK_PID_001&age=14&gender=female',
207209
web: '#/welcome',
208210
},
209211
}

src/core/utils/utils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ export function processQuery(query, service) {
7474
smilestore.setRecruitmentService(service, {
7575
survey_code: urlParams.survey_code,
7676
})
77+
} else if (service === 'spark' && urlParams.subject_ID) {
78+
log.log('Spark mode')
79+
smilestore.setRecruitmentService(service, {
80+
subject_ID: urlParams.subject_ID,
81+
participant_ID: urlParams.participant_ID || '',
82+
age: urlParams.age || '',
83+
gender: urlParams.gender || '',
84+
})
7785
} else if (
7886
service === 'citizensci' &&
7987
urlParams.CITIZEN_ID &&

src/dev/developer_mode/RecruitmentChooserView.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ const api = useViewAPI()
140140
</CardContent>
141141
</Card>
142142

143+
<!-- SPARK Platform Card -->
144+
<Card class="flex flex-col">
145+
<CardHeader>
146+
<CardTitle>SPARK</CardTitle>
147+
<CardDescription
148+
>SPARK is a recruitment service from the Hartley Lab for adolescent participants of various
149+
ages.</CardDescription
150+
>
151+
</CardHeader>
152+
<CardContent class="flex justify-end flex-1 items-end">
153+
<Button asChild variant="default" size="xs" class="is-red" id="spark_tester">
154+
<a :href="api.urls['spark']"
155+
><i-lucide-dices /> SPARK User
156+
<ArrowRight class="inline-block ml-1 w-4 h-4" />
157+
</a>
158+
</Button>
159+
</CardContent>
160+
</Card>
161+
143162
<!-- Citizen Science Platform Card -->
144163
<Card class="flex flex-col">
145164
<CardHeader>

0 commit comments

Comments
 (0)