IPstack PHP Wrapper: Accurate IP Geolocation API Integration for Developers & Businesses

If you’ve used the package before, this release is a major quality step forward.
If you’re new to it, this is the right time to start.

The new sudiptpa/ipstack release modernizes the SDK with a cleaner architecture, stronger typing, better error handling, improved documentation, and practical production patterns for both plain PHP and Laravel-style integrations.

Table of Contents

  1. What’s New in This Release
  2. Why This Upgrade Matters
  3. Installation
  4. Quick Start (Framework-Agnostic PHP)
  5. Core Features and How to Use Them
  6. Advanced Usage Patterns
  7. Laravel Integration Example
  8. Error Handling Strategy
  9. Testing and Quality
  10. Migration Notes
  11. Open for Contributions
  12. Related Reading (SEO/Previous Blogs)
  13. Conclusion

1) What’s New in This Release

Here are the most important updates shipped in the latest modernized version:

  • New factory/client architecture
  • PSR-18 based transport layer
  • Typed models for ipstack responses
  • Bulk lookup support with edge-case safety
  • Better exception mapping (API + transport errors)
  • Expanded test coverage for real-world failure paths
  • PHP 8.3 to 8.5 support
  • Improved README with migration guide and advanced examples

This isn’t just a feature release. It’s a reliability release.

2) Why This Upgrade Matters

IP geolocation often starts as a minor utility but quickly becomes central to:

  • authentication risk signals
  • geo personalization
  • analytics enrichment
  • fraud and abuse detection

In those contexts, consistency matters more than convenience.
This release focuses on consistency: explicit construction, typed data, predictable errors, and testable boundaries.

3) Installation

composer require sudiptpa/ipstack

If you want the same PSR-18 adapter stack used in examples:

composer require symfony/http-client nyholm/psr7

4) Quick Start (Framework-Agnostic PHP)

<?php

declare(strict_types=1);

use Ipstack\Ipstack;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Component\HttpClient\Psr18Client;

$client = Ipstack::factory()
    ->withAccessKey($_ENV['IPSTACK_ACCESS_KEY'])
    ->withPsr18(new Psr18Client(), new Psr17Factory())
    ->build();

$result = $client->lookup('8.8.8.8');

echo $result->formatted(); // Mountain View, 94035, California, United States

5) Core Features and How to Use Them

Single IP Lookup

$result = $client->lookup('1.1.1.1');

echo $result->country->name;
echo $result->region->name;
echo $result->city;

Requester IP (/check)

$mine = $client->lookupRequester();
echo $mine->ip;

Bulk Lookup

$collection = $client->lookupBulk(['8.8.8.8', '1.1.1.1']);

foreach ($collection as $row) {
    echo $row->ip . ' => ' . $row->formatted() . PHP_EOL;
}

Query Options

use Ipstack\Client\Options;

$options = Options::create()
    ->fields(['ip', 'country_name', 'region_name', 'city'])
    ->language('en')
    ->security(true)
    ->hostname(true);

$result = $client->lookup('8.8.8.8', $options);

6) Advanced Usage Patterns

A) Use a Custom Transport (great for testing/offline dev)

use Ipstack\Transport\TransportInterface;

final class DemoTransport implements TransportInterface
{
    public function get(string $url, array $query): array
    {
        return [
            'ip' => '8.8.8.8',
            'country_name' => 'United States',
            'region_name' => 'California',
            'city' => 'Mountain View',
            'zip' => '94035',
        ];
    }
}

Then inject:

$client = Ipstack::factory()
    ->withAccessKey('DUMMY')
    ->withTransport(new DemoTransport())
    ->build();

B) Build robust error handling

Catch by exception type, not message string:

use Ipstack\Exception\RateLimitException;
use Ipstack\Exception\TransportException;
use Ipstack\Exception\InvalidResponseException;
use Ipstack\Exception\IpstackException;

try {
    $result = $client->lookup($ip);
} catch (RateLimitException $e) {
    // quota policy
} catch (TransportException|InvalidResponseException $e) {
    // network/upstream policy
} catch (IpstackException $e) {
    // fallback domain policy
}

C) Keep raw payload for audit/debug

$raw = $result->raw();
$asJson = json_encode($result); // JsonSerializable raw payload

7) Laravel Integration Example

Even though the package is framework-agnostic, it fits Laravel very naturally.

Service Provider Binding

use Ipstack\Ipstack;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Component\HttpClient\Psr18Client;

$this->app->singleton(\Ipstack\Client\IpstackClient::class, function () {
    return Ipstack::factory()
        ->withAccessKey(config('services.ipstack.key'))
        ->withPsr18(new Psr18Client(), new Psr17Factory())
        ->build();
});

Usage in Controller/Service

public function show(Request $request, \Ipstack\Client\IpstackClient $ipstack)
{
    $geo = $ipstack->lookup($request->ip());

    return response()->json([
        'ip' => $geo->ip,
        'country' => $geo->country->name,
        'region' => $geo->region->name,
        'city' => $geo->city,
    ]);
}

Middleware pattern (recommended)

  • resolve client once
  • lookup requester IP once
  • attach context to request attributes
  • consume context in downstream handlers

This avoids duplicate lookups and keeps geo context consistent per request.

8) Error Handling Strategy

This release maps known ipstack API errors to dedicated exceptions:

  • RateLimitException (104)
  • InvalidFieldsException (301)
  • TooManyIpsException (302)
  • BatchNotSupportedException (303)
  • plus transport/response exceptions

This is useful for real policy behavior:

  • retry only where appropriate
  • fail fast on invalid caller parameters
  • monitor rate limits separately from transport instability

9) Testing and Quality

The package now includes stronger coverage around:

  • requester lookup behavior
  • bulk edge cases and limits
  • factory misconfiguration
  • PSR-18 transport failure modes

Quality pipeline includes:

  • PHPUnit
  • PHPStan
  • CI matrix across PHP 8.3 / 8.4 / 8.5

10) Migration Notes

If you used older versions:

  • move from constructor-style direct calls to factory-built client
  • replace legacy convenience method patterns with:
    • lookup()
    • lookupRequester()
    • lookupBulk()
  • consume typed model fields instead of manual payload array parsing

The README migration table gives direct old->new mapping.

11) Open for Contributions

Contributions are welcome and appreciated.

Good contribution areas:

  • transport adapters/examples
  • additional integration examples (Symfony, Laravel, Slim, etc.)
  • test coverage improvements for edge payload variants
  • docs improvements and migration tips from real projects

If you open a PR, include tests and update docs where behavior changes.

12) Conclusion

This release is focused on real-world reliability, not just syntactic modernization.

You now get a cleaner architecture, typed outputs, better error semantics, stronger tests, and clearer integration patterns for both plain PHP and Laravel-style projects. If you’re using IP intelligence in auth, personalization, or analytics, this release reduces risk and improves maintainability immediately.

Thanks for reading.
If you’re using the package in production, feedback and PRs are welcome.

Also Read: V1:: A Simple IP to Geo Location solution for PHP