Prevent permission request when using `geolocation` at page load

When a geolocation component is present in a Dash app layout, the user will be requested to allow/disable location permission already at load time, regardless whether the location has actually been requested or not in a callback.

This is kind of confusing for the user (as nothing is really happening afterwards), and causes a Violation from react.js to appear in the console, because in theory location permissions should only be requested in response to a user gesture.

To be clear Dash doesn’t really update the location, but it only requests permission. You still an additional callback to trigger a position refresh.

Shouldn’t this be changed to respect react guidelines?

Hi @guidocioni

You could try adding the dcc.Geolocation to the layout in a callback only when those features are used.

Can you make an example app that will trigger the violation? I added the Geolocation component to a layout and it only asked for permission – there were no errors in the console.

Hey,
in my case the geolocation component is where the button that requests the geolocation also is. I think that changing its position wouldn’t change the behaviour as, regardless of where it’s placed in the app, it will be loaded in the layout at first page request.

The violation is only visible if you activate the VERBOSE level in the console, so it wouldn’t be visible by default.

I agree this is not a major issue but, AFAIK, all the websites on my browser that use geolocation ONLY request permission once I press on the button/perform the action that is supposed to trigger a refresh of the geolocation. That’s why I was confused to receive the permission request on page load.

Do you think this should be the default behaviour? Maybe I’m wrong :slight_smile:

@guidocioni

What I mean is something like this: The geolocation component is added in the callback when its used. Here’s one way to do it:


from dash import Dash, dcc, html, Input, Output, callback

app = Dash(__name__, suppress_callback_exceptions=True)

app.layout = html.Div(
    [
        html.Button("Update Position", id="geo-start-btn"),
        html.Div(id="geo"),
    ]
)

@callback(
    Output("geo", "children"),
    Input("geo-start-btn", "n_clicks"),
    prevent_initial_call=True
)
def start_geolocation_section(n):
    return  html.Div([
        html.Button("Update Position", id="update_btn"),
        dcc.Geolocation(id="geolocation"),
        html.Div(id="text_position"),
    ])


@callback(Output("geolocation", "update_now"), Input("update_btn", "n_clicks"))
def update_now(click):
    return True if click and click > 0 else False


@callback(
    Output("text_position", "children"),
    Output("geo-start-btn", "style"),
    Input("geolocation", "local_date"),
    Input("geolocation", "position"),
)
def display_output(date, pos):
    if pos:
        return html.P(
            f"As of {date} your location was: lat {pos['lat']},lon {pos['lon']}, accuracy {pos['accuracy']} meters",
        ), {"display": "none"}
    return "No position data available", {"display": "none"}


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


Ah well, that’s a cool trick.
I thought all the layout IDs had to be defined when running the application, I didn’t know they could be dynamically populated.
That seems to work well, althought it requires an additional callback…

My solution was to use a Div made just by the geolocation component which is populated when the button is pressed.

@callback(
    Output("geo", "children"), Input("geolocate", "n_clicks"), prevent_initial_call=True
)
def start_geolocation_section(n):
    return html.Div(
        [
            dcc.Geolocation(id="geolocation"),
        ]
    )