An open-source, research-grade sleep diary app built with React Native and Expo. Available on iOS, Android, and the web. Designed to be easily tailored by researchers, clinicians, and developers for their own sleep studies and clinical needs.
๐ Web app: https://sleepdiaries.circadia-lab.uk
๐งฌ Adapting this for your own study? Use SleepDiaries Protocol instead โ a template repository that seeds a clean copy of a specific release with lab-specific config already stripped out.
Sleep Diaries is a cross-platform app (iOS, Android, and web) that guides users through structured morning and evening questionnaires to track their sleep patterns over time. It is based on consensus sleep diary methodology used in clinical sleep research.
The app is intentionally simple and modular โ the question sets, input types, themes, and data storage can all be customised without touching the core navigation or UI logic.
It also includes a suite of validated one-time research questionnaires (ESS, ISI, MEQ, PSQI, and others), a scored final report unlocking after 14 diary days, and support for researcher-assigned participant codes โ making it suitable for deployment in structured sleep studies.
- ๐ Morning entry โ 13-question diary covering bedtime, sleep onset, night wakings, final awakening, sleep quality, and restedness
- ๐ Evening entry โ 5-question diary covering naps, caffeine, exercise, and medication
- โฑ๏ธ Rich input types โ 24-hour time stepper, duration stepper, yes/no, 1โ5 rating scale, number counter, medication tracker, and free text
- ๐ Conditional questions โ follow-up questions appear automatically based on previous answers
- ๐จ Dual themes โ amber for morning entries, blue for evening entries
- ๐พ Local persistence โ all entries saved to device storage via AsyncStorage
- ๐ Past entries โ scrollable history grouped by date with expandable answer cards
- ๐ Final report โ auto-unlocks after 14 morning entries, computes sleep metrics with colour-coded reference bands
- ๐ญ Sleep pattern actogram โ weekly chart of bedtime to out-of-bed time with night-waking markers and a sleep-midpoint trend line, so drifting schedules and missed days are visible at a glance
- ๐ฏ Age-aware reference ranges โ optional age group (under 18, 18โ64, 65+) chosen at onboarding or in the Profile adjusts the green/amber/red bands for sleep duration, latency and WASO; stored on the device only
- ๐ Data-safety reminders โ entries live on the device, so the Home tab nudges participants to install the PWA (web) and to export a backup; the browser is also asked to keep storage persistent
- ๐ค Data export โ CSV and JSON export via native share sheet, including questionnaire results
- ๐ผ๏ธ Share card โ share a branded sleep report image to social media from the final report screen, with the original home screen background; works on iOS, Android, and mobile web (PWA)
- ๐ Push notifications โ daily 8am and 9pm reminders
- โ๏ธ Settings โ notifications toggle, text-to-speech, language, questionnaire credits, account management
- ๐ค Profile โ editable name and research code, summary stats, sleep metrics glossary, quick actions
- ๐ Entry tab stats โ streak, entry counts, days in study
- ๐ฅ JSON import โ restore a backup or migrate between devices, with merge or replace (imports questionnaire results too)
- ๐ฑ iOS & Android โ single codebase via React Native + Expo
- ๐ Web โ Progressive Web App (PWA) installable on any device
- ๐ฒ Installable โ installs to home screen on iOS, Android, and desktop Chrome with full offline support
- ๐ Localisation โ English, Portuguese (Brazil) ๐ง๐ท and Swedish ๐ธ๐ช (UI and daily diary), locale detected automatically from device settings
- ๐งฉ Fully coded UI โ entry cards, the completion screen, tab bar, nav buttons and backgrounds are drawn in code with no per-language artwork, so a new language only needs strings
- ๐ Research questionnaires โ validated one-time instruments (ESS, ISI, DBAS-16, MEQ, PSQI, RU-SATED, STOP-BANG, MCTQ) accessible from the Profile, with results unlocking after 14 diary days
- ๐ My Medications โ save regular treatments to your profile; they auto-populate the morning and evening medication questions
SleepDiaries/
โโโ app/ # expo-router file-based navigation
โ โโโ _layout.jsx # Root stack navigator + asset preloading + PWA splash
โ โโโ index.jsx # Onboarding / name entry screen (+ research code)
โ โโโ questionnaire.jsx # Step-by-step questionnaire (morning or evening)
โ โโโ past-entries.jsx # Scrollable entry history
โ โโโ final-report.jsx # Sleep metrics summary report
โ โโโ export.jsx # CSV / JSON export + JSON import
โ โโโ EntryDatePrompt.jsx # "Which night is this for?" prompt for entries made after midnight
โ โโโ QuestionnaireScreen.jsx # Full-screen runner for one-time research questionnaires
โ โโโ InstructionsModal.jsx # Full-screen instructions slideshow (coded, no PNGs)
โ โโโ ProfileModal.jsx # Profile sheet (name, code, stats, glossary, questionnaires)
โ โโโ QuestionnaireModal.jsx # Step-by-step one-time research questionnaire modal
โ โโโ MedicationsScreen.jsx # Saved medication presets (accessible from Profile modal)
โ โโโ SleepMetricsScreen.jsx # Sleep metrics glossary (push screen from Profile modal)
โ โโโ QuestionnairesScreen.jsx # Questionnaires list (push screen from Profile modal)
โ โโโ QuestionnaireCreditsScreen.jsx # Questionnaire credits (push screen from Settings)
โ โโโ ThresholdReferencesScreen.jsx # References for the metric thresholds used in the final report
โ โโโ (tabs)/ # Tab bar screens
โ โโโ _layout.jsx # Custom tab bar (Ionicons, no image assets)
โ โโโ home.jsx # Home screen
โ โโโ entry.jsx # Entry tab with sleep stats dashboard
โ โโโ settings.jsx # Settings (includes questionnaire credits)
โโโ components/
โ โโโ ActogramChart.jsx # Weekly sleep pattern chart for the final report (react-native-svg)
โ โโโ AgeBandPicker.jsx # Optional age group selector (onboarding + Profile)
โ โโโ BottomCards.jsx # Past Entries and Final Report shortcut cards
โ โโโ DataSafetyBanner.jsx # Install / back-up reminder on the Home tab
โ โโโ EntryCardContent.jsx # Morning / evening entry cards (all languages, no PNGs)
โ โโโ EntryCompleteSplash.jsx # "Entry complete" screen shown after saving
โ โโโ NavButtons.jsx # Questionnaire Back / Next buttons
โ โโโ ScreenBackground.jsx # Shared gradient/background wrapper used across screens
โโโ data/
โ โโโ questions.js # โญ Daily diary question definitions โ start here to customise
โ โโโ questions.pt-BR.js # Portuguese (BR) translations of question text
โ โโโ questions.sv.js # Swedish translations of question text
โ โโโ useQuestions.js # Merges locale overrides at startup
โ โโโ questionnaires.js # โญ One-time research questionnaire definitions (ESS, ISI, etc.)
โโโ i18n/
โ โโโ index.js # Locale detector + t() helper (interpolation, plurals)
โ โโโ en.js # English strings
โ โโโ pt-BR.js # Portuguese (Brazil) strings
โ โโโ sv.js # Swedish strings
โโโ storage/
โ โโโ storage.js # AsyncStorage helpers + CSV/JSON export + import
โ โโโ EntriesContext.jsx # React Context โ shared entry cache consumed by all screens
โ โโโ notifications.js # Push notification scheduling
โโโ utils/
โ โโโ alert.js # Cross-platform Alert helper (web fallback)
โ โโโ constants.js # โญ Shared constants (e.g. MIN_ENTRIES_FOR_REPORT)
โ โโโ dataSafety.js # Persistent-storage request and install / back-up reminder rules
โ โโโ dateEntry.js # Entry-date logic for post-midnight entries and the evening gate
โ โโโ metrics.js # Final-report metrics (duration, efficiency, SOL, WASO, ...)
โ โโโ referenceRanges.js # โญ Age-banded reference ranges and colour logic for the final report
โ โโโ stats.js # Shared stat helpers (computeStats)
โโโ theme/
โ โโโ colors.js # โญ Central colour palette and morning/evening themes
โ โโโ typography.js # Font constants (Livvic, Afacad)
โ โโโ useInsets.js # Cross-platform safe area hook
โโโ web/
โ โโโ manifest.json # PWA manifest
โ โโโ sw.js # Service worker (offline support)
โ โโโ icons/ # PWA icons (192px, 512px)
โ โโโ splashscreens/ # iPhone/iPad splash screens
โโโ scripts/
โ โโโ deploy.sh # Web export + PWA injection + deploy prep (with release-branch guard)
โ โโโ fix-paths.js # Rewrites asset paths for sub-path (GitHub Pages) hosting
โ โโโ crop_taskbars.py # Legacy utility to centre-crop taskbar image assets
โโโ assets/
โ โโโ images/ # Logo, social preview and splash icon; index.js maps them
โโโ __tests__/ # Jest tests (metrics, stats, storage, export, i18n and translation keys, questionnaires, Swedish, reference ranges, data safety)
โโโ .github/workflows/
โ โโโ test.yml # Runs the Jest suite and a web build check on every push and pull request
โ โโโ release-pr.yml # Opens a main โ release PR pinned to a version tag
โโโ metro.config.js # Metro bundler config (SVG support)
โโโ declarations.d.ts # TypeScript declaration for SVG imports
โโโ app.json # Expo configuration
โโโ package.json # Dependencies
- Node.js v18 or later
- Expo CLI
- Expo Go on your phone, or Xcode (iOS simulator) / Android Studio (Android emulator)
# Clone the repository
git clone https://github.com/circadia-bio/SleepDiaries.git
cd SleepDiaries
# Install dependencies
npm install
# Start the development server
npx expo startThen press i for iOS simulator, a for Android emulator, or scan the QR code with Expo Go on your phone.
npx expo start --webnpm run deployThis runs the deploy script which exports the web build, injects PWA tags, copies assets, and outputs everything to the docs/ folder.
Production is deployed from the release branch, not main. main is the integration branch: pull requests (new features, translations) merge there and get a Netlify branch-deploy preview, while release only moves when you cut a version, so unreleased work can never reach users by accident.
- Bump the version (
app.json,package.json,CITATION.cff,CHANGELOG.md,README.md) onmain, then tag it:git tag v1.2.0 && git push origin v1.2.0 - Run Actions โ Open release PR with that tag. It opens a PR into
releasefrom a snapshot of the tag (release-candidate/v1.2.0), so anything merged tomainafterwards is not included. It fails if the tag is not onmainor does not match the version inpackage.json. - Merge the PR. Netlify then deploys
releaseto production.
scripts/deploy.sh includes a guard: locally it refuses to run unless you are on release with no uncommitted changes to tracked files (override with FORCE_DEPLOY=1); on Netlify it fails any production build that is not from release, while deploy previews and branch deploys are allowed.
The workflow needs Allow GitHub Actions to create and approve pull requests enabled under Settings โ Actions โ General (and at organisation level for org-owned repositories).
๐ Live web app: https://sleepdiaries.circadia-lab.uk
The app detects the device locale at startup using expo-localization and selects the appropriate language automatically. No in-app language switcher is required โ it just works.
| Language | Locale code | Status |
|---|---|---|
| ๐ฌ๐ง English | en |
โ Complete |
| ๐ง๐ท Portuguese (Brazil) | pt-BR |
โ Complete |
| ๐ธ๐ช Swedish | sv, sv-SE, sv-FI |
UI and daily diary; research instruments remain in English |
Swedish is selected automatically for Swedish device/browser locales, including Sweden and Finland. Restart the app after changing the device/browser language. Notification text, sharing controls, report labels, dates and decimal separators (e.g. "7,5" in Swedish and Portuguese) also follow the locale. If reminders were already enabled before changing language, switch reminders off and back on in Settings to reschedule their text in the new language.
The Swedish daily diary and instructions are an unvalidated app translation, not an authorized or clinically validated Swedish Consensus Sleep Diary version. Research instrument titles, instructions, questions, response options, scale anchors, credits and interpretations remain in their original English. A Swedish notice makes this explicit in the questionnaire list, both questionnaire views, and the final report. Scoring, stored answer values and CSV/JSON keys are unchanged.
The Swedish alcohol help retains the source diary's 355/150/45 ml serving sizes. It clarifies that these servings are not equivalent to UK alcohol units; no numeric thresholds or calculation logic have been changed.
All other locales fall back to English.
All UI strings are defined in i18n/en.js, i18n/pt-BR.js and i18n/sv.js. The i18n/index.js module resolves the correct bundle at startup and exports a t() helper used throughout the app:
import t from '../i18n';
t('login.cta') // "Let's go" / "Vamos lรก"
t('home.entriesNeeded', { count: 3 }) // "3 more entries needed" / "Faltam 3 registros"The helper supports {{variable}} interpolation and automatic _one / _other pluralisation.
Question text, rating labels, units, and placeholders are defined separately in data/questions.<locale>.js (questions.pt-BR.js, questions.sv.js) and merged over the base English definitions at startup by data/useQuestions.js. Only translatable fields are overridden โ IDs, types, defaults, and conditional logic remain in data/questions.js.
- Create
i18n/<locale>.jsfollowing the structure ofen.js - Create
data/questions.<locale>.jsfor the question text - Add the locale to the
TRANSLATIONSmap ini18n/index.js - Register the question overrides in
data/useQuestions.js - Add the locale to the
LANGUAGE_NAMESmap inapp/(tabs)/settings.jsx - Add the strings for the entry cards and completion screen under
appText(morningCard,eveningCard,entryPendingMorning,entryDoneMorning,entryLocked,entrySavedMorning,homepage, ...). No image assets are needed
Everything that used to be baked into PNGs is now rendered in code from the i18n strings: the morning/evening entry cards (components/EntryCardContent.jsx), the entry-complete screen (components/EntryCompleteSplash.jsx), the tab bar, the questionnaire nav buttons, the instructions slideshow, the bottom shortcut cards and the screen backgrounds. Adding a language therefore only needs strings, never new image exports.
Sleep Diaries includes a set of validated one-time research questionnaires accessible from the Profile screen. These complement the daily diary by capturing baseline clinical and chronobiological characteristics of participants.
Note on permissions: Several instruments are protected by copyright. It is the responsibility of the researcher or institution deploying this app to obtain the necessary permissions before using any instrument in a study. See the
creditfield indata/questionnaires.jsor Settings โ Questionnaire credits in the app for per-instrument details.
| Instrument | Full name | Items | Scale | Measures |
|---|---|---|---|---|
| ESS | Epworth Sleepiness Scale | 8 | 0โ3 per item (max 24) | Daytime sleepiness |
| ISI | Insomnia Severity Index | 7 | 0โ4 per item (max 28) | Insomnia severity |
| DBAS-16 | Dysfunctional Beliefs and Attitudes about Sleep | 16 | 0โ10 mean (max 10) | Sleep-related cognitions |
| MEQ | MorningnessโEveningness Questionnaire | 19 | Weighted sum (max 86) | Chronotype |
| PSQI | Pittsburgh Sleep Quality Index | 17 | 7-component global (max 21) | Sleep quality |
| RU-SATED | Ru-SATED Sleep Health Scale | 6 | 0โ4 per item (max 24) | Multidimensional sleep health |
| STOP-BANG | STOP-BANG Questionnaire | 8 | Yes/No count (max 8) | OSA risk screening |
| MCTQ | Munich Chronotype Questionnaire | 7 | MSFsc (clock time) + SJL (hours) | Chronotype + social jetlag |
Questionnaires appear in the Profile modal under a dedicated section. Each can be completed at any time, but results are withheld until 14 morning diary entries have been collected โ matching the same threshold as the final report. This ensures results reflect a participant who has completed an adequate baseline period.
Once the threshold is met, the scored result and a colour-banded interpretation are shown both in the profile and on the completion screen. A Redo option is available for follow-up timepoints, with a confirmation prompt before overwriting any existing result.
All questionnaire definitions live in data/questionnaires.js. Each instrument is a plain JavaScript object:
export const MY_SCALE = {
id: 'myscale',
title: 'My Scale',
shortTitle: 'MS',
beta: true,
credit: 'Author, A. (Year). Journal, vol(issue), ppโpp. ยฉ Rights holder.',
instructions: 'Instructions shown to the participant before item 1.',
reference: 'Short citation string shown on the result screen.',
items: [
{
id: 'ms1', number: 1,
text: 'Question text',
type: 'scale_0_3', // see supported input types below
options: [ ... ],
},
],
score: (answers) => /* return a number or object */,
interpret: (score) => ({
label: 'Label',
color: '#hex',
description: 'Plain-language description shown to the participant.',
}),
};
// Add to the registry:
export const QUESTIONNAIRES = [..., MY_SCALE];| Type | Description |
|---|---|
scale_0_3 |
4-option labelled scale (0โ3) |
scale_0_4 |
5-option labelled scale (0โ4) |
scale_0_10 |
11-point circular picker (0โ10) |
scale_1_10 |
10-option labelled scale (1โ10) |
single_choice |
Pick one from a list of options with explicit values |
yes_no |
Yes / No |
frequency_3 |
Rarely or never / Sometimes / Usually or always |
frequency_4 |
Not during the past month / <once/week / 1โ2ร/week / โฅ3ร/week |
time |
HH:MM stepper |
duration_min |
Integer minutes stepper |
number |
Integer stepper with min/max/unit |
Any item can also include an optional hint string, which renders as a small info box below the question text โ useful for clarifying ambiguous items (e.g. the MCTQ free-day bedtime question).
Several instruments are protected by copyright. The credit field on each definition (visible in Settings โ Questionnaire credits) lists the citation and permission status. A summary:
| Instrument | Status |
|---|---|
| ESS | ยฉ Murray W. Johns โ permission required for commercial use |
| ISI | ยฉ Charles M. Morin โ available for non-commercial research |
| DBAS-16 | ยฉ Charles M. Morin โ available via MAPI Research Trust |
| MEQ | Public domain |
| PSQI | ยฉ University of Pittsburgh โ permission required; contact authors |
| RU-SATED | ยฉ University of Pittsburgh โ permission required; contact authors |
| STOP-BANG | ยฉ University Health Network, Toronto โ free for non-commercial research (stopbang.ca) |
| MCTQ | ยฉ Till Roenneberg, LMU Munich โ free for non-commercial research (thewep.org) |
| KSS | Freely available for research use (defined but not currently active) |
It is the responsibility of the researcher or institution deploying this app to obtain the necessary permissions before using any instrument in a study.
Entries exported as JSON from Sleep Diaries can be imported back into the app โ useful for restoring a backup, transferring data between devices, or migrating participants between study phases.
- Go to Settings โ Export Data
- Scroll to Import from JSON at the bottom
- Tap it and select your
.jsonfile from Files - If you already have entries on the device, you will be asked how to handle the conflict:
| Option | What it does |
|---|---|
| Merge | Keeps all existing entries and adds any new ones from the file. Duplicate entries (same date and type) are skipped. Questionnaire results are imported only if not already present. |
| Replace | Deletes all existing entries and questionnaire results, and replaces them with the imported data. Requires a second confirmation. |
The import expects a JSON file previously exported by Sleep Diaries. The file must contain an entries array. A questionnaires array is imported if present.
{
"participant": "Lucas",
"researchCode": "STUDY-001",
"exportedAt": "2025-01-15T10:30:00Z",
"entries": [
{
"id": "2025-01-14-morning",
"type": "morning",
"date": "2025-01-14",
"completedAt": "2025-01-14T08:22:00Z",
"answers": { "...": "..." }
}
],
"questionnaires": [
{
"id": "ess",
"completedAt": "2025-01-14T09:00:00Z",
"answers": { "ess1": 2, "ess2": 1, "...": "..." },
"score": 12
}
]
}On the web version, tapping Import opens your browser's file picker instead of the native Files app.
Sleep Diaries is a Progressive Web App (PWA) โ it can be installed directly to your home screen from the browser, with no App Store required. Once installed it runs full-screen, works offline, and behaves like a native app.
- Open sleepdiaries.circadia-lab.uk in Safari
- Tap the Share button (box with arrow pointing up)
- Scroll down and tap Add to Home Screen
- Tap Add โ the app icon will appear on your home screen
Note: PWA installation on iOS only works in Safari, not Chrome or Firefox.
- Open sleepdiaries.circadia-lab.uk in Chrome
- Tap the three-dot menu (โฎ) in the top right
- Tap Add to Home screen or Install app
- Tap Install โ the app icon will appear on your home screen
- Open sleepdiaries.circadia-lab.uk
- Click the install icon (โ) in the address bar
- Click Install
All questions are defined in a single file: data/questions.js
Each question is a plain JavaScript object with a type field that controls how it renders. To add, remove, or reorder questions, simply edit this file โ no other changes are needed.
{
id: 'mq1', // Unique identifier (used for conditional logic)
number: 1, // Display number shown on screen
text: 'Question text', // The question shown to the user
type: 'time', // Input type (see below)
defaultValue: { ... }, // Optional starting value
optional: true, // If true, user can skip without answering
}| Type | Description | Use for |
|---|---|---|
time |
24-hour hour:minute stepper | Bedtime, wake time |
duration |
Hours + minutes stepper | Time to fall asleep, nap length |
yes_no |
Large Yes / No buttons | Binary questions |
rating |
1โ5 labelled option buttons | Sleep quality, restedness |
number |
+/- counter with unit label | Number of drinks, wake-ups |
medication |
Add/edit/delete entries with dose and time | Medication tracking |
text_input |
Multiline free text | Comments, notes |
// Parent question
{
id: 'mq4',
text: 'Did you wake up during the night?',
type: 'yes_no',
followUp: 'mq4b',
},
// Follow-up โ only shown if mq4 === 'yes'
{
id: 'mq4b',
text: 'How many times did you wake up?',
type: 'number',
conditionalOn: { id: 'mq4', value: 'yes' },
},All colours live in theme/colors.js (fonts are in theme/typography.js):
COLORSโ the shared brand palette (navy, blue, orange, light blue, background), the green/amber/red status colours used in the final report, andtextMuted, the grey used for hints and captionsTHEME.morningandTHEME.eveningโ the amber and blue looks used by the daily questionnaire, the entry cards and the entry-complete screen. Change a value there and all three follow
import { COLORS, THEME } from '../theme/colors';
THEME.morning.primary; // '#E07A20' โ questionnaire buttons, text, progress bar
THEME.evening.entryFrom; // gradient start of the evening entry card
COLORS.status.good; // report greentextMuted is #64748B (about 4.8:1 on white) so small grey text stays readable; if you change it or the entry-card colours, check the contrast ratio. Some older screens still use hex values inline and can move to these tokens over time.
The app uses expo-router with file-based routing:
index.jsx โ Onboarding (shown on first launch, skipped if name saved)
(tabs)/home โ Main home screen (+ InstructionsModal + ProfileModal)
(tabs)/entry โ Entry tab with sleep stats dashboard
(tabs)/settings โ Settings (includes questionnaire credits)
questionnaire โ Full-screen questionnaire (slides up, hides tab bar)
past-entries โ Entry history
final-report โ Sleep metrics report
export โ CSV / JSON export + JSON import
The ProfileModal also hosts the QuestionnaireModal inline โ tapping Start or Redo on a questionnaire opens it as a page sheet on top of the profile, without leaving the screen. InstructionsModal is a standalone screen in app/ pushed from the home screen.
All data is stored locally on the device using @react-native-async-storage/async-storage. No data is sent to any server.
// Stored keys:
// 'user_name' โ participant name string
// 'research_code' โ optional research study identifier
// 'age_band' โ optional age group ('under18' | 'adult' | 'older'); device-only, not exported
// 'last_export_at' โ time of the last successful export (drives the back-up reminder)
// 'data_safety_dismissals' โ when the install / back-up reminders were last dismissed
// 'entries' โ JSON array of diary entry objects
// 'seen_instructions' โ 'true' once the instructions modal has been dismissed
// 'questionnaire_{id}' โ one object per completed one-time questionnaire
// 'medication_presets' โ JSON array of saved medication preset objects
// Diary entry structure:
{
id: '2024-01-15-morning',
type: 'morning',
date: '2024-01-15',
completedAt: '2024-01-15T08:32:00Z',
answers: {
mq1: { hour: 22, minute: 30 },
mq4: 'yes',
mq4b: 2,
mq11: 4,
// ...
}
}
// Questionnaire result structure:
{
id: 'ess',
completedAt: '2024-01-15T09:00:00Z',
answers: { ess1: 2, ess2: 0, /* ... */ },
score: 12 // number, or object for computed instruments (e.g. MCTQ: { msf_sc, sjl })
}This app implements the Consensus Sleep Diary (CSD) โ a standardised instrument for clinical and research settings. The morning questions cover:
- Sleep onset latency
- Number and duration of night wakings
- Early morning awakening
- Total sleep time (computed)
- Sleep efficiency (computed)
- Sleep quality and restedness
The final report (unlocked after 14 morning entries) automatically computes:
| Metric | Formula |
|---|---|
| Total sleep time | Time in bed โ sleep onset latency โ WASO |
| Sleep efficiency | Total sleep time รท time in bed ร 100% |
| Sleep onset latency | Average time to fall asleep |
| WASO | Wake after sleep onset |
| Sleep quality | Average of 1โ5 ratings |
| Restedness | Average of 1โ5 ratings |
The report also opens with a sleep pattern actogram (components/ActogramChart.jsx): one bar per night from bedtime to out-of-bed time, shaded by time asleep and time awake in bed, with red markers for the number of night wakings and a dashed line tracing the midpoint of sleep. It shows seven days at a time (swipe or use the arrows), and a day with no entry leaves a visible gap instead of closing up. The waking markers show how many times a participant woke, not when, because the diary records a count and a total duration rather than timestamps.
The colour bands on the final report depend on an optional age group (under 18, 18โ64, or 65 and over). Participants can set it during onboarding or change it later in the Profile; tapping the selected option again clears it. It is stored only on the device, is not part of CSV/JSON exports, and defaults to the 18โ64 ranges when left blank.
| Metric | Under 18 | 18โ64 | 65 or over |
|---|---|---|---|
| Sleep duration โ green | 8โ10 h | 7โ9 h | 7โ8 h |
| Sleep duration โ amber | 7โ8 h, 10โ11 h | 6โ7 h, 9โ10 h | 5โ7 h, 8โ9 h |
| Sleep onset latency | green โค30 min, amber 31โ45, red >45 | green โค30 min, amber 31โ45, red >45 | green โค30 min, amber 31โ60, red >60 |
| Wake after sleep onset | green โค20 min, amber 21โ50, red โฅ51 | green โค20 min, amber 21โ40, red โฅ41 | green โค20 min, amber >20 (no red) |
| Sleep efficiency | green โฅ85%, amber 75โ85%, red <75% in every age group |
Duration is red outside the amber band. For latency, WASO and efficiency the colours follow the NSF Sleep Quality Consensus Panel (Ohayon et al., 2017, Sleep Health, 3(1), 6โ19), which rated each value for each age group as appropriate, uncertain or inappropriate: green = appropriate (good sleep quality), amber = uncertain, red = rated poor. The panel rated sleep latency up to 30 minutes as good at every age. It gave no โpoorโ level of WASO for adults 65 and over, so their WASO band is amber above 20 minutes and never red. Efficiency uses โฅ85% as good and โค74% as poor for every group (the paper uses โค64% for 18โ25-year-olds, which the app does not model separately). Duration ranges come from the NSF duration recommendations (Hirshkowitz et al., 2015). The under-18 band uses the teenage (14โ17) values; younger children need more sleep, so add a band if the app is ever used with them.
All of the numbers, the colour logic and the scale-bar geometry live in utils/referenceRanges.js, so changing a threshold is a one-file edit. The same ranges drive the metric cards, the share card and Settings โ Sleep metric thresholds.
The onboarding screen includes an optional research code field. This allows researchers to assign a unique identifier to each participant at enrolment. The code is:
- Saved locally on the device alongside the participant's name
- Included as a
research_codecolumn in CSV exports - Included as a
researchCodefield in JSON exports - Cleared when the participant logs out or deletes their account
Participants leave the field blank if they are using the app independently.
The Profile button on the home screen slides up a modal showing:
- Editable participant name and research code
- Optional age group, which selects the reference ranges used in the final report
- Summary stats: morning entries, evening entries, current streak, member since date
- Questionnaires โ one-time research instruments with status badges and Start/Redo buttons
- Sleep metrics glossary with plain-language explanations of each metric
- Quick actions: replay instructions, link to circadia-lab.uk
The Entry tab shows a live stats dashboard above the entry cards:
- ๐ฅ Current streak (consecutive days with a morning entry)
- Morning entries, evening entries, and days in study (always visible)
- Edit
data/questions.jsto add, remove, or reorder diary questions - Edit
data/questionnaires.jsto add, remove, or reorder one-time instruments - Add new input types in
app/questionnaire.jsxorapp/QuestionnaireModal.jsx - Change the unlock threshold โ edit
MIN_ENTRIES_FOR_REPORTinutils/constants.js(currently 14); the same constant governs the final report, questionnaire result visibility, and the entry-tab stats dashboard - Connect a backend โ replace the
AsyncStoragecalls instorage/storage.jswith API calls
Franรงa, L. G. S., Baehl, B., Howard, J., Kussow, F., Luna Colรณn, Y., & Leocadio-Miguel, M. (2026). Sleep Diaries (v1.2.0) [Software]. Circadia Lab. https://doi.org/10.5281/zenodo.19683378
| Role | Names |
|---|---|
| Principal Investigators | Lucas Franรงa, Mario Leocadio-Miguel |
| Development | Lucas Franรงa |
| Design | Bri Baehl, Jacob Howard, Frederic Kussow, Yuliana Luna Colรณn |
| Swedish translation | Jonatan Nyberg |
The app design was created by exchange students โ Bri Baehl, Jacob Howard, Frederic Kussow, and Yuliana Luna Colรณn โ during the 7th Annual Digital Civics Exchange (DCX), an international programme connecting students across disciplines to co-design civic technologies.
๐ dcx.events
Development of this app was assisted by Claude (Anthropic's AI assistant). Claude helped scaffold the React Native codebase, implement navigation, build the questionnaire engine, set up local storage, push notifications, data export, the final report, the localisation system, and the one-time research questionnaire feature.
Contributions are welcome. If you are adapting this for a research study and want to share improvements back, please open a pull request.
- Fork the repository
- Create a feature branch (
git checkout -b feat/my-feature) - Commit your changes (
git commit -m 'โจ feat: add my feature') - Push to the branch (
git push origin feat/my-feature) - Open a Pull Request
| Package | Version | Purpose |
|---|---|---|
expo |
~55.0.0 | Core Expo SDK |
expo-router |
~55.0.0 | File-based navigation |
expo-localization |
~55.0.12 | Device locale detection |
react-native |
0.83.2 | Cross-platform mobile framework |
react |
19.2.0 | React framework |
@expo/vector-icons |
^15.0.2 | Ionicons icon set |
@react-native-async-storage/async-storage |
2.2.0 | Local data persistence |
expo-notifications |
~55.0.0 | Push notification reminders |
expo-status-bar |
~55.0.0 | Status bar control |
expo-font |
~55.0.4 | Custom font loading |
react-native-paper |
^5.12.0 | UI component library |
react-native-safe-area-context |
5.6.2 | Safe area handling |
react-native-screens |
4.23.0 | Native screen management |
react-native-svg |
15.15.3 | SVG rendering (screen backgrounds, entry cards, completion screen, actogram) |
react-native-svg-transformer |
^1.5.3 | SVG imports as React components |
babel-preset-expo |
~55.0.0 | Babel transpilation |
expo-document-picker |
~55.0.9 | JSON file import |
react-native-view-shot |
4.0.3 | Capture React Native views as images (share card) |
expo-sharing |
~55.0.18 | Native file sharing (share card) |
expo-blur |
~55.0.14 | Blur effects (final report background, profile modal) |
- ๐งฌ SleepDiaries Protocol โ template repo for adapting SleepDiaries to your own study, pinned to a specific release
- ๐งช slumbR โ R package for reading, scoring and analysing Sleep Diaries exports (docs)
- ๐งฎ ScoreMe โ researcher-facing web app for scoring questionnaires from JSON
- ๐ฑ Teenage Sleep Diaries โ fork of the protocol template for adolescent sleep research
- ๐ nonparametric-actigraphy-clustering โ unsupervised clustering of actigraphy rest-activity profiles using nonparametric methods
- โก ACTT_validation_study โ validation study for actigraphy-based sleep staging cut-points
- ๐ฌ circadia-bio โ the Circadia Lab GitHub organisation
Copyright ยฉ Circadia Lab โ Lucas Franรงa & Mario Leocadio-Miguel
Released under the MIT License.
Design by Bri Baehl, Jacob Howard, Frederic Kussow, and Yuliana Luna Colรณn.
Note on third-party questionnaire instruments: The validated sleep questionnaires included in this app (ESS, ISI, DBAS-16, MEQ, PSQI, RU-SATED, STOP-BANG, MCTQ) are the intellectual property of their respective authors and institutions. Their inclusion in this open-source repository does not grant any rights to use them beyond what is permitted by each instrument's licence. See Settings โ Questionnaire credits in the app, or the
creditfield indata/questionnaires.js, for per-instrument copyright and permission details.
- Persist answers with AsyncStorage
- Show name entered at onboarding on home screen
- Past entries screen with history view
- Final report with sleep metrics
- Push notification reminders (morning + evening)
- Data export (CSV / JSON) including questionnaire results
- Web app
- Progressive Web App (PWA) โ installable on iOS, Android, and desktop
- Offline support via service worker
- JSON import with merge/replace (including questionnaire results)
- Optional research code for study participants
- Profile screen with editable participant info, stats, and metrics glossary
- Entry tab sleep stats dashboard
- Automatic deployment via CI/CD
- Full Portuguese (Brazil) localisation โ strings, questions, and image assets
- SVG support via react-native-svg-transformer
- One-time research questionnaires (ESS, ISI, DBAS-16, MEQ, PSQI, RU-SATED, STOP-BANG, MCTQ) (beta)
- Medication presets โ auto-populate diary medication questions from saved treatments
- Share card โ share a branded sleep report image from the final report screen
- Full UI modernisation โ glassy card system, gradient backgrounds, blur effects, refined typography and icons throughout
- Questionnaire result validation and removal of beta flag โ all eight instruments now stable
- Entry date prompt โ participants filling in entries between midnight and 14:00 are asked which night the entry belongs to, correctly attributing data for night owls and delayed sleep schedules
- Swedish localisation โ UI and daily diary (research instruments stay in English)
- Sleep pattern actogram in the final report
- Entry cards and completion screen rendered in code โ no per-language artwork
- Release branch workflow โ production deploys from
releasethrough a tag-pinned pull request - Age-specific reference ranges โ optional age group in onboarding and Profile
- Central colour theme โ morning/evening looks, status colours and muted text in
theme/colors.js - KSS (Karolinska Sleepiness Scale) โ protocol integration pending
- Backend API integration
- Additional language support

