Streamlit Debugging Tricks: A handy guide to building a sticky debug div for debug.print calls

Hi all!

As not-a-developer, I often find myself inserting debugging statements like st.write(some_variable) throughout my code. This can be suboptimal, so I created a proof-of-concept for a “debug.print” command that allows me to directly print debug information in my Streamlit app :slight_smile:

Idea: create a div that which will stick to the bottom and contain debugging info. Include time & line of code from which debug command was triggered. Save history and be able to scroll.

Github: GitHub - TomJohnH/streamlit-debug

Code elements:

  1. Very simple external module
  2. External css style debug.css


  1. Create python file (or use the function directely)
import streamlit as st
import datetime
from inspect import getframeinfo, stack

def debug(input):
    if "debug_string" not in st.session_state:
        st.session_state["debug_string"] = "<b>Debug window ☝️</b>"
    now =
    st.session_state["debug_string"] = (
        "<div style='border-bottom: dotted; border-width: thin;border-color: #cccccc;'>"
        + str(now.hour)
        + ":"
        + str(now.minute)
        + ":"
        + str(now.second)
        + " Debug.print["
        + str(getframeinfo(stack()[1][0]).lineno)
        + "] "
        + str(input)
        + "</div>"
        + st.session_state["debug_string"]
  1. Create external css file:
.debug {
    padding-left: 10px;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    max-height: 200px;
    background-color: #333;
    color: #ccc;
    width: 100%;
    overflow: auto;
    font-family: monospace;
  1. Import module:
import st_debug as d
  1. Load css:
def local_css(file_name):
    with open(file_name) as f:
        st.markdown(f"<style>{}</style>", unsafe_allow_html=True)

  1. At the bottom of your code make additional div:
if "debug_string" in st.session_state:
        f'<div class="debug">{ st.session_state["debug_string"]}</div>',

Write debugging commands:

a = np.matrix("1 2; 3 4")
d.debug("this presents state of the matrix " + str(a))


if "counter" not in st.session_state:
    st.session_state["counter"] = 1

d.debug("counter " + str(st.session_state["counter"]))
  1. That’s all :slight_smile: Above method is easily reusable in other apps (in fact you have to only import external file, load css and you are ready to go)


Let’s say that you like the div but you would like to toggle it’s visibility with CTRL + Q shortcut.

  1. Expand file with function storing js code that will be responsible for div toggle and reaction to key presses:
def js_code():
    return """
    function myFunction() {
    var x = window.parent.document.getElementById("debug");
    if ( === "none") { = "block";
    } else { = "none";

    function KeyPress(e) {
        var evtobj = window.event? event : e
        if (evtobj.keyCode == 81 && evtobj.ctrlKey) myFunction();

    const doc = window.parent.document;
    doc.onkeydown = KeyPress;

  1. import streamlit.components.v1 in your main app file
import streamlit.components.v1 as components
  1. Below the “debug div” add js script using components.html

Now you can toggle the debug div with CTRL+Q keys combination.

  1. Happy streamliting!

Looks super cool! We’ve been thinking about having something like this built-in for a long time, maybe with some additional features like a profiler or a view on what’s in your session state and cache.

1 Like

Hi @jrieke, thank you for the comment. Having a build in “watcher” would be very usefull! :slight_smile:

For anyone interested: as my example is somewhat quick and dirty PoC, direct d.debug(st.session.state) would not look good (session state saves value of "debug_string" variable that is used to print out debugg info). If you need to print out session state info you can create dictionary without "debug_string"

session_state_without_debug = {}
for key in st.session_state:
    if key != "debug_string":
        session_state_without_debug[key] = st.session_state[key]