Technical infrastructure for a prospective, randomized controlled, double-blind, 2×2 factorial vignette study examining implicit bias in emergency pain management decisions.
This repository contains the complete technical stack used to implement automated, blind randomization for an online vignette study. The system was designed to meet three core methodological requirements:
- True randomization —> participants are assigned to study arms without investigator involvement
- Double-blinding —> participants cannot identify their assigned arm; all four study arms are visually identical
- Full anonymity —> no personally identifiable information (name, IP address, email) is collected or stored at any stage
Design: Prospective, randomized controlled, double-blind, 2×2 factorial experimental vignette study
Research Question: Do medical students exhibit implicit bias in analgesic prescribing decisions when presented with patients bearing substance-abuse-associated visual characteristics?
| Objective Pain Source (e.g., ankle fracture) | Subjective Pain Source (e.g., renal colic) | |
|---|---|---|
| Substance abuse-associated appearance | Arm 1 | Arm 2 |
| Non-Substance abuse appearance | Arm 3 | Arm 4 |
The critical bias detection comparison is Arm 2 vs. Arm 4: identical clinical presentation (renal colic), differing only in patient visual appearance.
Patient images were synthetically generated using MidJourney v6 (Midjourney Inc.) to ensure privacy compliance while maintaining experimental control over visual characteristics.
Participant scans QR code / opens link
↓
Cloudflare Worker (XYZ.com/page)
— masks n8n infrastructure from participants
↓
GET /informedconsent → n8n serves informed consent HTML page
↓
Participant reads consent and clicks "I agree"
↓
POST /informedconsent → n8n executes block randomization
↓
┌─────────────────────────────────┐
│ Assigns participant to Arm 1–4 │
│ Generates anonymous UUID │
│ Logs to Google Sheets │
└─────────────────────────────────┘
↓
Participant is silently redirected
to their assigned JotForm survey
| Component | Tool | Purpose |
|---|---|---|
| Automation & webhook | n8n (Cloud) | Randomization logic, routing, logging |
| Edge proxy | Cloudflare Workers | URL masking, SSL termination, CORS handling |
| Informed consent UI | Vanilla HTML/CSS/JS | Consent page served dynamically by n8n |
| Data collection | JotForm | Four independent survey forms (one per arm) |
| Randomization log | Google Sheets | Real-time arm balance monitoring |
Block randomization with a fixed block size of 4 was implemented using the Fisher-Yates shuffle algorithm. This ensures perfect arm balance at every fourth participant while maintaining allocation concealment.
// Block randomization — Fisher-Yates shuffle
const arms = [1, 2, 3, 4];
for (let i = arms.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arms[i], arms[j]] = [arms[j], arms[i]];
}Arm counts and the running participant total are persisted in n8n's built-in Static Data store, ensuring state is maintained across sessions without a dedicated database.
Each participant receives an anonymous UUID (format: P-XXXX-XXXX-XXXX) generated at the time of assignment. This ID appears in the Google Sheets log alongside arm assignment and timestamp, but contains no personal information.
├── README.md # This file
├── n8n_workflow.json # Importable n8n workflow
├── cloudflare_worker.js # Cloudflare Worker edge proxy script
└── consent_page/
└── informedconsent.html # Informed consent HTML page
- n8n Cloud account (or self-hosted n8n instance)
- Cloudflare account with a domain under Cloudflare DNS
- Google account (for Sheets logging)
- Four JotForm survey forms (one per study arm)
- Open n8n → Workflows → Import from file
- Upload
n8n_workflow.json - In the Randomization & Generate ID (Code) node, replace the four
formUrlsvalues with your own JotForm links - Connect your Google Sheets credential and update the Sheet ID
- Activate the workflow (toggle top-right) — note the Production webhook URL
- Cloudflare Dashboard → Workers & Pages → Create Worker
- Paste the contents of
cloudflare_worker.js - Update
N8N_BASE_URLwith your n8n Production webhook URL - Deploy and add a route:
yourdomain.com/calisma* - Add a DNS AAAA placeholder record if needed:
@ → 100:: (Proxied)
The consent page (informedconsent.html) is served dynamically by the n8n GET webhook — no separate hosting is required. The Cloudflare Worker automatically rewrites all internal URLs so the n8n domain is never exposed to participants.
- No IP addresses, email addresses, or any personally identifiable information are collected
- Participant identifiers are randomly generated UUIDs with no link to real-world identity
- The study was conducted in accordance with the Declaration of Helsinki
- Ethical approval: Ufuk University Clinical/Non-interventional Research Ethics Committee; approval no 26.02.27.05/04 and date 02.27.2026
- Acknowledgment: This study supported by the Ufuk University Scientific Research Projects (BAP) program (UFUK-BAP-2026-004).
If you use this infrastructure in your own research, please cite:
@misc{kanbakan2026implicitbias,
author = {Kanbakan, Altuğ},
title = {Randomization Infrastructure for Double-Blind Online Vignette Studies},
year = {2026},
publisher = {GitHub},
url = {https://github.com/altugkanbakan/[repo-name]}
}Full study citation will be updated upon publication.
This project is licensed under the MIT License — you are free to use, adapt, and redistribute this infrastructure for your own research.