Build A Streamlit App in Minutes¶
What You'll Build¶
A Streamlit app that:
- Authenticates with SweatStack
- Fetches your activity data
- Displays an heart rate chart
- Allows switching between users
In a hurry?
uv init
uv add "sweatstack[streamlit]" matplotlib
Create a new app this link and put the credentials in a .env file:
SWEATSTACK_CLIENT_ID=your_client_id_here
SWEATSTACK_CLIENT_SECRET=your_client_secret_here
Copy and paste the following code into a app.py file:
import os
import matplotlib.pyplot as plt
import streamlit as st
from sweatstack.streamlit import StreamlitAuth
# Initialize authentication
auth = StreamlitAuth(
client_id=os.getenv("SWEATSTACK_CLIENT_ID"),
client_secret=os.getenv("SWEATSTACK_CLIENT_SECRET"),
redirect_uri="http://localhost:8501",
)
# Sidebar for auth and user selection
with st.sidebar:
auth.authenticate()
if auth.is_authenticated():
auth.select_user()
# Check if authenticated
if not auth.is_authenticated():
st.write("# 💓 Heart Rate Dashboard")
st.write("Please log in to view your activity data.")
st.stop()
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
selected_user = auth.select_user() # Dropdown to switch user
auth.client.switch_user(selected_user)
# Activity selection
activity = auth.client.select_activity()
if not activity:
st.warning("No activities found. Make sure you have activities in SweatStack.")
st.stop()
st.write(f"### {activity.name or 'Latest Activity'}")
st.write(f"**Sport:** {activity.sport}")
st.write(f"**Date:** {activity.start.date()}")
# Fetch activity data (time series)
with st.spinner("Loading heart rate data..."):
data = auth.client.get_activity_data(activity.id)
# Check if heart rate data exists
if data is None or data.empty or "heart_rate" not in data.columns:
st.info("No heart rate data available.")
st.stop()
plt.plot(
data.index,
data["heart_rate"],
)
st.pyplot(plt.gcf())
Run the app:
uv run --env-file .env streamlit run --server.runOnSave true app.py
We'll start simple and add features step by step.
Prerequisites and setup¶
- A SweatStack account (app.sweatstack.no)
- uv installed
Start by creating a new project folder, open a terminal and attach into the folder. Install the required packages:
uv init
uv add "sweatstack[streamlit]" matplotlib
Creating a new SweatStack API application¶
First, we need to register your app with SweatStack to get API credentials.
To get started, create a new SweatStack API application by visiting this link.
You can use placeholder values for the url, image url, and privacy statement fields for now, but set the redirect URI to http://localhost:8501. Save your application.
Click "Create Secret", give it a name, and make sure to copy the secret immediately, as it will only be shown once.
Create a .env file in your project folder:
SWEATSTACK_CLIENT_ID=your_client_id_here
SWEATSTACK_CLIENT_SECRET=your_client_secret_here
Security
Treat your app's client secret like a password. When you're using git, add .env to .gitignore to keep it safe!
Creating the Streamlit app¶
Let's start with a simple app that authenticates with SweatStack.
Create app.py:
import os
import streamlit as st
from sweatstack.streamlit import StreamlitAuth
# Initialize authentication
auth = StreamlitAuth(
client_id=os.getenv("SWEATSTACK_CLIENT_ID"),
client_secret=os.getenv("SWEATSTACK_CLIENT_SECRET"),
redirect_uri="http://localhost:8501",
)
# Add login button
auth.authenticate()
# Check if authenticated
if not auth.is_authenticated():
st.write("# 💓 Heart Rate Dashboard")
st.write("Please log in to view your activity data.")
st.stop()
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
st.success("Connected to SweatStack!")
st.balloons()
Client Instance
Always use auth.client for API calls in Streamlit:
# ✅ Correct
activities = auth.client.get_activities()
# ❌ Wrong - won't work with Streamlit and might expose your data to other users of the same Streamlit app
import sweatstack as ss
activities = ss.get_activities()
Run Your App¶
uv run --env-file .env streamlit run --server.runOnSave true app.py
Your app should automatically open in your default browser. If it doesn't, open http://localhost:8501
Click the login button to start the authentication process. You'll be redirected to SweatStack to authorize, then back to your app.
What this does:
StreamlitAuthhandles the OAuth2 flowauth.authenticate()shows a login/logout buttonauth.is_authenticated()checks if user is logged inst.stop()prevents the rest of the code from running if not authenticated
Activity selection¶
Now let's add activity selection.
Update your app.py - replace the success message with this code:
# ... previous code omitted ...
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
# Activity selection
activity = auth.select_activity()
if not activity:
st.warning("No activities found. Make sure you have activities in SweatStack.")
st.stop()
st.markdown(f"Selected Activity: {activity.sport.display_name()} on {activity.start.date()}")
View complete code
import os
import streamlit as st
from sweatstack.streamlit import StreamlitAuth
# Initialize authentication
auth = StreamlitAuth(
client_id=os.getenv("SWEATSTACK_CLIENT_ID"),
client_secret=os.getenv("SWEATSTACK_CLIENT_SECRET"),
redirect_uri="http://localhost:8501",
)
# Add login button
auth.authenticate()
# Check if authenticated
if not auth.is_authenticated():
st.write("# 💓 Heart Rate Dashboard")
st.write("Please log in to view your activity data.")
st.stop()
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
# Activity selection
activity = auth.select_activity()
if not activity:
st.warning("No activities found. Make sure you have activities in SweatStack.")
st.stop()
st.markdown(f"Selected Activity: {activity.sport.display_name()} on {activity.start.date()}")
Add Heart Rate Chart¶
Now let's add the heart rate visualization for the selected activity. Add these import at the top of the file:
import matplotlib.pyplot as plt
Then add this code after displaying the activity info:
# ... omitted code ...
# Fetch activity data (time series)
with st.spinner("Loading heart rate data..."):
data = auth.client.get_activity_data(activity.id)
# Check if heart rate data exists
if data is None or data.empty or "heart_rate" not in data.columns:
st.info("No heart rate data available.")
st.stop()
plt.plot(
data.index,
data["heart_rate"],
)
st.pyplot(plt.gcf())
View complete code
import os
import matplotlib.pyplot as plt
import streamlit as st
from sweatstack.streamlit import StreamlitAuth
# Initialize authentication
auth = StreamlitAuth(
client_id=os.getenv("SWEATSTACK_CLIENT_ID"),
client_secret=os.getenv("SWEATSTACK_CLIENT_SECRET"),
redirect_uri="http://localhost:8501",
)
# Add login button
auth.authenticate()
# Check if authenticated
if not auth.is_authenticated():
st.write("# 💓 Heart Rate Dashboard")
st.write("Please log in to view your activity data.")
st.stop()
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
# Activity selection
activity = auth.select_activity()
if not activity:
st.warning("No activities found. Make sure you have activities in SweatStack.")
st.stop()
st.markdown(f"Selected Activity: {activity.sport.display_name()} on {activity.start.date()}")
# Fetch activity data (time series)
with st.spinner("Loading heart rate data..."):
data = auth.client.get_activity_data(activity.id)
# Check if heart rate data exists
if data is None or data.empty or "heart_rate" not in data.columns:
st.info("No heart rate data available. Try an activity recorded with a heart rate monitor.")
st.stop()
plt.plot(
data.index,
data["heart_rate"],
)
st.pyplot(plt.gcf())
What this does:
get_activity_data(id)returns a pandas DataFrame with time-series data for the selected activity- The DataFrame includes columns like
heart_rate,elapsed_time,distance, etc. - Not all activities have heart rate data (depends on sensors used)
Adding User Selection¶
If you have access to multiple users, you can add a dropdown to select the user.
Add user selection:
# ... code omitted ...
# Check if authenticated
if not auth.is_authenticated():
st.write("# 💓 Heart Rate Dashboard")
st.write("Please log in to view your activity data.")
st.stop()
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
selected_user = auth.select_user() # Dropdown to switch user
auth.client.switch_user(selected_user)
# ... rest of the app can stay untouched ...
View complete code
import os
import matplotlib.pyplot as plt
import streamlit as st
from sweatstack.streamlit import StreamlitAuth
# Initialize authentication
auth = StreamlitAuth(
client_id=os.getenv("SWEATSTACK_CLIENT_ID"),
client_secret=os.getenv("SWEATSTACK_CLIENT_SECRET"),
redirect_uri="http://localhost:8501",
)
# Sidebar for auth and user selection
with st.sidebar:
auth.authenticate()
if auth.is_authenticated():
auth.select_user()
# Check if authenticated
if not auth.is_authenticated():
st.write("# 💓 Heart Rate Dashboard")
st.write("Please log in to view your activity data.")
st.stop()
# User is logged in!
st.write("# 💓 Heart Rate Dashboard")
selected_user = auth.select_user() # Dropdown to switch user
auth.client.switch_user(selected_user)
# Activity selection
activity = auth.client.select_activity()
if not activity:
st.warning("No activities found. Make sure you have activities in SweatStack.")
st.stop()
st.write(f"### {activity.name or 'Latest Activity'}")
st.write(f"**Sport:** {activity.sport}")
st.write(f"**Date:** {activity.start.date()}")
# Fetch activity data (time series)
with st.spinner("Loading heart rate data..."):
data = auth.client.get_activity_data(activity.id)
# Check if heart rate data exists
if data is None or data.empty or "heart_rate" not in data.columns:
st.info("No heart rate data available.")
st.stop()
plt.plot(
data.index,
data["heart_rate"],
)
st.pyplot(plt.gcf())
What this does:
auth.select_user()shows a dropdown with all your connected accountsauth.client.switch_user(selected_user)switches to the selected user
That's it!¶
Your app now:
- ✅ Authenticates with SweatStack
- ✅ Fetches your latest activity
- ✅ Displays an interactive heart rate chart
- ✅ Allows switching between accounts