Getting user's IP address in an app

If I do this in a server function :

print(anvil.server.request.remote_address)

I get this error :

AttributeError: 'HttpRequest' object has no attribute 'remote_address'

Definitely not using httprequest.

What are you trying to do? The anvil.server.request object is only available inside HTTP API calls - see the documentation. Are you trying to use the object inside a standard server call?

I agree itā€™s a little confusing that anvil.server.request is set to an empty anvil.server.HttpRequest object by default. I will make sure we fix that to be None in the case of a standard server call.

Ah, ok. I wanted the IP so I could log it for future auditing.
Any way I can get it? Client or server side is fine.

EDIT - I could obviously do it the way you show in the docs by calling ip.jason.com but that seems a little overkill.

Do you mean you want the IP of the browser where the server call was initiated? Sadly an anvil.http.request to ip.jsontest.com will give you one of our egress IPs where the outgoing request actually originates.

We donā€™t currently have a mechanism for getting client information from the current session, but itā€™s on our (very) long list of features that would be nice to have. Customers on our Anvil support plans are able to commission or prioritise features on our roadmap - please do get in touch by email if that is something you would be interested in.


EDIT: You can now get the client IP from anvil.server.context

I assume thereā€™s no way to consume an external API in the client? I can put the URL to a server endpoint in a link but Iā€™d need a way to ā€œclickā€ it and absorb the result.

I think Iā€™m probably barking up a dead tree ā€¦

You can use anvil.http.request() from client code as well, and it will come from the browserā€™s IP.

However, there are two major caveats to mention:

  1. Itā€™s restricted in what you can request. You canā€™t access unencrypted HTTP resources like http://ip.jsontest.com (because Anvil apps are all HTTPS, so the browser wonā€™t allow it), and you canā€™t access URLs on other websites that arenā€™t ā€œcross-originā€. (Making requests to an API endpoint in your own app should be fine, though.)

  2. It happens in client code, which is inherently untrusted. A malicious user can modify the client code and, eg, prevent it from contacting the API endpoint that records its IP.

If youā€™re OK with those two caveats, then yes, absolutely - import anvil.http on the client side and hit a server http_endpoint that records its address in anvil.server.session.

Hope that helps!

1 Like

I do keep forgetting I have to import the library. Thatā€™s my lack of python knowledge showing through.

Thanks, chaps!

Just for completeness (and in case anyone is interested), this should work -

In a server module :

  @anvil.server.http_endpoint("/tools/:v")
  def tools(v, **params):
    if v=="myip":
    # Return it or store it somewhere.
    return anvil.server.request.remote_address

From your client (form) :

  import anvil.http
  ...
  myip=anvil.http.request("https://<yourappid>.anvilapp.net/_/api/tools/myip")
  print(repr(a.get_bytes()))
1 Like

Some client side approaches until itā€™s supported server side https://stackoverflow.com/questions/391979/how-to-get-clients-ip-address-using-javascript-only

Expounding a bit, basically itā€™s a webrtc hack that may be removed, or hitting some other server. Randall Degges built ipify.org for this and runs it on heroku. Heā€™s an awesome person and says heā€™ll keep it going. I trust him and would use that.

Is it possible to update the API reference for this as well? Right now itā€™s pretty thin:

context

Contains information about what triggered the currently running code.

https://anvil.works/docs/api/anvil.server#context

Just throwing this out there, but I independently found and started using ipify for casual usage. Hereā€™s the code required if using within Anvil:

import anvil.http
import json
ip = anvil.http.request(ā€˜https://api.ipify.org?format=jsonā€™,method='GETā€™,json=True)
ipAddress = ip[ā€˜ipā€™]
print(ipAddress)

Thanks for that, but I think external methods are not really necessary now since @daviesian updated his answer above :

2 Likes

ā€¦For anyone looking for it here is an example of anvil.server.context being used that I posted a while ago:

1 Like