--- title: "Getting started with rCoros" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with rCoros} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE # all chunks require live credentials; run interactively ) ``` rCoros gives you tidy access to your [COROS Training Hub](https://coros.com/traininghub) data from R. Every function returns a tibble, so you can pipe results straight into dplyr and ggplot2. ## Setup Store your credentials in `~/.Renviron` so they are never hard-coded in a script: ``` COROS_EMAIL=you@example.com COROS_PASSWORD=secret ``` Then restart R and authenticate: ```{r auth} library(rCoros) auth <- coros_login() auth #> #> region: us #> user_id: 123456789 #> logged in: 2026-06-07 08:00:00 ``` Pass `region = "eu"` if your account was created in Europe. The `auth` object is just a lightweight list — create it once per session and pass it to every subsequent call. ## Activities `coros_activities()` returns one row per activity. By default it fetches the last 30 days and auto-paginates until all matching activities are returned: ```{r activities} library(dplyr) acts <- coros_activities(auth) acts #> # A tibble: 47 × 16 #> activity_id name sport_type sport_name date start_time #> #> 1 4780… Morning Trail R… 102 Trail Run… 2026-06-06 2026-06-06 06:12:00 #> 2 4779… Easy Run 100 Running 2026-06-04 2026-06-04 07:00:00 #> … ``` Filter to runs only, then look at distance and training load over time: ```{r runs} runs <- acts |> filter(sport_type %in% c(100L, 102L)) |> arrange(date) library(ggplot2) ggplot(runs, aes(date, distance_km)) + geom_col(fill = "#3A7BD5") + labs(title = "Weekly volume", x = NULL, y = "Distance (km)") ``` ### Activity detail Drill into a single activity to get lap splits and heart-rate zones: ```{r detail} detail <- coros_activity_detail( auth, activity_id = acts$activity_id[[1]], sport_type = acts$sport_type[[1]] ) # One-row summary detail$summary |> glimpse() # Lap splits detail$laps # Time in HR zones ggplot(detail$hr_zones, aes(factor(zone), minutes, fill = factor(zone))) + geom_col(show.legend = FALSE) + scale_fill_brewer(palette = "RdYlGn", direction = -1) + labs(title = "Time in HR zones", x = "Zone", y = "Minutes") ``` ## Daily wellness metrics `coros_daily_metrics()` pulls per-day HRV, resting heart rate, VO2max, training load, and more for up to 90 days at a time: ```{r metrics} metrics <- coros_daily_metrics(auth, start_day = "20260101", end_day = "20260607") # HRV trend with baseline ggplot(metrics, aes(date)) + geom_ribbon(aes(ymin = hrv_baseline - 5, ymax = hrv_baseline + 5), fill = "steelblue", alpha = 0.2) + geom_line(aes(y = hrv_baseline), colour = "steelblue", linewidth = 0.8) + geom_point(aes(y = hrv), size = 1.5) + labs(title = "Overnight HRV vs. baseline", x = NULL, y = "HRV (ms)") ``` For a quick view of just the last 7 days, `coros_hrv()` hits a lighter dashboard endpoint: ```{r hrv} coros_hrv(auth) #> # A tibble: 7 × 4 #> date hrv baseline hrv_sd #> #> 1 2026-06-01 61.2 58.4 4.1 #> 2 2026-06-02 64.8 58.8 3.9 #> … ``` ## Training load Training load and its acute:chronic ratio are in `coros_daily_metrics()`. A ratio above ~1.5 is a useful proxy for injury risk: ```{r load} metrics |> filter(!is.na(load_ratio)) |> ggplot(aes(date, load_ratio)) + geom_hline(yintercept = c(0.8, 1.3), linetype = "dashed", colour = "grey60") + geom_line(colour = "#E06C2C", linewidth = 1) + annotate("text", x = min(metrics$date), y = 1.35, label = "Caution zone", hjust = 0, size = 3, colour = "grey40") + labs(title = "Acute:chronic training load ratio", x = NULL, y = "Load ratio") ``` ## Workout programmes `coros_workouts()` returns your saved workout library as two linked tibbles — the workout header and its individual steps: ```{r workouts} w <- coros_workouts(auth) # All workouts w$workouts # Steps for a specific workout w$steps |> filter(workout_id == w$workouts$id[[1]]) ``` ## Training calendar `coros_schedule()` shows what's planned for the next two weeks (or any window you specify): ```{r schedule} sched <- coros_schedule(auth) sched #> # A tibble: 9 × 5 #> happen_day name sport_name estimated_min completed #> #> 1 2026-06-07 Long Run Running 90 FALSE #> 2 2026-06-09 Recovery Run Running 40 FALSE #> … ``` ## Putting it together A common pattern is to join activities back to daily metrics to explore how recovery scores relate to performance: ```{r join} combined <- runs |> left_join( metrics |> select(date, hrv, hrv_baseline, rhr, load_ratio), by = "date" ) ggplot(combined, aes(hrv, avg_hr, colour = load_ratio)) + geom_point(size = 2.5) + geom_smooth(method = "lm", se = FALSE, colour = "grey40") + scale_colour_viridis_c(name = "Load ratio") + labs( title = "HRV vs. average run HR", x = "Overnight HRV (ms)", y = "Average HR (bpm)" ) ```