4

I want to get user's location. When I test the following code on my local computer it returns the correct position. Tried to change location with vpn and everything worked correctly too.
app.py:

@app.route('/')
def index():
    url = 'http://freegeoip.net/json'
    r = requests.get(url)
    j = json.loads(r.text)
    city = j['city']

    print(city)

But when I run my site with the same code on pythonanywhere it returns one incorrect city all the time, doesn't matter wherever I connect from. Does it return the location of the server instead? How can I get the correct location of each user?

Steve
  • 722
  • 4
  • 10
  • 24

1 Answers1

5

You're using your server IP for geolocation. When you visit that particular endpoint, it takes the client IP addresses, so when you deployed your app to Pythonanywhere - the client to that endpoint becomes the server.

When you were running the locally on your PC, you were requesting the API endpoint using your IP address - so if you switched to VPN, your IP address also changed.

In order to fix your current code, you need to pass the IP address of the client to freegeoip.net/json endpoint. Try this:

from flask import request

@app.route('/')
def index():
    url = 'http://freegeoip.net/json/{}'.format(request.remote_addr)
    r = requests.get(url)
    j = json.loads(r.text)
    city = j['city']

    print(city)

However, keep in mind that this API endpoint is deprecated and will stop working on July 1st, 2018. For more information please visit: https://github.com/apilayer/freegeoip#readme - you may want to start using their new service - my solution is still applicable to their new API.

In some cases (like in Pythonanywhere) there might be a proxy server in front of your web app, rendering the request.remote_addr useless. In that case you should use the X-Forwarded-For header. Remember to use the correct value though. Have a look at this good solution for more info.

samu
  • 2,870
  • 16
  • 28
  • I tried to do so but the problem is that request.remote_addr returns private ip address and the output of the request for such ip is empty – Steve May 09 '18 at 11:37
  • 1
    Try deploying it to the server and see if that works. If not, instead of using `request.remote_addr` try using `request.headers.get('X-Forwarded-For')` - normally the http server should set the remote address for you, but in some cases it only puts the original IP address in that header. I didn't use Pythonanywhere, so I'm not sure which one it does. – samu May 09 '18 at 11:41
  • thank you, request.headers.get('X-Forwarded-For') worked! – Steve May 09 '18 at 12:59
  • Great, I'll edit the answer to include that as well. – samu May 09 '18 at 13:04