When building Gradio applications, you often need to persist data between interactions. This is called state management. Gradio provides three ways to manage state:
- Global state: Shared among all users, persists while the app is running
- Session state: Unique to each user, persists during their session
- Browser state: Stored in the browser’s localStorage, persists even after page refresh
Global state
Global state is straightforward: any variable created outside a function is shared between all users.
import gradio as gr
# This variable is shared between all users
visitor_count = 0
def increment_counter():
global visitor_count
visitor_count += 1
return visitor_count
with gr.Blocks() as demo:
number = gr.Textbox(label="Total Visitors", value="Counting...")
demo.load(increment_counter, inputs=None, outputs=number)
demo.launch()
Every user who opens the app increases the visitor count. The value is shared globally across all sessions.
When not to use global state: If you need values that are unique to each user (like chat history, user preferences, or individual progress), use session state or browser state instead.
Session state
Session state allows you to persist data for each user individually. Data is maintained across multiple interactions but does not transfer between users. If a user refreshes the page, their session state is reset.
To use session state, follow these steps:
Create a gr.State object
Initialize it with a default value if needed. The value must be deepcopy-able. Add State as input/output
Include the State object in your event listener’s inputs and outputs as needed.button.click(fn=add_items, inputs=[items, cart], outputs=cart)
Use State in your function
Add the state variable to your function’s parameters and return value.def add_items(new_items, previous_cart):
cart = previous_cart + new_items
return cart
Here’s a complete example of a simple shopping cart:
import gradio as gr
with gr.Blocks() as demo:
cart = gr.State([]) # Initialize empty cart
items_to_add = gr.CheckboxGroup(
["Cereal", "Milk", "Orange Juice", "Water"]
)
def add_items(new_items, previous_cart):
cart = previous_cart + new_items
return cart
gr.Button("Add Items").click(
add_items,
[items_to_add, cart],
cart
)
cart_size = gr.Number(label="Cart Size")
cart.change(lambda cart: len(cart), cart, cart_size)
demo.launch()
Think of gr.State as an invisible Gradio component that can store any value. In this example, cart is not visible in the UI but is used for calculations.
Understanding State changes
The .change() listener for a State variable triggers after any event listener modifies the state:
- For sequences (
list, set, dict): Triggers if any elements change
- For objects or primitives: Triggers if the hash of the value changes
If you create a custom class and use it with gr.State, make sure the class includes a sensible __hash__ implementation.
State persistence
Session state values:
- Are cleared when the user refreshes the page
- Are stored in the app backend for 60 minutes after the user closes the tab
- Can have custom retention with the
delete_cache parameter in gr.Blocks
with gr.Blocks(delete_cache=(3600, 3600)) as demo:
# Delete cached state every hour (3600 seconds)
pass
Working with non-deepcopyable objects
Some objects cannot be deepcopied (like threading locks or database connections). For these, use a global dictionary keyed by session hash:
import gradio as gr
class NonDeepCopyable:
def __init__(self):
from threading import Lock
self.counter = 0
self.lock = Lock() # Lock objects cannot be deepcopied
def increment(self):
with self.lock:
self.counter += 1
return self.counter
# Global dictionary to store user-specific instances
instances = {}
def initialize_instance(request: gr.Request):
instances[request.session_hash] = NonDeepCopyable()
return "Session initialized!"
def cleanup_instance(request: gr.Request):
if request.session_hash in instances:
del instances[request.session_hash]
def increment_counter(request: gr.Request):
if request.session_hash in instances:
instance = instances[request.session_hash]
return instance.increment()
return "Error: Session not initialized"
with gr.Blocks() as demo:
output = gr.Textbox(label="Status")
counter = gr.Number(label="Counter Value")
increment_btn = gr.Button("Increment Counter")
increment_btn.click(increment_counter, inputs=None, outputs=counter)
# Initialize instance when page loads
demo.load(initialize_instance, inputs=None, outputs=output)
# Clean up instance when page is closed/refreshed
demo.unload(cleanup_instance)
demo.launch()
Create a global dictionary
Store one instance per user, keyed by their session_hash.
Initialize on load
Use demo.load() to create an instance when the user first visits.
Clean up on unload
Use demo.unload() to delete the instance when the user leaves.
Access via session_hash
Use gr.Request to get the user’s session_hash in your functions.
Browser state
Browser state persists data in the browser’s localStorage, allowing it to survive page refreshes and even browser restarts. This is useful for storing user preferences, API keys, or settings.
Create a gr.BrowserState object
Optionally provide a default value and a storage key.username = gr.BrowserState("")
Use like gr.State
Add it to event listeners as inputs and outputs.button.click(save_username, inputs=username, outputs=status)
Example: Persisting login credentials
import gradio as gr
def save_credentials(username, password):
# In a real app, you would validate and hash the password
return username, password, "Credentials saved!"
def load_status(username):
if username:
return f"Welcome back, {username}!"
return "No saved credentials found."
with gr.Blocks() as demo:
gr.Markdown("# Login Demo")
# Store credentials in browser localStorage
stored_username = gr.BrowserState("")
stored_password = gr.BrowserState("")
status = gr.Textbox(label="Status", interactive=False)
with gr.Row():
username_input = gr.Textbox(label="Username")
password_input = gr.Textbox(label="Password", type="password")
save_btn = gr.Button("Save Credentials")
save_btn.click(
save_credentials,
inputs=[username_input, password_input],
outputs=[stored_username, stored_password, status]
)
# Load saved credentials on page load
demo.load(load_status, inputs=stored_username, outputs=status)
demo.launch()
BrowserState persistence
Important: Data stored in gr.BrowserState does not persist if the Gradio app is restarted, unless you:
- Hardcode specific values for
storage_key and secret in gr.BrowserState
- Restart the Gradio app on the same server name and port
Only do this if you’re running trusted Gradio apps, as different apps on the same domain could access the same localStorage data.
Choosing the right state type
| State Type | Shared Between Users | Persists on Refresh | Persists After Browser Close | Use Cases |
|---|
| Global State | ✅ Yes | ✅ Yes (until app restarts) | ✅ Yes (until app restarts) | Visitor counters, global settings, shared resources |
| Session State | ❌ No | ❌ No | ❌ No | Chat history, form data, user progress |
| Browser State | ❌ No | ✅ Yes | ✅ Yes | User preferences, API keys, login credentials |
Next steps
Now that you understand state management, you can: