Sync WHOOP Data With Notion
Introduction
I have recently started tracking daily metrics in Notion. I am doing this for multiple reasons such as accountability, data collection, and retrospective ability. I got the inspiration to do this from a YouTube series by August Bradley — the source is here. Some metrics that I enter daily are focused on sleep and recovery from my WHOOP strap. This process requires me to manually consolidate data from the WHOOP app and enter it into Notion. While this is not overly time-consuming, I couldn’t help but ask the question:
“How can I make this easier?”
This leads to the mission of automatically syncing my WHOOP data with my daily tracking entries. The data points I want to track are:
- Recovery Percentage
- Sleep Time in Milliseconds
- Sleep Efficiency Percentage
Is This Even Possible
To figure out if this is possible, I need to break the problem down into smaller chunks:
- How do I get the data from WHOOP?
- How do I enter the data into Notion?
- Can this data reading/writing happen automatically?
Luckily enough, they both have public APIs that I can use:
WHOOP Developer Platform
They have a platform that allows developers to create integrations with WHOOP. This looks like a perfect start for gathering data. They provide access to different data metrics, and more importantly, sleep! There is also a webhook mechanism that pushes data to a REST API. Webhooks are perfect for automation as you can create systems that handle events instead of having to set up infrastructure to poll data. Let’s test it out:
- Create an Application in the developer dashboard
- Follow Authenticating with WHOOP to receive an access token. They use OAuth 2.0 for their authentication method.
- Once you have an access token, you can use Postman to call the WHOOP APIs.
- Use something like https://webhook.site/ to verify you can receive webhook events from WHOOP.
Side note: It would be awesome if WHOOP allowed developers to get a longstanding token for access to just their account instead of OAuth 2.0. It would make a project like this much easier!
Notion API
The Notion API is very straightforward. You can create one on the Notion Integrations page. When you create an integration, you get a token that can be used to call any of their APIs. To test it out we should:
- Create an Integration to get a token
- Use Postman to test out calling the APIs
Final Verdict
After testing both the WHOOP and the Notion API, I have been able to derisk the project! There was some complexity with WHOOP around managing OAuth 2.0 access and refresh tokens, but overall seemed possible.
My Solution
The solution consists of a couple of components:
- AWS Lambda with API Gateway to serve as Webhook for WHOOP
- Secret in AWS Secret Manager storing the WHOOP access and refresh token
- AWS Lambda running every 45 minutes to refresh WHOOP tokens
I used Python for all the application code and Terraform for the infrastructure. You can find the source code for the project hosted on GitHub here.
Webhook API
I created a simple flow diagram using Excalidraw:
The First step of the webhook is to collect information. To do this, I can utilize the WHOOP `recovery.updated` event. When I receive this event, here are the steps the code goes through:
- Get the recovery cycle ID in the event payload.
- Call the `getRecoveryForCycle` API to get the Recovery Percentage. To call the API, I need to get a valid access token which I store in AWS Secrets Manager.
- Use the `sleep_id` from the recovery data to call the `getSleepById` API and get the sleep time in milliseconds and the sleep efficiency percentage.
Now that I have all the information needed, I can submit the data to Notion. I do not want to create duplicate Daily Tracking entries in case I need to manually change my sleep or recovery in the WHOOP app, so I need to create the entry if it doesn’t exist or update the existing one. This can be done by:
- Use the `Query a database` API to see if there is already an entry in the database by looking for entries with sleep date
- Update the Notion database with the information
- If there is already an entry, use the `Update page` API to update the current entry
- If we need to create the entry, use the `Create a page` API to create a new entry
Once that is done, we should see an entry in your Notion database with the correct data!
WHOOP Token Rotator
Because WHOOP uses OAuth 2.0, we get an access token that expires after a certain amount of time. We can use the refresh token provided to get new access and refresh tokens. This needs to be done occasionally so we know the webhook will get a valid token. I chose to do this outside of the webhook because I did not want the possibility of 2 invocations of the webhook trying to refresh the tokens. This could create a race condition where the invalid refresh token could be stored.
To solve this, I created a service that will refresh the tokens. then I can use AWS CloudWatch Events to trigger a Lambda to execute every 45 minutes.
Infrastructure as Code
Defining the infrastructure as code was important to me for a couple of reasons:
- It makes the project easier to replicate
- No need to go around in the AWS console messing with settings
I have worked on projects before where everything is set up manually in the AWS console, and it is incredibly difficult for knowledge transfer, maintenance, and migration. For this project, I decided to try out Terraform and see how it works. Overall I enjoyed using it as I can deploy and manage the project from my source code. I did run into a couple of issues during the process, but I am sure there are ways to fix them with a little more time investment:
- I couldn’t get AWS Access Keys to be read correctly from environment variables, so I had to set them as terraform variables.
- I was unable to get the python package bundling working fully contained in Terraform, so I run a bundling script before the deployment.
Final Outcome
This ended up being a fun project! I am now able to wake up every morning and have my Daily Tracking entry automatically created every morning and prefilled with my WHOOP sleep and recovery information. This was overall a fun challenging project, and I hope to be able to do more in the future.
If you are interested in creating a solution like this tailored to your needs, I can help out at gw3tech.com.