'Python Streamlit running on Heroku - how to get remote/client ip?

I was able to deploy an Streamlit App to Heroku. I did that to compare Heroku and Streamlit Share. Both runs fine, but I want to log client's IP (remote IP) to understand where my app is getting accessed from.

I'm googling for two days now without success. I saw a lot of posts related to the subject, most discussing how to get the real IP, where is it HTTP_X_FORWARDED_FOR and so on.

At first I understood that ENV['HTTP_X_FORWARDED_FOR'] was a environment var which I could get and parse using os.environ['HTTP_X_FORWARDED_FOR'] but it is not the case. I even tried request.headers['X-Forwarded-For'] which requires Flask but I learnt that Flask and Streamlit do not get along. Other solutions dealing with PHP/Java are beyond my knowledge.

So, my question is: "Is it possible to get remote IP using a Python package, without Flask?"



Solution 1:[1]

You can make the client inform the IP address to the host by using the streamlit-javascript package and inserting a JavaScript code that access an external service, e.g. api.ipify.org.

import streamlit as st
from streamlit_javascript import st_javascript


def client_ip():

    url = 'https://api.ipify.org?format=json'

    script = (f'await fetch("{url}").then('
                'function(response) {'
                    'return response.json();'
                '})')

    try:
        result = st_javascript(script)

        if isinstance(result, dict) and 'ip' in result:
            return result['ip']

    except:
        pass


ip_address = client_ip()  # now you have it in the host...

st.write(ip_address)  # so you can log it, etc.

It's not a perfect solution (as it won't be of any use inside a NAT, for instance), but I think it's as far as you can go with Streamlit.

Of course, acquiring the request IP from Tornado (the webserver) could be a Streamlit feature, but it isn't just yet.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1