Skip to content

joeymalvinni/webrtc-ip

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

59 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

webrtc-ip banner

Apache 2.0 License Github contributors PRs welcome

webrtc-ip

Fast browser public-IP lookup using WebRTC ICE candidates and a STUN server.

import { getIP, prefetchIP } from "webrtc-ip";

void prefetchIP().catch(() => undefined); // start as early as possible

const ip = await getIP();

webrtc-ip is a browser/client-side library. It requires RTCPeerConnection, so it does not run during SSR or in plain Node.js. In unsupported environments, v5 rejects with a typed WebRTCIPError instead of returning an empty string.

Installation

npm install webrtc-ip
bun add webrtc-ip

Usage

Basic

import { getIP } from "webrtc-ip";

try {
  const ip = await getIP();
  console.log(ip);
} catch (error) {
  console.error("Could not resolve IP", error);
}

Next.js / React

Use it from a client component only:

"use client";

import { useEffect, useState } from "react";
import { getIP, prefetchIP } from "webrtc-ip";

void prefetchIP().catch(() => undefined);

export default function Home() {
  const [ip, setIp] = useState<string | null>(null);

  useEffect(() => {
    getIP()
      .then(setIp)
      .catch(() => setIp(null));
  }, []);

  return <p>{ip ?? "Resolving…"}</p>;
}

Options

const ip = await getIP({
  stun: [
    "stun:stun.l.google.com:19302",
    "stun:stun1.l.google.com:19302"
  ],
  timeout: 3000,
  cache: true,
  cacheTtl: 60_000
});
Option Default Description
stun "stun:stun.l.google.com:19302" STUN URL or URL array. Pass [] with includeLocal: true for local-only candidates.
timeout 3000 Maximum time to wait for ICE candidates, in ms.
cache true Reuse an in-flight/completed lookup for matching options.
cacheTtl Infinity How long completed cached lookups remain fresh, in ms.
includeLocal false Include host/local candidates. Modern browsers may expose mDNS names instead of private IPs.
signal undefined AbortSignal for cancellation.

Rich result

import { getIPInfo } from "webrtc-ip";

const info = await getIPInfo();

console.log(info.ip);        // "203.0.113.42"
console.log(info.type);      // "srflx", "host", "relay", ...
console.log(info.elapsedMs); // lookup duration, not cached-read time

Safe nullable helper

import { getIPOrNull } from "webrtc-ip";

const ip = await getIPOrNull(); // string | null

Cancellation

const controller = new AbortController();

const promise = getIP({ signal: controller.signal, timeout: 5000 });
controller.abort();

await promise; // rejects with WebRTCIPError code "ABORTED"

API

getIP(options?: string | string[] | GetIPOptions): Promise<string>
getIPInfo(options?: string | string[] | GetIPOptions): Promise<GetIPInfoResult>
getIPOrNull(options?: string | string[] | GetIPOptions): Promise<string | null>
prefetchIP(options?: string | string[] | GetIPOptions): Promise<string>
clearIPCache(): void
isSupported(): boolean
isWebRTCIPError(error: unknown): error is WebRTCIPError

Errors

Failures reject with WebRTCIPError:

import { getIP, isWebRTCIPError } from "webrtc-ip";

try {
  await getIP();
} catch (error) {
  if (isWebRTCIPError(error)) {
    console.log(error.code);
  }
}

Error codes:

  • UNSUPPORTED β€” RTCPeerConnection is unavailable, such as SSR/Node.js.
  • TIMEOUT β€” no accepted candidate arrived before timeout.
  • NO_PUBLIC_CANDIDATE β€” ICE completed without a public/server-reflexive candidate.
  • WEBRTC_BLOCKED β€” browser policy, permissions, or networking blocked WebRTC setup.
  • INVALID_STUN_URL β€” a STUN URL is malformed.
  • INVALID_OPTIONS β€” timeout or cacheTtl is invalid.
  • ABORTED β€” the supplied AbortSignal was aborted.

Notes

  • prefetchIP() starts the same cached lookup that getIP() reads later. This is what makes later calls fast.
  • If you fire-and-forget prefetchIP(), attach a .catch() handler because unsupported or blocked environments reject.
  • WebRTC/STUN still performs a network round trip and can fail on restrictive networks, VPNs, hardened browsers, or when WebRTC/UDP is disabled.
  • Local candidates may be masked as .local mDNS names by modern browsers.

Migration from v4 to v5

  • Unsupported environments now reject with WebRTCIPError code UNSUPPORTED instead of resolving "".
  • Package exports now provide both CommonJS and ESM entry points.
  • New APIs: isSupported, getIPInfo, getIPOrNull, isWebRTCIPError, cacheTtl, and AbortSignal support.

Authors

The author of webrtc-ip is Joey Malvinni.

List of all contributors

License

Apache 2.0