get-client-ip
Version:
📍 A Lightweight Utility for Extracting the Real Client IP Address from Incoming HTTP Requests
148 lines (104 loc) • 5.87 kB
Markdown
<div align="center">
<img src="https://github.com/WolfieLeader/npm/blob/main/assets/get-client-ip-banner.svg" align="center" alt="banner" />
<h1 align="center">get-client-ip</h1>
<p align="center">
Extract the real client IP from HTTP requests.<br/>
Works standalone or as Express/NestJS middleware.
</p>
<a href="https://opensource.org/licenses/MIT" rel="nofollow"><img src="https://img.shields.io/github/license/WolfieLeader/npm?color=DC343B" alt="License"></a>
<a href="https://www.npmjs.com/package/get-client-ip" rel="nofollow"><img src="https://img.shields.io/npm/v/get-client-ip?color=0078D4" alt="npm version"></a>
<a href="https://www.npmjs.com/package/get-client-ip" rel="nofollow"><img src="https://img.shields.io/npm/dt/get-client-ip.svg?color=03C03C" alt="npm downloads"></a>
<a href="https://github.com/WolfieLeader/npm" rel="nofollow"><img src="https://img.shields.io/github/stars/WolfieLeader/npm" alt="stars"></a>
</div>
## Highlights ✨
- **Checks 14 sources** (headers + socket) in priority order
- **Handles** comma-separated, array, and RFC 7239 `Forwarded` formats
- **Framework compatibility** — supports Express v5/v4 and NestJS (Express adapter)
- **Flexible usage** — works standalone or as middleware, and auto-populates typed `req.clientIp` and `req.clientIps`
- **Zero config** — validates IPs using Node.js `net.isIP()`
## Installation 📦
Requires Node.js >= 18.
```bash
npm install get-client-ip
# or
pnpm add get-client-ip
```
## Quick Start 🚀
```typescript
import express from "express";
import { getClientIp } from "get-client-ip";
const app = express();
// Middleware — auto-populates req.clientIp and req.clientIps
app.use(getClientIp);
app.get("/me", (req, res) => {
res.json({ ip: req.clientIp, ips: req.clientIps });
});
// Or standalone — call directly in a specific route
app.get("/ip", (req, res) => {
const ip = getClientIp(req);
res.json({ ip });
});
app.listen(3000);
```
## API Reference 📖
### `getClientIp(req, res?, next?): string | undefined`
Extracts the client's IP address from an incoming request. Works both as a standalone function and as Express middleware. Returns `string | undefined`.
**Side effects:** Sets `req.clientIp` and `req.clientIps` on the request object when a valid IP is found. Throws if `req` is `undefined`.
### TypeScript Augmentation
The package augments the Express `Request` type automatically:
```typescript
// These properties are available after calling getClientIp
req.clientIp; // string | undefined — first valid IP
req.clientIps; // [string, ...string[]] | undefined — all valid IPs (non-empty array)
```
No manual type declarations are needed.
## Header Priority 📋
Sources are checked in the following order. The first valid IP found is returned.
| Priority | Source | Description |
| -------- | -------------------------- | -------------------------------------- |
| 1 | `req.ip` | Express `trust proxy` setting |
| 2 | `Forwarded` | RFC 7239 (parsed for `for=` directive) |
| 3 | `CF-Connecting-IP` | Cloudflare |
| 4 | `True-Client-IP` | Akamai / Cloudflare Enterprise |
| 5 | `Fastly-Client-IP` | Fastly CDN |
| 6 | `X-Appengine-User-IP` | Google App Engine |
| 7 | `CF-Pseudo-IPv4` | Cloudflare pseudo-IPv4 |
| 8 | `X-Client-IP` | General proxy header |
| 9 | `X-Forwarded-For` | De facto standard proxy header |
| 10 | `Forwarded-For` | Variant of X-Forwarded-For |
| 11 | `X-Forwarded` | Microsoft variant |
| 12 | `X-Real-IP` | Nginx proxy header |
| 13 | `X-Cluster-Client-IP` | Rackspace / Riverbed |
| 14 | `req.socket.remoteAddress` | Direct connection fallback |
## NestJS 🧩
```typescript
import { Controller, Get, Req } from "@nestjs/common";
import type { Request } from "express";
import { getClientIp } from "get-client-ip";
()
export class AppController {
("ip")
getIp(() req: Request) {
const ip = getClientIp(req);
return { ip };
}
}
```
## Security 🛡️
> **Header trust warning:** When `req.ip` is not populated, forwarding headers are used only when `req.socket.remoteAddress` appears to be from a local/private proxy range. Public socket peers skip header fallback to reduce spoofing risk.
**In production behind a reverse proxy:**
1. Configure Express's [`trust proxy`](https://expressjs.com/en/guide/behind-proxies.html) setting so that `req.ip` is correctly populated
2. This ensures the function returns `req.ip` first and avoids fallback ambiguity
3. Without `trust proxy`, forwarding headers may still be ignored when the peer is public
> **CGNAT addresses:** Addresses in the `100.64.0.0/10` range (RFC 6598) are treated as public, not trusted proxy addresses. Headers are not trusted when the socket peer is a CGNAT address. If your application is behind a load balancer (e.g., AWS ALB), configure Express's `trust proxy` setting so `req.ip` is populated correctly.
## Credits 🙏
Inspired by [Petar Bojinov's](https://github.com/pbojinov) work on client IP detection.
## Contributions 🤝
- Open an [issue](https://github.com/WolfieLeader/npm/issues) or feature request
- Submit a PR to improve the package
- Star the repo if you find it useful
<div align="center">
<br/>
Crafted carefully by [WolfieLeader](https://github.com/WolfieLeader)
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).
</div>