Packages
phoenix_kit
1.7.6
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/utils/geolocation.ex
defmodule PhoenixKit.Utils.Geolocation do
@moduledoc """
IP Geolocation utilities for PhoenixKit.
Provides functionality to extract IP addresses from Phoenix LiveView sockets
and look up geographical location data using free IP geolocation APIs.
## Features
- Extract IP addresses from Phoenix LiveView sockets
- Primary API: IP-API.com (45 requests/minute)
- Fallback API: ipapi.co (1000 requests/day)
- Graceful error handling with fallback to IP-only tracking
- Privacy-first design (disabled by default)
## Usage
# Extract IP from socket
ip_address = PhoenixKit.Utils.Geolocation.extract_ip_from_socket(socket)
# Lookup location data
case PhoenixKit.Utils.Geolocation.lookup_location(ip_address) do
{:ok, location} ->
# Process location data
{:error, reason} ->
# Handle error, fall back to IP-only
end
"""
require Logger
alias PhoenixKit.Utils.IpAddress
@doc """
Extracts IP address from a Phoenix LiveView socket.
## Examples
iex> extract_ip_from_socket(socket)
"192.168.1.1"
iex> extract_ip_from_socket(socket_with_no_peer_data)
"unknown"
"""
def extract_ip_from_socket(socket) do
IpAddress.extract_from_socket(socket)
end
@doc """
Looks up geographical location data for an IP address.
Uses IP-API.com as primary service (45 requests/minute) with ipapi.co
as fallback (1000 requests/day).
## Examples
iex> lookup_location("8.8.8.8")
{:ok, %{
"country" => "United States",
"region" => "California",
"city" => "Mountain View"
}}
iex> lookup_location("invalid-ip")
{:error, "Invalid IP address"}
"""
def lookup_location(ip_address) when is_binary(ip_address) do
case String.trim(ip_address) do
"" -> {:error, "Empty IP address"}
"unknown" -> {:error, "Unknown IP address"}
"127.0.0.1" -> {:error, "Localhost IP address"}
"::1" -> {:error, "Localhost IPv6 address"}
valid_ip -> perform_lookup(valid_ip)
end
end
def lookup_location(_), do: {:error, "Invalid IP address format"}
# Private functions
defp perform_lookup(ip_address) do
case lookup_with_ip_api(ip_address) do
{:ok, location} ->
{:ok, location}
{:error, reason} ->
Logger.warning("IP-API.com lookup failed: #{reason}, trying fallback")
lookup_with_ipapi_co(ip_address)
end
end
defp lookup_with_ip_api(ip_address) do
url = "http://ip-api.com/json/#{ip_address}?fields=status,message,country,regionName,city"
case make_http_request(url) do
{:ok, %{"status" => "success"} = data} ->
location = %{
"country" => data["country"],
"region" => data["regionName"],
"city" => data["city"]
}
{:ok, location}
{:ok, %{"status" => "fail", "message" => message}} ->
{:error, "IP-API.com error: #{message}"}
{:ok, _} ->
{:error, "Invalid response from IP-API.com"}
{:error, reason} ->
{:error, "HTTP request failed: #{reason}"}
end
end
defp lookup_with_ipapi_co(ip_address) do
url = "https://ipapi.co/#{ip_address}/json/"
case make_http_request(url) do
{:ok, %{"error" => true, "reason" => reason}} ->
{:error, "ipapi.co error: #{reason}"}
{:ok, data} when is_map(data) ->
location = %{
"country" => data["country_name"],
"region" => data["region"],
"city" => data["city"]
}
{:ok, location}
{:error, reason} ->
{:error, "HTTP request failed: #{reason}"}
end
end
defp make_http_request(url) do
case Finch.build(:get, url)
|> Finch.request(PhoenixKit.Finch, receive_timeout: 5_000) do
{:ok, %Finch.Response{status: 200, body: body}} ->
case Jason.decode(body) do
{:ok, data} -> {:ok, data}
{:error, _} -> {:error, "Invalid JSON response"}
end
{:ok, %Finch.Response{status: status}} ->
{:error, "HTTP #{status}"}
{:error, reason} ->
{:error, reason}
end
rescue
error ->
{:error, "Request exception: #{Exception.message(error)}"}
end
end