New Component: Streamlit-Cookies-Controller

Hello when reloading a page the cookie resets. I was wondering if there is any way to fix this?

2 Likes

Having the same issue… hoping someone can chime in here.

1 Like

Very useful, thank you!

When streamlit is deployed on a K8 pod (access via route) cookies are shared between sessions…
Does this means the cookies are kept on server side ?

Hi @Nathan_Chen! Nice component :slight_smile:

I was wondering how you actually access the browsers cookies with the component :thinking: I saw that you wrap the CookieController class around st.session_state.

I recently went with a similar approach and overwrote the class’ dunder methods to make state easier to access. I added a typed item getter to ensure fail safety for items that are not available in session_state. Would love to get your feedback on this:

class StateController(object):
    """Usage: 
    Instantiate controller: 
        state = StateController()
    Set a value: 
        state['str_user_guid'] = '00000000-0000-0000-0000-000000000000'
        state['bool_user_logged_in'] = True
        state['dict_user_details'] = {"name": "John"}
        data = st.file_uploader('Upload Excel File', type='xlsx')
        if data:
            state['df_excel_upload'] = pd.read_excel(data)
    Get a value: 
        user_guid = state.str_user_guid
        state.bool_user_logged_in:
            st.write(f'Welcome {state.dict_user_details.get("name")}!')
        if not state.df_excel_upload.empty:
            df = (
                state.df_excel_upload
                .pipe(transform)
                )
    Delete a value: 
        if st.button('Logout'): 
            state.pop('str_user_guid')
            state.pop('bool_user_logged_in')
            state.pop('dict_user_details')
    """

    def __getattr__(self, item: str):
        return self.typed_getter(item)

    def __setattr__(self, item: str, value: Any):
        st.session_state[item] = value

    def __setitem__(self, item: str, value: Any):
        st.session_state[item] = value

    def __getitem__(self, item: str):
        return self.typed_getter(item)

    def to_dict(self):
        return st.session_state

    def pop(self, item: str):
        """only use for deletion"""
        return st.session_state.pop(item, None)
        
    def typed_getter(self, item: str):
        """Itemgetter from session_state with simple protocol for default values.
        First part of key string (item) indicates the datatype of item. 
        Defaults to a falsey value when not present in session_state.

        Args:
            item (str): key of the item to fetch from session_state

        Returns:
            Any: The value of the requested item in session_state, defaulted according to its datatype.
        """
        dtype, _ = item.split('_', maxsplit=1)
        if dtype == 'series':
            return st.session_state.get(item, pd.Series())
        if dtype == 'df':
            return st.session_state.get(item, pd.DataFrame())
        if dtype == 'bool':
            return st.session_state.get(item, False)
        if dtype == 'int':
            return st.session_state.get(item, 0)
        if dtype == 'float':
            return st.session_state.get(item, 0.0)
        if dtype == 'str':
            return st.session_state.get(item, None)
        if dtype == 'dict':
            return st.session_state.get(item, dict())
        else:
            return st.session_state.get(item, None)

Cheers
Mo

1 Like

I cannot remove the cookie.
I set user after login success in login page.

controller = CookieController()
controller.set('user', user['sAMAccountName'])

On mainpage:

if st.sidebar.button("logout"):
            controller.remove('user')
            controller.refresh()

The cookie user is still available even after reloading page.
and it show the error on server :
streamlit.errors.StreamlitAPIException: st.session_state.cookiescannot be modified after the widget with keycookies is instantiated
Can anyone help me for this?

2 Likes

Cookies are sill present and can be seen in the developer tool of the browser.
Any solution to this?

Did you find any solution?

same here!

This is not working - the cookie resets / does not persist in browser
Also this is just a copy of the cookie manager in extra_streamlit_components, isn’t it?

I am trying to use the cookie controller to have a persistent login state but am having issues with the login state being shared between different browsers. Logging in on one machine will result in ‘logged in’ state for anyone else loading the streamlit app.

It appears that the cookie_controller object is common to all sessions, i.e. if I print the cookie contoller object I see the same memory address on two different machines.

How do I ensure a new instance of the cookie controller is re-instantiated for each session? Do I need to store it within the session state?

Update:
Okay simpler than I thought. Re-instantiating the cookie controller and storing it in st.session_state solved my problem and now login status is separated by session.

1 Like

I see the same behavior. Calling remove does not actually clear the cookie in the browser. Is there a fix for this?

Hey! I was experiencing the same issue where remove() wasn’t clearing the cookies properly, and the logout state wasn’t syncing.

This approach worked for me:

if st.button("Logout", use_container_width=True):
    cookie_manager.remove("user")
    cookie_manager.remove("permission")
    cookie_manager.remove("loginTime")
    st.session_state.clear()
    time.sleep(1) 
    st.rerun()

Adding time.sleep(1) before st.rerun() ensures the browser has time to apply the cookie changes before the app reloads. Hope this helps someone else!

1 Like

I have an issue when using this component. I am trying to build a very simple authentication and persist user_id in a cookie so when user login once, he can refresh the page and navigate the website without need to re-login with every page refresh.
what I am getting is my login function get called every time the user refresh the page, even if cookie persist, this cause login page to appear for a second then disappear and home page appears

I have a very sample code of what I am trying to do

import streamlit as st
from streamlit_cookies_controller import CookieController
import time

controller = CookieController()
user_id = controller.get("user_id")
print(user_id) # expect it to be None for the first time only and once user logged in once it should have "SAYED" but this not the case

def login():
    # in my original code, this has login form and check username and password against ones stored in db
    print("logging func")
    st.write("LOGIN")
    if st.button("login"):
        controller.set("user_id", "SAYED")
        time.sleep(1)
        st.rerun()

def home():
    # in my original code, this contains my home page with a lot of components and content
    print("home func")
    st.write("HOME")

if not user_id:
    pg = st.navigation(pages=[st.Page(login)])
else:
    pg = st.navigation(pages=[st.Page(home)])

pg.run()

I expect the code to print in log

None
logging func

then when user log in

SAYED
home func

but what I got in log is

None
logging func
None #not sure why this
logging func # not sure why this

then when user press login button i got

None # why it is not SAYED from cookie ?
logging func # why it goes to loggin function at all 
SAYED # this is expected 
home func # this is expected

Thanks

1 Like

Same issue here. :worried:

(post deleted by author)

Thanks for sharing, this is very helpful. When you store the cookie controller in the session state, do you ensure unique key for the controller in every session or leave it blank/same key for new session states?

[Bug] CookieController prevents video autoplay in Streamlit
I’m encountering an issue when using the streamlit-cookies-controller component in my Streamlit app. Specifically, initializing CookieController() on page load seems to interfere with HTML5 video autoplay behavior.

st.video(“source/hero-video.mp4”, loop=True, autoplay=True, muted=True, width=1024)