Prerequisites
- Ruby 3.0+ with
ip-api-ioinstalled - A free ip-api.io API key
Rescue typed exceptions
Every typed error inherits from Ipapi::Error and carries #status_code, #message and #body. Rescue the specific class you care about.
begin
info = client.lookup_ip("8.8.8.8")
puts info.ip
rescue Ipapi::RateLimitError => e
puts "quota hit — resets at #{e.reset}"
rescue Ipapi::AuthenticationError
puts "check your API key"
rescue Ipapi::InvalidRequestError => e
puts "bad request: #{e.message}"
rescue Ipapi::ServerError
puts "ip-api.io is having trouble, try later"
rescue Ipapi::Error => e
puts "transport / decode error: #{e.message}"
end Ipapi::Error — they are caught by the final rescue above.
Handle rate limits with RateLimitError
On HTTP 429 you get Ipapi::RateLimitError, carrying the x-ratelimit-* header values (-1 when a header is absent). Because the client never retries, #reset tells you when to.
rescue Ipapi::RateLimitError => e
puts e.limit # your quota for the window
puts e.remaining # requests left (0 here)
puts e.reset # unix timestamp when quota renews
# schedule a retry at e.reset instead of hammering the API Check quota proactively with rate_limit
Read your current limits without triggering a 429, so you can throttle in advance.
rl = client.rate_limit
puts rl.plan_name
puts "#{rl.ip_api.remaining} / #{rl.ip_api.limit}"
puts "#{rl.email_api.usage_percent}% used" Account usage with usage_summary
Aggregate usage for the current period — handy for dashboards and internal alerts.
usage = client.usage_summary
puts "#{usage.total_requests} #{usage.successful_requests}"
puts "#{usage.rate_limited_requests} #{usage.quota_consumed}"
puts "#{usage.period_start} #{usage.period_end}"