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
8 Likes

Hi @Nathan_Chen,

Thanks for sharing!

2 Likes

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.')
4 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

Amazing work, thank you!

Is there any way to use Streamlit-Cookies-Controller with st-paywall to keep the user logged in after the page is refreshed? Would be nice if anyone can help with that! Thank you in advance :heart:

I would like to ask a question about how to configure a ‘cookie path’. I tried to add a multi page path, but it didn’t work. Perhaps I misunderstood. Can you give me an example? Thank you very much!

I’m seeing a very weird issue - perhaps a delay of 10s of seconds setting the cookie or cookie is not set ( I have to login again multiple times). I’m storing the login email as the cookie [ controller.set('c_user', email, max_age=24*60*60) ]
However, this doesn’t seem to be working all the time. Perhaps, not sure if I’m missing any other setting - will raise a query/request on the controller github page.

No effect not understood

import streamlit as st
from streamlit_cookies_controller import CookieController

# 设置页面配置
st.set_page_config('Cookie QuickStart', '🍪', layout='wide')

# 初始化 Cookie 控制器
controller = CookieController()

# 检查是否已登录
def check_login():
    cookies = controller.getAll()
    return 'username' in cookies

# 显示欢迎信息
def welcome_user():
    cookies = controller.getAll()
    username = cookies.get('username', 'Guest')
    st.write(f"Welcome to Streamlit Cookie Controller :cookie: {username}")

# 登录表单
def login_form():
    st.title("欢迎访问 Streamlit Cookie Controller :cookie:")
    username = st.text_input("用户名")
    password = st.text_input("密码", type="password")
    if st.button("登录"):
        if username and password:
            # 简单验证(例如,用户名和密码是否都不为空)
            controller.set('username', username)
            st.experimental_rerun()

# 主逻辑
if check_login():
    welcome_user()
    if st.button("注销"):
        controller.remove('username')
        st.experimental_rerun()
else:
    login_form()