Building a Sleep and Readiness Dashboard with the Oura API
by Pinta
4 min read
In today's fast-paced world, keeping an eye on our sleep and readiness scores can greatly impact our overall well-being. The Oura Ring provides valuable data on sleep quality, readiness, and more. In this guide, we'll explore how to build a Sleep and Readiness Dashboard using the Oura API, a library written primary for Deno, a next-generation JavaScript Runtime. We'll create a project that fetches Oura data and with Deno Fresh visualizes your sleep and readiness scores over the past 30 days.
Prerequisites
Before we get started, this is not supposed to be a finished product, there are plenty of articles out there covering the content of creating beautiful and intuitive dashboards. This is an article about getting started with fetching and using Oura data with the Oura API.
Make sure you have the following set up:
- The Deno runtime. This getting started guide should have you covered.
- An Oura API token. You can obtain one at Oura's developer portal.
Setting Up the Project
To keep this article short I have scaffold a Deno Fresh project, removed unwanted files and added a couple of small things to make the article easier to follow along. I have then uploaded that project to a public repository that you can easily use as a base. We want to quickly get you a working prototype that you can experiment further with. If you need further help or other questions you can find me on my Discord server.
-
Clone the project repository:
git clone https://github.com/Pinta365/oura_fresh.git
Open the folder with your favorite editor, I use Visual Studio Code.
-
Create the following empty files:
/islands/chart.tsx
/lib/oura.ts
.env
Lets update some files
/deno.json
Add the following dependencies to the imports section of your deno.json
file:
"oura": "https://deno.land/x/oura_api@0.7.0/mod.ts",
"$fresh_charts/": "https://deno.land/x/fresh_charts@0.3.1/"
.env
Replace your_token
with your Oura API token:
TOKEN=<your_token>
/islands/chart.tsx
Replace the content of this file with:
export { Chart as default } from "$fresh_charts/island.tsx";
/lib/oura.ts
Replace the content of this file with:
import { Oura } from "oura";
const accessToken = Deno.env.get("TOKEN") || "";
interface OuraData {
sleepData: {
days: string[];
scores: number[];
};
readinessData: {
days: string[];
scores: number[];
};
}
/**
* Fetch sleep and readiness data from the Oura API.
* @param daysToGet Number of days to fetch data for.
* @returns Promise containing OuraData.
*/
export async function getOuraData(daysToGet: number): Promise<OuraData> {
const ouraClient = new Oura(accessToken);
const end = new Date();
const start = new Date();
start.setDate(new Date().getDate() - daysToGet);
try {
const returnDocument: OuraData = {
sleepData: {
days: [],
scores: [],
},
readinessData: {
days: [],
scores: [],
},
};
//Get Sleep documents.
const dailySleeps = await ouraClient.getDailySleepDocuments(
start.toLocaleDateString(),
end.toLocaleDateString(),
);
for (const item of dailySleeps) {
const { score, day } = item;
returnDocument.sleepData.days.push(day);
returnDocument.sleepData.scores.push(score);
}
//Get readiness documents.
const dailyReadiness = await ouraClient.getDailyReadinessDocuments(
start.toLocaleDateString(),
end.toLocaleDateString(),
);
for (const item of dailyReadiness) {
const { score, day } = item;
returnDocument.readinessData.days.push(day);
returnDocument.readinessData.scores.push(score);
}
return returnDocument
} catch (error) {
// Just log the error in the console while developing.
console.error(`Error fetching data: ${error}`);
return <OuraData> {};
}
}
/routes/index.tsx
Replace the content of this file with:
import { getOuraData } from "../lib/oura.ts";
import Chart from "../islands/chart.tsx";
import { ChartColors } from "$fresh_charts/utils.ts";
export default async function Page() {
if (!Deno.env.get("TOKEN")) {
return <h1>Can't find environment variable with Oura token.</h1>;
}
// Fetch 30 days of data.
const daysToFetch = 30;
const ouraData = await getOuraData(daysToFetch);
// Check if we got data points, should probably implement better checks.
if (ouraData.sleepData.scores.length <= 0) {
return <h1>No sleep data.</h1>;
}
if (ouraData.readinessData.scores.length <= 0) {
return <h1>No readiness data.</h1>;
}
return (
<div class="container">
<header>
<h1>Oura Sleep and Readiness Score 🛌🏽</h1>
</header>
<main>
<p>
This interacts with the Oura API and fetches your last
{daysToFetch} days of Sleep and Readiness Score.
</p>
<div class="grid">
<div>
<Chart
type="line"
options={{
interaction: {
mode: "index",
intersect: false,
},
}}
data={{
labels: ouraData.sleepData.days,
datasets: [
{
label: "Sleep score",
data: ouraData.sleepData.scores,
borderColor: ChartColors.Red,
tension: 0.3,
},
],
}}
/>
</div>
<div>
<Chart
type="line"
options={{
interaction: {
mode: "index",
intersect: false,
},
}}
data={{
labels: ouraData.readinessData.days,
datasets: [
{
label: "Readiness score",
data: ouraData.readinessData.scores,
borderColor: ChartColors.Blue,
tension: 0.3,
},
],
}}
/>
</div>
</div>
</main>
<footer class="py-8">
<small>
<p>
Connect with me on{" "}
<a href="https://discord.gg/J7QtVxAt6F">
this discord
</a>{" "}
for questions and discussions.
</p>
</small>
</footer>
</div>
);
}
Fetching and Visualizing Data
Now that our project is set up, let's fetch and visualize the data.
In the ./routes/index.tsx
file, we're using the getOuraData
function to fetch your sleep and readiness data for the
last 30 days. This is where all the interaction with the Oura endpoints are happening. Check out
the Docs for more information concerning fetching various types of Oura data. We then
display this data using Deno Fresh's chart components.
Running the Project
To run the project, use the following command:
deno task start
This command
will start the Deno Fresh development server, and show you the address where you can connect to the site, default is
http://localhost:8000
. The fresh server will reload automatically when it detects changes to the source files.
Conclusion
Congratulations! You've created a Sleep and Readiness Dashboard using the Oura API and Deno Fresh. This project allows you to monitor your sleep and readiness scores, helping you make informed decisions to improve your well-being.
Feel free to customize and expand upon this project to suit your needs. Connect with us on Discord if you have any questions or want to discuss further improvements.
Happy tracking, and sweet dreams! 🌙😴