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:
StreamlitAuth
handles 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