Flask
Python
IP address
web development
visitor tracking

Get IP address of visitors using Flask for Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Flask, the simplest way to get a visitor's IP address is request.remote_addr. That answer is only fully correct when Flask is receiving the client connection directly, though, because reverse proxies and load balancers change what Flask sees as the remote peer.

Direct Requests: Use request.remote_addr

For a basic Flask app running without a proxy in front of it, the client IP is available on the request object:

python
1from flask import Flask, request
2
3app = Flask(__name__)
4
5@app.route("/")
6def index():
7    return {"ip": request.remote_addr}
8
9if __name__ == "__main__":
10    app.run(debug=True)

If you call this app directly from a browser or a local HTTP client, request.remote_addr is usually the address you want to log.

Why Proxies Change the Answer

In production, Flask is often behind Nginx, a cloud load balancer, or another reverse proxy. In that setup, the TCP connection reaching Flask comes from the proxy, not from the original browser.

So if you read request.remote_addr without any proxy configuration, you may get:

  • the local reverse proxy address
  • the load balancer address
  • another internal hop instead of the real visitor IP

That is expected behavior. Flask only sees the immediate peer unless you explicitly tell it which forwarded headers to trust.

The Safe Way Behind a Proxy

Flask applications behind a trusted reverse proxy should use Werkzeug's ProxyFix middleware with the correct number of proxy hops:

python
1from flask import Flask, request
2from werkzeug.middleware.proxy_fix import ProxyFix
3
4app = Flask(__name__)
5app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
6
7@app.route("/")
8def index():
9    return {"ip": request.remote_addr}
10
11if __name__ == "__main__":
12    app.run()

After that middleware is configured correctly, request.remote_addr reflects the forwarded client address rather than the local proxy address.

Do Not Trust X-Forwarded-For Blindly

Beginners often read the header directly:

python
request.headers.get("X-Forwarded-For")

That is unsafe unless you control the proxy chain and configure trust boundaries correctly. Clients can send fake forwarded headers themselves. ProxyFix exists so the application can trust only the expected number of proxy layers instead of treating arbitrary headers as facts.

If you must inspect the raw header for diagnostics, treat it as untrusted input until your deployment setup guarantees who set it.

Logging the IP Address

A common use case is request logging:

python
1from flask import Flask, request
2
3app = Flask(__name__)
4
5@app.route("/hello")
6def hello():
7    app.logger.info("visitor_ip=%s path=%s", request.remote_addr, request.path)
8    return "hello"

That is useful for:

  • operational debugging
  • rate limiting
  • abuse detection
  • rough geographic analytics

Be careful, though. IP addresses are sensitive data in many privacy regimes, so only log them when there is a clear purpose.

IPv4, IPv6, and Local Testing

Do not assume every address is IPv4. Flask may return IPv6 loopback or client addresses depending on the network path.

For example, local development can show values such as:

  • '127.0.0.1'
  • '::1'

Your code should treat the IP as an address string, not as "always dotted IPv4 text."

A Practical Rule

Use this decision process:

  • no proxy in front of Flask: read request.remote_addr
  • trusted proxy in front of Flask: configure ProxyFix, then read request.remote_addr
  • untrusted forwarded headers: do not treat them as the real client IP

That keeps the code simple and avoids accidental spoofing bugs.

Common Pitfalls

The most common mistake is reading request.remote_addr behind a reverse proxy and assuming the returned address is the real browser IP. Often it is only the proxy's address.

Another issue is trusting X-Forwarded-For directly from request headers. Unless the application is configured to trust a known proxy chain, that header can be forged by the client.

People also forget IPv6. Code that assumes every IP contains dots instead of colons eventually breaks in real deployments.

Summary

  • 'request.remote_addr is the normal way to get the client IP in Flask.'
  • Behind a reverse proxy, configure ProxyFix so Flask can trust forwarded address information correctly.
  • Do not trust forwarded headers blindly from the raw request.
  • Treat IP values as generic address strings that may be IPv4 or IPv6.
  • Use IP logging carefully and only when it serves a real operational need.

Course illustration
Course illustration

All Rights Reserved.