Get browser user agent strings

Hi there,

I am building a simple dash web app and I am wondering if there is any simple way I can get the browser user agent strings?

I would like to check if the device is mobile or PC, and then do different things in the app layout accordingly (like changing graph config, etc).

Thank!

Hello @Trydash2021,

Never tried but I think it is possible using flask, you can then store this information and then manipulate your layout accordingly.

Thanks for your reply!

Indeed, apparently one of these two should do the work:

print(request.headers.get(ā€˜User-Agent’))
print(flask.request.user_agent.string)

However, now sure how to implement them. Does anyone has any idea where and how to implement this in a simple dash app and be able to get this string to make some changes in the layout?

Sorry for the simple question :slight_smile: , I am quite ok with python but but relative new to dash and flask

Hi @Trydash2021

Not only should you Trydash2021, you should Trydash-bootstrap-components :wink:

Here is more information on how to adjust your layout for different screen sizes using the breakpoints in Bootstrap:
https://dash-bootstrap-components.opensource.faculty.ai/docs/components/layout/

See more information on how to get started with dash-bootstrap-components here

Here is a handy cheat sheet for using Bootstrap classes with Dash.

Your are right indeed! :grinning:

I am actually already using bootstrap-components row, columns and container to adjust the columns width as a function of the screen width which is great!

However the reason I am asking to the user agent, and understand if device is mobile, is because I want to change the graph config if the device is mobile, i.e. when screen width is xs. More specifically I want to make the plotly graph static if the screen width is small (xs as it is called in the doc. col() ) .

I already got the possibility to change that manually with a button and a call back. Why I do that? Because scrolling plotly graph with the zoom ā€œonā€ on a phone can difficult.

But I would like to make it automatic or at least to get the default choice automatic when loading the app.

I can do that with my call back but I need to get somehow the screen width or the device type.

Do you know if i get the screen width or device type (user agent string) in python with any component in a dash app?

Thanks in advance for any advice!

Hey @Trydash2021

Oh, I see what you are asking. My previous post was for people who really are ā€œnew to dash and flaskā€ :slight_smile:

I’ve run into that problem too - where it’s difficult to scroll on a small screen because the graphs will zoom instead of scrolling the page. I typically just disable the graph zoom on all screen sizes as a workaround. But it would be nice to get a better solution.

I wasn’t able to get anything like this working:

print(request.headers.get(ā€˜User-Agent’))
print(flask.request.user_agent.string)

It looks like it could be an elegant solution. If anyone knows how to do this, please feel free to post an example in this thread.

In the meantime, you can use a clientside callback to get the screen width and height, then update the `dcc.Graph(config=…) in a callback. Since Dash callbacks run at startup, this can be used to configure the graphs for the screen size.

However, this may not be a great solution either because this issue has more to do with touch screens than screen size. Large tablets, ipad or PCs with a touch screen will have this same zoom/scroll issue.

Here is a MWE of a clientside callback to get screen width and height:


from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px
import dash_bootstrap_components as dbc

df = px.data.tips()


app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])


app.layout = dbc.Container(
    [dcc.Store(id="store"), dbc.Card(html.Div(id="graph-container"))], fluid=True,
)

app.clientside_callback(
    """
    function(trigger) {
        //  can use any prop to trigger this callback - we just want to store the info on startup
        const screenInfo = {height :screen.height, width: screen.width};        
        return screenInfo
    }
    """,
    Output("store", "data"),
    Input("store", "data"),
)


@app.callback(Output("graph-container", "children"), Input("store", "data"))
def update(screen):
    if screen and screen["height"] < 1000:
        return dcc.Graph(
            id="graph",
            figure=px.bar(df, x="day", y="total_bill"),        
            config={"displayModeBar": False},
        )
    else:
        return no_update


if __name__ == "__main__":
    app.run_server(debug=True)

1 Like

Hi! Many thanks!
It work smoothly :slight_smile: my ā€œclientsideā€ and JS knowledge are indeed quite limited, this was helpful!

I did a small variation which get the user_agent string and check if the device is touch or not

below the code if could be any useful

P.S.

"displayModeBar": True

it is not enough to make the plotly graph static, one should specify also

 'staticPlot': False

Here is the small variation that check if device is touch

from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import dash_bootstrap_components as dbc

df = px.data.tips()

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([
    dbc.Container(
        [dcc.Store(id="store"), dbc.Card(html.Div(id="graph-container"))], fluid=True,),    
    ])

app.clientside_callback(
    """
    function(trigger) {
        //  can use any prop to trigger this callback - we just want to store the info on startup
        // USE THIS TO GET screen dimensions 
        // const screenInfo = {height :screen.height, width: screen.width};  
        // USE THIS TO GET useragent string
        screenInfo = navigator.userAgent;
        return screenInfo
    }
    """,
    Output("store", "data"),
    Input("store", "data"),
)



@app.callback(Output("graph-container", "children"), Input("store", "data"))
def update(JSoutput):
    
 
    ############
    # Check if it is "touch_capable"
    ############
    
    print('THIS IS USER AGENT STRING:',JSoutput)
    from user_agents import parse
    user_agent = parse(JSoutput)
    # if user_agent.is_mobile is True:
    # if user_agent.is_tablet is True:
    if user_agent.is_touch_capable is True:
        print('####### DEVICE is touch') 
        return dcc.Graph(
                    id="graph",
                    figure=px.bar(df, x="day", y="total_bill"),        
                    config={"displayModeBar": False,
                            'staticPlot': True},
                )        
        
        
    else:
        print('####### DEVICE is NOT touch')
        return dcc.Graph(
            id="graph",
            figure=px.bar(df, x="day", y="total_bill"),        
            config={"displayModeBar": True,
                    'staticPlot': False},
        )      
        
    ############
    # check screen width
    ############
    
    # print(JSoutput["width"])
    # if JSoutput and JSoutput["width"] < 500:
    #     return dcc.Graph(
    #         id="graph",
    #         figure=px.bar(df, x="day", y="total_bill"),        
    #         config={"displayModeBar": False,
    #         'staticPlot': True},
    #     )
    # else:
    #     return dcc.Graph(
    #         id="graph",
    #         figure=px.bar(df, x="day", y="total_bill"),        
    #         config={"displayModeBar": True,
    #         'staticPlot': False},
    #     )


if __name__ == "__main__":
    app.run_server(debug=True)


2 Likes