Title: IPinfo API call
Last modified: February 2, 2026

---

# IPinfo API call

 *  Resolved [Gerard Kanters](https://wordpress.org/support/users/gkanters/)
 * (@gkanters)
 * [4 months ago](https://wordpress.org/support/topic/ipinfo-api-call/)
 * Hi Ben, 
   Great work on this plugin. I do have an issue, otherwise I would not
   use the support ticket 🙂 I also taken the liberty to sugges a fix. But this 
   is just for your convenience.—## ProblemThe IPinfo module uses the `ipinfo/ipinfo`
   PHP library, which calls the **Legacy API** (`https://ipinfo.io/{ip}`) with a
   Bearer token. That Legacy endpoint has a **50,000 requests/month** limit for 
   the free tier. Once that quota is exceeded, almost all requests return **429 
   Quota Exceeded** (e.g. 99% in weekly IPinfo reports).IPinfo’s **free unlimited**
   tier is the **Lite API**: `https://api.ipinfo.io/lite/{ip}?token={token}`.– Lite
   API docs: [https://ipinfo.io/developers/lite-api](https://ipinfo.io/developers/lite-api)–
   Auth & URL structure: [https://ipinfo.io/developers](https://ipinfo.io/developers)–
   Free plan difference: [https://ipinfo.io/faq/article/134-what-is-the-difference-between-using-the-authenticated-free-plan-and-just-the-public-api-with-no-account](https://ipinfo.io/faq/article/134-what-is-the-difference-between-using-the-authenticated-free-plan-and-just-the-public-api-with-no-account)**
   Expected:** Use the Lite API so that authenticated free-tier tokens get unlimited
   requests and no 429s from quota.—## Suggested fixCall the Lite API directly with`
   wp_remote_get` (and optional persistent cache with transients) instead of the
   vendor that uses the Legacy URL.### Example implementation`php<br><br><em>/**
   </em><br><br><em> * Get geolocation via IPinfo Lite API (unlimited for free tier).
   </em><br><br><em> * Do NOT use Legacy (ipinfo.io) – 50k/month limit → 429.</em
   ><br><br><em> *</em><br><br><em> * @param string $ip    IP address to look up.
   </em><br><br><em> * @param string $token IPinfo access token.</em><br><br><em
   > * @return array|false Normalized location array or false.</em><br><br><em> */
   </em><br><br>public static function get_geolocation( $ip, $token ) {<br><br> 
   if ( empty( $token ) ) {<br><br>        return false;<br><br>    }<br><br>   
   <em>// Optional: persistent cache (e.g. transient) to reduce API calls.</em><
   br><br>    $cache_key = 'zerospam_ipinfo_' . md5( $ip );<br><br>    $cached  
   = get_transient( $cache_key );<br><br>    if ( false !== $cached ) {<br><br> 
   return $cached;<br><br>    }<br><br>    <em>// Correct: Lite API – unlimited 
   for free accounts.</em><br><br>    $url = 'https://api.ipinfo.io/lite/' . rawurlencode(
   $ip ) . '?token=' . rawurlencode( $token );<br><br>    $response = wp_remote_get(
   $url, array( 'timeout' => 5 ) );<br><br>    if ( is_wp_error( $response ) ) {
   <br><br>        return false;<br><br>    }<br><br>    $code = wp_remote_retrieve_response_code(
   $response );<br><br>    if ( 429 === (int) $code || 200 !== (int) $code ) {<br
   ><br>        return false;<br><br>    }<br><br>    $body = wp_remote_retrieve_body(
   $response );<br><br>    $data = json_decode( $body, true );<br><br>    if ( !
   is_array( $data ) || empty( $data&#091;'country_code'] ) ) {<br><br>        return
   false;<br><br>    }<br><br>    <em>// Normalize to existing log_record format:
   country = 2-letter code, etc.</em><br><br>    $result = array(<br><br>       '
   country' => $data&#091;'country_code'],<br><br>        'region'  => isset( $data&#
   091;'region'] ) ? $data&#091;'region'] : '',<br><br>        'city'    => isset(
   $data&#091;'city'] ) ? $data&#091;'city'] : '',<br><br>        'postal'  => isset(
   $data&#091;'postal'] ) ? $data&#091;'postal'] : '',<br><br>    );<br><br>    
   if ( ! empty( $data&#091;'loc'] ) ) {<br><br>        $loc = explode( ',', $data&#
   091;'loc'], 2 );<br><br>        if ( 2 === count( $loc ) ) {<br><br>         
   $result&#091;'latitude']  = trim( $loc&#091;0] );<br><br>            $result&#
   091;'longitude'] = trim( $loc&#091;1] );<br><br>        }<br><br>    }<br><br
   >    <em>// Cache e.g. 14 days.</em><br><br>    set_transient( $cache_key, $result,
   14 * DAY_IN_SECONDS );<br><br>    return $result;<br><br>}<br><br>`—## API URLs
   reference| Use case   | Correct (Lite – unlimited)                          |
   Incorrect (Legacy – 50k/month)        ||———–|——————————————————|—————————————-
   || Lookup IP | `https://api.ipinfo.io/lite/8.8.8.8?token=TOKEN`     | `https://
   ipinfo.io/8.8.8.8` (+ Bearer) || Auth      | `?token=TOKEN` in query string (
   or Bearer on Lite)   | Bearer header on Legacy                |—## References–[
   IPinfo Lite API]([https://ipinfo.io/developers/lite-api](https://ipinfo.io/developers/lite-api))–[
   IPinfo Developers – Authentication & URL structure]([https://ipinfo.io/developers](https://ipinfo.io/developers))–[
   Free plan vs public API]([https://ipinfo.io/faq/article/134-what-is-the-difference-between-using-the-authenticated-free-plan-and-just-the-public-api-with-no-account](https://ipinfo.io/faq/article/134-what-is-the-difference-between-using-the-authenticated-free-plan-and-just-the-public-api-with-no-account))

Viewing 1 replies (of 1 total)

 *  Plugin Author [Ben Marshall](https://wordpress.org/support/users/bmarshall511/)
 * (@bmarshall511)
 * [4 months ago](https://wordpress.org/support/topic/ipinfo-api-call/#post-18809709)
 * Thanks for the detailed report and for putting together a suggested implementation,
   super helpful.
 * You’re exactly right: the current integration uses IPinfo’s Legacy endpoint (
   ipinfo.io/{ip}), which is capped at 50,000 requests/month on the free tier and
   can lead to widespread 429 “Quota Exceeded” responses once that limit is hit.
 * We’ve updated the IPinfo module to use the Lite API endpoint instead (api.ipinfo.
   io/lite/{ip}?token=…), which is the unlimited option for authenticated free-tier
   tokens. We also added persistent caching to reduce API calls further, and removed
   the vendor dependency in favor of the native WordPress HTTP API.
 * This change will be included in v5.7.2.
 * Also, if you have a minute, we’d really appreciate a [quick review on WordPress.org](https://wordpress.org/support/plugin/zero-spam/reviews/#new-post),
   it helps a ton with visibility and lets other site owners know the plugin is 
   actively maintained.
 * Thanks again, we’re always here to help. Just reply if you have any questions.

Viewing 1 replies (of 1 total)

You must be [logged in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fwordpress.org%2Fsupport%2Ftopic%2Fipinfo-api-call%2F%3Foutput_format%3Dmd&locale=en_US)
to reply to this topic.

 * ![](https://ps.w.org/zero-spam/assets/icon.svg?rev=2343080)
 * [Zero Spam for WordPress](https://wordpress.org/plugins/zero-spam/)
 * [Frequently Asked Questions](https://wordpress.org/plugins/zero-spam/#faq)
 * [Support Threads](https://wordpress.org/support/plugin/zero-spam/)
 * [Active Topics](https://wordpress.org/support/plugin/zero-spam/active/)
 * [Unresolved Topics](https://wordpress.org/support/plugin/zero-spam/unresolved/)
 * [Reviews](https://wordpress.org/support/plugin/zero-spam/reviews/)

 * 1 reply
 * 2 participants
 * Last reply from: [Ben Marshall](https://wordpress.org/support/users/bmarshall511/)
 * Last activity: [4 months ago](https://wordpress.org/support/topic/ipinfo-api-call/#post-18809709)
 * Status: resolved