Most computers on the internet do not have their own public IP address. They have a private address (192.168.x.x, 10.x.x.x) on a local network, and a router somewhere translates between that private address and a single public one shared by every device on the network. That translation is what NAT does. It is so universal that most developers never think about it — until they try to write peer-to-peer software.
The problem NAT creates for peer-to-peer is symmetric. Neither peer knows its public mapping until it sends a packet out and observes what the other side received. Worse, NATs come in flavours — full-cone, restricted-cone, port-restricted, symmetric — that differ in how strictly they enforce which incoming packets they will deliver back through the translation. A symmetric NAT, the strictest kind, will refuse to forward an inbound packet from any source other than the one the original outbound packet was addressed to.
WebRTC handles this with ICE, which gathers candidates from every plausible address (local, STUN-discovered public, TURN-relayed) and tries them in priority order. When ICE fails, the failure is almost always a NAT story underneath — usually two symmetric NATs at opposite ends of a connection that cannot be threaded without a TURN relay carrying the traffic.