The most likely source of this information is your browser’s WebRTC implementation.
You can see this in the source code of ip-api.com.
From https://github.com/diafygi/webrtc-ips, which also provides a demo of this technique:
Firefox and Chrome have implemented WebRTC that allow requests to STUN servers be made that will return the local and public IP addresses for the user. These request results are available to javascript, so you can now obtain a users local and public IP addresses in javascript.
It was recently noted that the New York Times was using this technique to help distinguish between real visitors and bots (i.e. if the WebRTC API is available and returns valid info, it’s likely a real browser).
There are a couple of Chrome extensions that purport to block this API, but they don’t seem to be effective at the moment. Possibly this is because there aren’t yet the hooks in the browser, as that GitHub README alludes to:
Additionally, these STUN requests are made outside of the normal XMLHttpRequest procedure, so they are not visible in the developer console or able to be blocked by plugins such as AdBlockPlus or Ghostery.