Skip to content

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:

.env
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:

app.py
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

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:

.env
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:

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:

  1. StreamlitAuth handles the OAuth2 flow
  2. auth.authenticate() shows a login/logout button
  3. auth.is_authenticated() checks if user is logged in
  4. st.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:

app.py
# ... 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:

app.py
# ... 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:

app.py
# ... 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:

  1. auth.select_user() shows a dropdown with all your connected accounts
  2. auth.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

Learn More