New Component: Streamlit-Cookies-Controller

Welcome to Streamlit Cookie Controller :cookie:

PyPI GitHub GitHub license GitHub issues GitHub pull requests

Control client browser cookie for the site.

What is Streamlit Cookie Controller?

streamlit-cookie-controller let you

  • get cookie(s)
  • set cookie
  • remove cookie

from/to the client browser.
It use universal-cookie package to access the cookies.

Installation

Open a terminal and run:

pip install streamlit-cookies-controller

Quickstart

Create a new file example.py

from streamlit_cookies_controller import CookieController

st.set_page_config('Cookie QuickStart', '🍪', layout='wide')

controller = CookieController()

# Set a cookie
controller.set('cookie_name', 'testing')

# Get all cookies
cookies = controller.getAll()

# Get a cookie
cookie = controller.get('cookie_name')

# Remove a cookie
controller.remove('cookie_name')

Run the streamlit app

streamlit run example.py
3 Likes

Hi @Nathan_Chen,

Thanks for sharing!

1 Like

There is a bug from my tests. It just runs continuously after running a streamlit app.

from streamlit_cookies_controller import CookieController


controller = CookieController()

# Set a cookie
controller.set('cookie_name', 'testing')

My setup

OS: windows 10
streamlit version: 1.32.0
streamlit_cookies_controller version: 0.0.2

1 Like

Thank you, very practical module.
Applying infinite loops seems to be an exception thrown by the ‘controller. set’ method.

1 Like

I have verified and it is not infinite loops.
It is rendering as expected on streamlit v1.31.1 when component height is zero.
Somehow streamlit 1.32.0 seem to flicker ‘Test1’ text when the component height is zero. Thus the illusion of infinite loop.

streamlit-cookies-controller have a helper function to RemoveEmptyElementContainer. That will hide div element when the iframe height is zero.
streamlit-temp-2024-03-09-11-03-64

import streamlit as st
from streamlit_cookies_controller import CookieController, RemoveEmptyElementContainer

st.set_page_config('Cookie QuickStart', '🍪', layout='wide')

controller = CookieController()
RemoveEmptyElementContainer()

# to check how many time 
if 'count' not in st.session_state:
    st.session_state['count'] = 0
st.session_state['count'] += 1
count = st.session_state['count']
st.write(f"Total script run count: {count}")

# Set a cookie
controller.set('cookie_name', 'testing')
st.write(st.session_state)

# Get all cookies
cookies = controller.getAll()
st.write(cookies)

# Get a cookie
cookie = controller.get('cookie_name')

# Remove a cookie
controller.remove('cookie_name')
3 Likes

Is it really necessary? Can you implement to not call it without ui flickering?

Thanks for the feedback. I have updated to v0.0.3 to pypi. Please check it out and let me know if there is still any issue.

1 Like

Works great now.

1 Like

Testing if it can survive page reload. Yes it can. For now I have not done any encryption on this test.

  • Log in with username and password.
  • Save the username and password in cookie.
  • Do not press the logout button, just reload the page.
  • It logged in back the user.

image

Start running the app.

import streamlit as st
from streamlit import session_state as ss
from streamlit_cookies_controller import CookieController
import time


cookie_name = st.secrets['COOKIE_NAME']
controller = CookieController(key='cookies')


# Newly opened app or user reloads the page.
if 'login_ok' not in ss:

    # Check the contents of cookie.
    cookies = controller.getAll()
    time.sleep(1)

    # Get cookie username and password if there is.
    cookie_username = controller.get(f'{cookie_name}_username')
    cookie_password = controller.get(f'{cookie_name}_password')

    if cookie_username and cookie_password:
        ss.login_ok = True
        ss.username = cookie_username
        ss.password = cookie_password
        st.success(f'Welcome back {ss.username}!!')
    else:
        ss.login_ok = False

Saving credentials to cookie after successful log in.

Test users data.

USERS = {
    'john': {'username': 'john', 'password': 'jjj'},
    'peter': {'username': 'peter', 'password': 'ppp'}
}
def authenticate():
    usern = ss.username
    passw = ss.password

    user_info = USERS.get(usern, {})
    
    if len(user_info):
       user_password = USERS.get(usern, {}).get('password', '')

       if user_password == passw:
            
            # Save to cookie.
            controller.set(f'{cookie_name}_username', ss.username, max_age=8*60*60)
            controller.set(f'{cookie_name}_password', ss.password, max_age=8*60*60)
            
            ss.login_ok = True

    if not ss.login_ok:
        st.error('Wrong username/password.')
3 Likes

Hi Betsu, are you still having the problem?

Great component!
But I get an error when I create a cookie (though the cookie is saved correctly):

2024-04-09 09:37:16.295 ComponentRequestHandler: GET C:\DEV_Streamlit\cookies\.venv\Lib\site-packages\streamlit_cookies_controller\frontend\build\bootstrap.min.css.map read error   
Traceback (most recent call last):
  File "C:\DEV_Streamlit\cookies\.venv\Lib\site-packages\streamlit\web\server\component_request_handler.py", line 54, in get
    with open(abspath, "rb") as file:
         ^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\DEV_Streamlit\\cookies\\.venv\\Lib\\site-packages\\streamlit_cookies_controller\\frontend\\build\\bootstrap.min.css.map'

I also get a GUI problem:
before click the button “Set a cookie”
image
After the cookie is created (with the terminal error as response):
image

streamlit==1.33.0
streamlit-cookies-controller==0.0.3

Thanks!

Thanks for informing the errors.
I have fixed the terminal error in ver 0.0.4.
I can’t duplicate the GUI error. Can send me your “Cookie Quickstart” code?

1 Like

GUI error it seems is just the div with component’s iframe child showing itself when the cookie is set. Just add this to you code and it should be fine:

st.html(
"""
<style>
     div[data-testid='element-container']:has(iframe[title='streamlit_cookies_controller.cookie_controller.cookie_controller']){
            display:none;
     }
</style>
"""
)

Or invoke it in a container like so:

with st.container(height=1, border=False):
    st.html("<style>div[height='1']{display:none;}</style>")
    controller.set('cookie_name', 'testing')

... continue code

GUI error shows when:

  1. Setting cookie (set method)
  2. Deleting cookie (remove method)
  3. Refreshing to get all cookies from browser (refresh method)

As these are the only times the component mounts so it shows the div parent iframe child.

1 Like

Thanks for your fast response! Now is ok. GUI error is that identified by Rushmore and his trick resolved the issue.

1 Like

Perfect, thanks!

1 Like