A small Wizard-of-Oz study app built with Node.js, Express, and Socket.IO. A researcher rings for permission and the agent may only speak once every connected participant has agreed. Participants can take part either through the web interface or through the bundled Chrome extension, which shows a raised 🖐️ overlay and a desktop notification when the agent wants to talk.
/— links to both interfaces/participant— participant web interface/wizard— researcher interface/health— returns{ "status": "ok" }chrome-extension/— participant Chrome extension (see its own README)
The server is authoritative and keeps the session state in memory. Each snapshot sent to clients contains:
{
"permissionRequested": false,
"permissionGranted": false,
"agreedCount": 0,
"participantCount": 0
}
- The researcher clicks Ring for permission to set
permissionRequestedtotrue. - Each participant agrees individually (clicking the 🖐️ overlay, the web Allow agent to talk button, or the notification button).
- Unanimous consent:
permissionGrantedbecomestrueonly once every connected participant has agreed (agreedCount >= participantCount, with at least one participant). agreedCount/participantCountare broadcast live so every interface can show an "X of Y agreed" tally.
- Ring for permission — starts a new request and clears prior agreements.
- Reset — clears
permissionRequested/permissionGrantedand all agreements without disconnecting participants. This makes the 🖐️ overlays disappear from every participant's screen. - Disconnect all — forcibly disconnects every connected participant. They must explicitly reconnect to rejoin.
Participants must opt in to connect (there is no automatic connection), which avoids stale sockets from tabs or extension workers left open:
- Web: open
/participantand click Connect. Click Disconnect to leave. - Chrome extension: click the toolbar icon and press Connect. When the agent wants to talk, a bouncing 🖐️ appears at the top-left of the current page (with a chime and a desktop notification) and an "X/Y YES" tally. Clicking the hand records agreement — it stays on screen with a green outline until the researcher resets. See chrome-extension/README.md for install and configuration steps.
- Install dependencies:
npm install
- Start the server:
npm start
- Open the interfaces:
- To test multiple participants, open several browser tabs pointed at http://localhost:3000/participant and click Connect in each. The researcher page shows the live participant count and agreement tally.
- (Optional) Load the participant Chrome extension from the
chrome-extension/folder and point it athttp://localhost:3000— see its README.
- Push this repository to GitHub.
- In Railway, create a new project and deploy from the GitHub repository.
- Railway runs the app with
npm start(defined inpackage.json) and injectsPORTautomatically. - In the service settings, generate a public domain.
- Open these routes on the generated domain:
/participant/wizard
- In the Chrome extension's Settings, set the Study server URL to the
generated
https://…domain, then Save & reconnect.
- No database, authentication, or session IDs are used.
- CORS is enabled (
origin: true) so thechrome-extension://origin can connect. - All state is stored in server memory and will reset whenever the Railway service restarts (redeploys, crashes, or sleeps).