Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Kraken Php Laravel Package

kraken-io/kraken-php

PHP client for the Kraken.io image optimization API, offering lossy and lossless compression, resizing, cropping, and format conversion for JPEG, PNG, GIF, and WebP images via file upload or URL, with asynchronous callback support.

Deep Wiki
Context7

Getting Started

Install

composer require kraken-io/kraken-php

There is no service provider or facade shipped with the package—it is a thin, framework-agnostic SDK. You wire it into Laravel manually.

Credentials first

Add to .env:

KRAKEN_API_KEY=
KRAKEN_API_SECRET=

Register in config/services.php:

'kraken' => [
    'api_key'    => env('KRAKEN_API_KEY'),
    'api_secret' => env('KRAKEN_API_SECRET'),
],

Bind a singleton in AppServiceProvider::register() (or use a dedicated KrakenService wrapper, see below):

$this->app->singleton(\Kraken\Client::class, fn () => new \Kraken\Client([
    'auth' => [
        'api_key'    => config('services.kraken.api_key'),
        'api_secret' => config('services.kraken.api_secret'),
    ],
]));

First use case: optimize an uploaded image

The most common day-one task is shrinking user uploads before you store them.

use Kraken\Client;

public function store(Request $request, Client $kraken)
{
    $path = $request->file('image')->store('tmp', 'local');

    $result = $kraken->upload([
        'file'  => Storage::disk('local')->path($path),
        'wait'  => true,
        'lossy' => true,
    ]);

    // $result['kraked_url'] is the optimized image; download & store it
    $bytes = file_get_contents($result['kraked_url']);
    Storage::disk('public')->put('images/photo.jpg', $bytes);

    return redirect()->back();
}

Where to look next in the source (src/Kraken/): Client.php for the upload() / url() / user() methods, and the request class for the option payload. Everything you can pass is a snake_case key straight from the Kraken.io HTTP API docs—the PHP package does almost no transformation.

Implementation Patterns

Wrap it in a service, don't call Client from controllers

namespace App\Services;

use Kraken\Client;
use Illuminate\Support\Facades\Storage;

class ImageOptimizer
{
    public function __construct(private Client $kraken) {}

    public function optimize(string $diskPath, string $disk = 'public'): array
    {
        $result = $this->kraken->upload([
            'file'         => Storage::disk($disk)->path($diskPath),
            'wait'         => true,
            'lossy'        => true,
            'quality'      => 82,
            'auto_orient'  => true,
            'preserve_meta'=> ['copyright'],
            'resize'       => ['width' => 2000, 'height' => 2000, 'strategy' => 'auto'],
        ]);

        return $result;
    }
}

Always run it on a queue

wait => true blocks for the duration of the optimization. For anything user-facing, dispatch a job:

class OptimizeImage implements ShouldQueue
{
    public int $tries = 3;
    public int $backoff = 30;

    public function __construct(public string $path) {}

    public function handle(ImageOptimizer $optimizer)
    {
        $optimizer->optimize($this->path);
        ImageOptimized::dispatch($this->path);
    }
}

Async via callback for batch / large jobs

$kraken->upload([
    'file'         => $absolutePath,
    'wait'         => false,
    'callback_url' => route('webhooks.kraken'),   // must be publicly reachable
    'lossy'        => true,
]);

The response contains an id. Persist it against your model so the webhook handler can correlate:

Route::post('/webhooks/kraken', KrakenWebhookController::class)
    ->withoutMiddleware(['web']);

Kraken POSTs the full result (including kraked_url) back to you; store the bytes and mark the record as processed.

Source URLs beat temp files when the image is already public

If the asset sits on S3 with a public URL, use url() instead of upload(). It avoids downloading the file locally and avoids needing the file to exist on your web server:

$kraken->url(['url' => $publicUrl, 'wait' => true, 'lossy' => true]);

Push straight to storage (skip the round-trip)

The API supports s3_store, azure_store, gcs_store, rclone_store, and kraken_store options. If you already have S3 credentials configured, let Kraken write directly to your bucket instead of downloading kraked_url back through your app—much cheaper for large batches.

Convert to modern formats in the same call

Use convert (e.g. ['format' => 'webp']) rather than the legacy webp flag; it's the current API surface and composes with resize.

Monitor your quota

$kraken->user()->balance() returns your plan quota. Surface it on an internal admin dashboard or log it nightly—Kraken returns errors once you exceed the plan, and you don't want to discover that in production.

Gotchas and Tips

Laravel's Http::fake() will NOT intercept this package. It uses Guzzle directly rather than Laravel's HTTP client, so fakes silently miss and your tests hit the real API. Mock Kraken\Client (or your ImageOptimizer wrapper) in the container instead:

$this->mock(ImageOptimizer::class, fn ($m) => $m->shouldReceive('optimize')
    ->andReturn(['kraked_url' => 'https://example.test/x.jpg']));

The package does not modify your local file. Optimization happens server-side; you get a kraked_url (or a stored object) back. You must download and persist it yourself unless you use an external store option. The original file on disk is untouched.

upload() needs a local filesystem path, not a Laravel UploadedFile or an S3 key. Use $file->getRealPath() or Storage::path(); for S3-only files, either presign a URL and use url(), or pull to a temp path first.

Callbacks need a public, CSRF-exempt route. Any route in routes/web.php will 419 from Kraken's POST. Register it in routes/api.php or explicitly strip the web middleware group. Make the handler idempotent—Kraken may retry—and key off the returned id.

Synchronous calls can time out for big images. Large PNGs at high quality can take tens of seconds. If you must call synchronously, bump max_execution_time or (better) move it to a job. The default queue worker timeout of 60s is often enough, but set $timeout explicitly on the job.

Options are snake_case and passed verbatim. A typo like callbackUrl or autoOrient is not validated client-side—the API silently ignores unknown keys and you get a confusingly unoptimized result. When debugging, dump the exact array you're sending before the call.

quality only meaningfully applies with lossy => true. The defaults are sane; don't start at quality => 100 thinking you'll get lossless—you'll get slow requests and near-original sizes.

preserve_meta is opt-in per field. If you need EXIF orientation preserved for camera photos, set auto_orient => true. If you need copyright/geotag data, list it in preserve_meta—otherwise all metadata is stripped, which is usually what you want for web images.

Read the error, don't swallow it. Failed calls throw an exception (from Kraken\Exception); catch it at the job level and decide between retry and dead-lettering. Auth failures (401/403) are not retryable—bad keys or exhausted quota. Timeouts and 5xx are retryable.

Config caching will bite you. After adding services.kraken, run php artisan config:clear in local and config:cache in production. env() inside a cached config returns null, so always go through config('services.kraken.*'), never env() directly in code.

No first-party Laravel integration means no events, no rate limiter, no HTTP client instrumentation. If you need retry/backoff on transient failures, implement it on the job ($tries/$backoff) or wrap the client in a decorator—you won't get it from the package.

Version pinning matters. The library changes infrequently (last release Sept 2024), but a composer update can still move API expectations. Pin to a minor range (^1.x) and rely on your wrapper's tests to catch payload changes.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core