Reflex custom component wrapping @tryvital/vital-link and integrating the Junction (Vital) health data SDK
Project description
reflex-junction
A Reflex custom component for integrating Junction (Vital) health data into your application. Connect wearables and health platforms (Oura, Fitbit, Apple Health, Garmin, etc.) with a few lines of Python.
Features
- Health Data Summaries — Sleep, activity, workouts, body composition, meals, profile
- Vitals Timeseries — Heart rate, HRV, SpO2, glucose, blood pressure, respiratory rate, steps, calories
- Lab Testing — Test panels, orders, biomarker results with range indicators
- Link Widget — React component wrapping
@tryvital/vital-linkfor provider connection UI - Webhooks — Svix signature verification, typed event models, event routing
- Introspection — Resource status, historical pull tracking, provider listing
- Chart-Ready — Computed vars formatted for
rx.recharts(line, bar, composed charts) - Visual Demo — 9-page demo app with sidebar nav, dark theme, and real data visualizations
- Typed Models — Python dataclasses for all data types (no
dict[str, Any]) - Multi-region — US and EU sandbox/production environments
Installation
pip install reflex-junction
Or with your preferred package manager:
uv add reflex-junction
poetry add reflex-junction
Quick Start
1. Get an API key
Sign up at tryvital.io and grab your API key from the dashboard.
2. Wrap your app
import os
import reflex as rx
import reflex_junction as junction
app = rx.App()
junction.wrap_app(
app,
api_key=os.environ["JUNCTION_API_KEY"],
environment="sandbox", # or "production"
register_user_state=True,
)
3. Use Junction state in your pages
def health_dashboard() -> rx.Component:
return rx.container(
rx.heading("Health Dashboard"),
rx.text(f"Connected: {junction.JunctionState.has_connections}"),
# Sleep scores chart
rx.recharts.line_chart(
rx.recharts.line(data_key="score"),
rx.recharts.x_axis(data_key="date"),
data=junction.JunctionUser.chart_sleep_scores,
),
# Heart rate timeseries
rx.recharts.line_chart(
rx.recharts.line(data_key="bpm", stroke="#ef4444"),
rx.recharts.x_axis(data_key="timestamp"),
data=junction.JunctionUser.chart_heartrate,
),
)
4. Add the Link widget
from reflex_junction import junction_link_button
def connect_page() -> rx.Component:
return rx.container(
junction_link_button(
"Connect a Provider",
link_token=junction.JunctionState.link_token,
env="sandbox",
on_success=junction.JunctionState.get_connected_providers,
),
)
Data Types
Health Summaries (Phase 1)
| Model | Description | Key Fields |
|---|---|---|
SleepSummary |
Sleep sessions | score, duration, stages, HR, HRV |
ActivitySummary |
Daily activity | steps, calories, distance, intensity |
WorkoutSummary |
Workout sessions | sport, duration, calories, HR |
BodyMeasurement |
Body composition | weight, BMI, fat%, muscle% |
ProfileData |
User profile | height, birth_date, gender |
MealSummary |
Nutrition entries | calories, protein, carbs, fat |
Vitals Timeseries (Phase 2)
| Method | Data Key | Unit |
|---|---|---|
fetch_heartrate() |
bpm | bpm |
fetch_hrv() |
hrv | ms |
fetch_blood_oxygen() |
SpO2 | % |
fetch_glucose() |
glucose | mg/dL |
fetch_blood_pressure() |
systolic/diastolic | mmHg |
fetch_steps_timeseries() |
steps | steps |
fetch_calories_timeseries() |
calories | kcal |
fetch_respiratory_rate() |
rate | breaths/min |
fetch_vital(metric, ...) |
Generic escape hatch for 50+ metrics |
Lab Testing (Phase 5)
| Model | Description |
|---|---|
LabTest |
Test panel with markers |
LabOrder |
Placed order with status |
BiomarkerResult |
Result with range indicators |
Webhook Events (Phase 4)
| Model | Prefix | Example |
|---|---|---|
ConnectionEvent |
connection.* |
Provider connected/disconnected |
DataEvent |
historical.*, daily.* |
New health data available |
WebhookEvent |
Base class | Any event type |
Webhook Support
junction.wrap_app(
app,
api_key=os.environ["JUNCTION_API_KEY"],
register_webhooks=True,
webhook_secret=os.environ["JUNCTION_WEBHOOK_SECRET"],
webhook_prefix="/junction", # POST /junction/webhooks
)
Webhooks use Svix signature verification. Invalid signatures are rejected with 401.
Running the Demo
The repo includes a 9-page demo app in junction_demo/.
uv sync --dev
cd junction_demo
export JUNCTION_API_KEY=sk_us_...
uv run reflex init
uv run reflex run
Pages: Dashboard, Sleep, Activity, Workouts, Body, Vitals, Labs, Providers, Settings.
Environment Options
| Environment | Description |
|---|---|
sandbox |
US sandbox (default) |
production |
US production |
sandbox_eu |
EU sandbox |
production_eu |
EU production |
API Reference
State Classes
| Class | Description |
|---|---|
JunctionState |
Core state — user creation, provider management, Link tokens |
JunctionUser |
Extended state — health data, vitals, labs, introspection |
Components
| Component | Description |
|---|---|
JunctionLink / junction_link |
Declarative VitalLink button (requires public key) |
JunctionLinkButton / junction_link_button |
Token-based Link widget (uses useVitalLink hook) |
Functions
| Function | Description |
|---|---|
wrap_app(app, api_key, ...) |
One-line app integration with optional webhooks |
junction_provider(*children, api_key, ...) |
Component wrapper for page-level integration |
on_load(handlers) |
Wrap page on_load handlers to wait for Junction init |
register_on_auth_change_handler(handler) |
Register handler to fire after Junction initializes |
create_webhook_router(prefix, secret) |
Create a standalone FastAPI webhook router |
register_webhook_api(app, secret, prefix) |
Register webhook endpoint on a Reflex app |
See the full documentation for detailed guides.
Contributing
task install # Install dev dependencies + pre-commit
task test # Run lint + typecheck + pytest
task run # Run the demo app
task run-docs # Serve docs locally at localhost:9000
License
MIT — Copyright (c) 2025 Syntropy Health
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file reflex_junction-0.2.0.tar.gz.
File metadata
- Download URL: reflex_junction-0.2.0.tar.gz
- Upload date:
- Size: 181.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.14 {"installer":{"name":"uv","version":"0.9.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
210dc312ce48dfe3cb5d869dd6af4efa94c0387da598e77a1c1da633d67f91d0
|
|
| MD5 |
4482f0252fe55d5b8be50da664f04a29
|
|
| BLAKE2b-256 |
84c1a117c1487e364de242d495f05015e22a63ecbf6c765f19891d20a80423f2
|
File details
Details for the file reflex_junction-0.2.0-py3-none-any.whl.
File metadata
- Download URL: reflex_junction-0.2.0-py3-none-any.whl
- Upload date:
- Size: 20.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.14 {"installer":{"name":"uv","version":"0.9.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9edd632c9b6824fd5609f2ecf597e8bee40f905bcd01b570d9fb609b8ca02cbf
|
|
| MD5 |
872563c2e61b9b4b9ddd8879f9d0178a
|
|
| BLAKE2b-256 |
f7271846fa4e437bd577d642519e18b92dc30b94095a98e9c55d4272c752dc40
|