# How to implement a user inactivity timeout?

**URL:** <https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613>\
**Category:** Using Streamlit\
**Created:** [November 17, 2023, 1:53am UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613 "2023-11-17T01:53:05Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![IndigoJay](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/indigojay/32/34270_2.png) [@IndigoJay](https://discuss.streamlit.io/u/IndigoJay)\
**Post date:** [November 17, 2023, 1:53am UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/1 "2023-11-17T01:53:05Z")

</div>

1. Developing this app locally
2. NA (not deployed)
3. NA - local
4. NA - no error messages
5. Versions - streamlit 1.14.0, python 3.8.10

I [searched](https://discuss.streamlit.io/t/timeout-a-streamlit-webapp-after-certain-time/52885) the [discussions](https://discuss.streamlit.io/t/session-timeout/40566) and [found](https://discuss.streamlit.io/t/create-a-session-state-time-out-function-for-inactivity/32411) a handful of similar requests.

I have developed an Streamlit app that is nearly ready to go into live internally. However my organization’s security policy requires production applications have a 60 minute user inactivity timeout.

I’ve tried and failed with approaches such as abusing st.cache(), st.experimental\_rerun(), time.sleep() and threading.

Below is a my final not-working attempt before throwing in the towel.

This code is by no means a good way to go or anything I am locked into! Maybe there is a Python or Streamlit way?

```auto
import streamlit as st
import time
import threading

TIMEOUT_MINUTES = 1 # one minute for testing :) 

def check_inactivity(timeout_minutes=TIMEOUT_MINUTES):
    while True:
        last_activity_timestamp = st.session_state.last_activity_timestamp
        st.write(f"Checking inactivity at {last_activity_timestamp}")

        current_time = time.time()
        time_difference = current_time - last_activity_timestamp

        if time_difference > timeout_minutes * 60:
            st.warning("Session timed out due to inactivity.")
            st.stop()
        time.sleep(30)  

def update_last_activity_timestamp():
    st.session_state.last_activity_timestamp = time.time()

def main():
    st.set_page_config(page_title="Test Inactivity Timeout", page_icon=":rocket:")
    if "last_activity_timestamp" not in st.session_state:
        st.session_state.last_activity_timestamp = time.time()

    inactivity_checker = threading.Thread(target=check_inactivity)
    inactivity_checker.daemon = True
    inactivity_checker.start()

    st.header("Test inactivity timeout")
    st.button("test", on_click=update_last_activity_timestamp)

if __name__ == " __main__":
    main()

```

---

<div class="post-metadata">

**Author:** ![dataprofessor](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/dataprofessor/32/44163_2.png) [@dataprofessor](https://discuss.streamlit.io/u/dataprofessor)\
**Post date:** [November 17, 2023, 12:38pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/2 "2023-11-17T12:38:34Z")

</div>

Hi @IndigoJay

There are previous related post as follows tackling the same issue of user inactivity timeout:

> [@Timeout a streamlit webapp after certain time](https://discuss.streamlit.io/t/timeout-a-streamlit-webapp-after-certain-time/52885):
>
> Summary How do I make my streamlit webapp timeout after certain time of inactivity by user on Windows & Unix systems. Expected behavior: User opens the webapp, leaves the tab running with no activity for some time. Streamlit script should close (st.stop() maybe) after a certain amount of time. Debug info Streamlit version: 1.27.0 Python version: 3.7.6 Using Conda? PipEnv? PyEnv? Pex? OS version: Windows 10 Browser version: Chrome 83.0.4103.116 Additional information Since I couldnt find any…

> [@Create a session state time out function for inactivity](https://discuss.streamlit.io/t/create-a-session-state-time-out-function-for-inactivity/32411):
>
> Summary There is not adequate information on the working session state. I want to create a session state time-out function for inactivity. Please share your views on this Steps to reproduce Code snippet: add code here If applicable, please provide the steps we should take to reproduce the error or specified behavior. Expected behavior: Explain what you expect to happen when you run the code above. Actual behavior: Explain the undesired behavior or error you see when you run the code abo…

Another approach could be to reset important session state variables of the app after a certain amount of time has elapsed if there were no changes made to those session state variables.

---

<div class="post-metadata">

**Author:** ![IndigoJay](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/indigojay/32/34270_2.png) [@IndigoJay](https://discuss.streamlit.io/u/IndigoJay)\
**Post date:** [November 17, 2023, 3:18pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/3 "2023-11-17T15:18:42Z")

</div>

Using thread timers is leading me into a part of Streamlit with errors like

`missing ScriptRunContext`

and github issues with warnings like:

> <https://github.com/streamlit/streamlit/issues/1326>
>
> If you create a thread from your Streamlit script, and call streamlit functions …from within that thread, you need to attach a \`ReportContext\` to it or else your \`st.foo()\` calls won't do anything, and you'll get a warning message that looks something like this:
> 
> “Thread ‘Thread-7’: missing ReportContext”
> 
> We should improve the error message to tell the user how to fix this! (We may just want an FAQ entry that we can link to from the error message.)
> 
> (The fix is to use \`add\_report\_ctx\` on the thread immediately after it's created:)
> 
> \`\`\`python
> from streamlit.ReportThread import add\_report\_ctx
> 
> thread = threading.Thread(target=...)
> add\_report\_ctx(thread)
> thread.start()
> \`\`\`
> 
> Related discussion: https://discuss.streamlit.io/t/how-to-run-a-subprocess-programs-using-thread-inside-streamlit/2440
> 
> (2022 edit: please see my comments \[here\](https://github.com/streamlit/streamlit/issues/1326#issuecomment-1024399877) - this is an internal Streamlit API and has some major caveats. In particular, please \*do not\* call \`st.foo\` commands from other threads - at least in production code that needs to be stable.)
> 
> \---
> 
> Community voting on feature requests enables the Streamlit team to understand which features are most important to our users.
> 
> \*\*If you'd like the Streamlit team to prioritize this feature request, please use the 👍 (thumbs up emoji) reaction in response to the initial post.\*\*

> [Jan 28, 2022]  
> … this is still an internal Streamlit API and therefore unsupported and subject to change. (We don’t _try_ to break peoples’ code when we change internals, but we don’t make any guarantees that we won’t.)  
> Note also that issuing Streamlit commands from other threads is undefined behavior. Streamlit’s various `st.foo` commands are _not thread safe_, so please don’t do this in production code as you’ll be introducing race conditions into your apps!

---

<div class="post-metadata">

**Author:** ![Goyo](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/goyo/32/28219_2.png) [@Goyo](https://discuss.streamlit.io/u/Goyo)\
**Post date:** [November 17, 2023, 8:37pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/4 "2023-11-17T20:37:25Z")

</div>

Before dealing with threading issues, what is supposed to happen after the timeout? Because, as far as I know, there is no API to kill a session. You are calling `st.stop()`, but you have that for free as long as your app is free of infinite loops.

That said, I think I found a way to detect a timeout that seems to work. But I still don’t know what to do with it.

```python
import queue

q = queue.SimpleQueue()

# Your code here.

try:
    q.get(block=True, timeout=5)
except queue.Empty:
    # What should hapen here?
    ...

```

---

<div class="post-metadata">

**Author:** ![IndigoJay](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/indigojay/32/34270_2.png) [@IndigoJay](https://discuss.streamlit.io/u/IndigoJay)\
**Post date:** [November 17, 2023, 10:26pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/5 "2023-11-17T22:26:28Z")

</div>

> [@Goyo](#):
>
> ```auto
> what is supposed to happen after the timeout?
> 
> ```

I want the application to run a home built `logout()` function after 60 minutes of user inactivity.

> [@Goyo](#):
>
> ```auto
> ...as long as your app is free of infinite loops....
> 
> ```

I think i see what you mean, `st.stop()` doesn’t really stop streamlit in this case:

```auto
import streamlit as st
import queue

st.title("testing queue timer")

q = queue.SimpleQueue()

if st.button("click me"):
    st.write(1+1)

try:
    q.get(block=True, timeout=10)
except queue.Empty:
    st.warning("10 second timeout. stopping streamlit ")
    st.stop() # doesn't actually stop streamlit

```

---

<div class="post-metadata">

**Author:** ![Goyo](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/goyo/32/28219_2.png) [@Goyo](https://discuss.streamlit.io/u/Goyo)\
**Post date:** [November 17, 2023, 10:38pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/6 "2023-11-17T22:38:14Z")

</div>

`st.stop()` will finish the execution of the script, that will happen anyway at that point. But you can call `logout()` instead, whatever it does…

---

<div class="post-metadata">

**Author:** ![IndigoJay](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/indigojay/32/34270_2.png) [@IndigoJay](https://discuss.streamlit.io/u/IndigoJay)\
**Post date:** [November 18, 2023, 2:39am UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/7 "2023-11-18T02:39:05Z")

</div>

I notice the Streamlit `running` message in the top right is constantly animated while the queue is going, is this a bad thing?

---

<div class="post-metadata">

**Author:** ![laciferin](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/laciferin/32/34674_2.png) [@laciferin](https://discuss.streamlit.io/u/laciferin)\
**Post date:** [November 18, 2023, 7:19pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/8 "2023-11-18T19:19:19Z")

</div>

have u considered:

1. Checking user timout logic in a separate thread: if the user times out: pushing True to queue.Queue()
2. Define a parent decorator function (lets call it- “check\_user\_timeout”): that checks if queue is empty or not : and if its non-empty: then calls st.stop()
3. wrapping ur logics inside @check\_user\_timeout

---

<div class="post-metadata">

**Author:** ![Goyo](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/goyo/32/28219_2.png) [@Goyo](https://discuss.streamlit.io/u/Goyo)\
**Post date:** [November 18, 2023, 8:40pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/9 "2023-11-18T20:40:34Z")

</div>

Yes, the same happens during a call to `time.sleep()`. Indeed all the waiting and listening from events is just an abstraction, there is always some active polling under the hood. It is the price you have to pay for synchrinizing threads or processes and it is supposed to be cheap. If in doubt, measure.

---

<div class="post-metadata">

**Author:** ![Goyo](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/goyo/32/28219_2.png) [@Goyo](https://discuss.streamlit.io/u/Goyo)\
**Post date:** [November 18, 2023, 8:41pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/10 "2023-11-18T20:41:59Z")

</div>

I considered and even tried it and failed. I would love to see a imple example of that working.

---

<div class="post-metadata">

**Author:** ![laciferin](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/laciferin/32/34674_2.png) [@laciferin](https://discuss.streamlit.io/u/laciferin)\
**Post date:** [November 19, 2023, 5:05pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/11 "2023-11-19T17:05:33Z")

</div>

can u share me your codebase? I would like to explore and fix it

---

<div class="post-metadata">

**Author:** ![IndigoJay](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/indigojay/32/34270_2.png) [@IndigoJay](https://discuss.streamlit.io/u/IndigoJay)\
**Post date:** [November 19, 2023, 6:25pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/12 "2023-11-19T18:25:04Z")

</div>

An approach from a different direction. Resetting a timestamp at the end of the streamlit code, and checking if the current time and the timestamp are greater in difference than x minutes. This doesn’t really shut down the program at x minutes, but if the user tries to interact with the program after x minutes, then that interaction will trigger the timeout.

Edit: I need to think about the implications of this approach. What if the user waits a few hours then clicks a button to write data to a database, Would this action happen, would it be well past the timeout. or would the time out trigger.

In this example, i start the program, wait 30+ seconds, then click the button, the value of the button is not printed to the page.

```auto
import streamlit as st
import time

if "last_activity_timestamp" not in st.session_state:
    st.session_state.last_activity_timestamp = time.time()

st.title("Testing timer")    
st.write(f"Last Activity Time: {st.session_state.last_activity_timestamp}")

time_difference = time.time() - st.session_state.last_activity_timestamp
st.write(f"Time Difference: {time_difference}")

if time_difference > 0.5 * 60: ## 30 seconds because testing
    st.warning("Session timed out due to inactivity.")
    st.stop()

if st.button("click me"):
    st.write(1+1)

st.session_state.last_activity_timestamp = time.time() # This must be at the end!

```

---

<div class="post-metadata">

**Author:** ![Goyo](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/goyo/32/28219_2.png) [@Goyo](https://discuss.streamlit.io/u/Goyo)\
**Post date:** [November 19, 2023, 6:27pm UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/13 "2023-11-19T18:27:49Z")

</div>

Unfortunately I dont’t keep any of that.

---

<div class="post-metadata">

**Author:** ![laciferin](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/laciferin/32/34674_2.png) [@laciferin](https://discuss.streamlit.io/u/laciferin)\
**Post date:** [November 20, 2023, 8:35am UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/14 "2023-11-20T08:35:37Z")

</div>

@Goyo check this out: [https://timeout.streamlit.app](https://timeout.streamlit.app)

There are so many things that used to work but no longer working in streamlit

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/streamlit/original/3X/c/f/cf4c2ee0d938358f82448c5fe4b9c3c91d7ce19c.svg) [@system](https://discuss.streamlit.io/u/system)\
**Post date:** [May 18, 2024, 8:35am UTC](https://discuss.streamlit.io/t/how-to-implement-a-user-inactivity-timeout/55613/15 "2024-05-18T08:35:54Z")

</div>

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.
