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

Remove Bg Laravel Package

mtownsend/remove-bg

Remove backgrounds from images in PHP and Laravel with a simple wrapper around the remove.bg API. Pass a file path, URL, or binary image and get a transparent PNG back in one call, with clean error handling for size limits and failed requests.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require mtownsend/remove-bg

Laravel 5.5+ auto-discovers Mtownsend\RemoveBg\RemoveBgServiceProvider and registers the RemoveBg facade alias. On older/non-Laravel setups add the provider and alias manually in config/app.php.

Configure credentials

php artisan vendor:publish --provider="Mtownsend\RemoveBg\RemoveBgServiceProvider" --tag="config"

Set REMOVE_BG_API_KEY in .env. The key is the only hard requirement; everything else has sane defaults. Create a key at https://www.remove.bg/api and note that calls are billed against your account's credits.

Where to look first

  1. config/removebg.php — the published config; confirms the env var name and any default size/format settings.
  2. src/RemoveBg.php — the single class that matters; read file(), url(), base64(), save(), getContents(), getBase64() to learn the fluent surface.
  3. src/Exceptions/ — every failure mode (InvalidApiKey, InvalidImage, etc.) is a concrete exception class; these are what you catch.
  4. The upstream remove.bg API docs — many parameters (type=car, channels, crop, shadow) may not be exposed by this wrapper and you'll need to reason about whether they're passable.

First use case

Background removal on a user-uploaded profile photo, saved to storage:

use Mtownsend\RemoveBg\RemoveBg;

$contents = RemoveBg::file($request->file('avatar')->getRealPath())
    ->getContents();

Storage::disk('public')->put("avatars/{$id}.png", $contents);

That is the 90% use case. Everything else is variations on "get bytes out, put bytes somewhere."

Implementation Patterns

Source ingestion — three entry points

The package mirrors remove.bg's three inputs:

  • RemoveBg::file($path) — local path or an UploadedFile/SplFileInfo. Pass $request->file('photo') directly rather than calling getRealPath(); the wrapper handles Illuminate\Http\UploadedFile.
  • RemoveBg::url($url) — remove.bg fetches the image server-side. Only works for publicly reachable URLs; do not hand it signed S3 URLs with tiny TTLs or localhost addresses.
  • RemoveBg::base64($data) — raw base64 string, without the data:image/png;base64, prefix. Strip it before passing.

Output — three sinks

  • ->getContents() — raw binary. The most portable; pipe into Storage::put(), response()->stream(), or file_put_contents().
  • ->getBase64() — encoded string for JSON responses or <img src="data:..."> embedding.
  • ->save($path) — writes the result to disk in one call. Convenient for local dev; prefer getContents() + Storage in production so you control the disk, visibility, and path prefix.

Controller pattern — synchronous

Fine for a single-image, admin-triggered operation or a prototype:

public function store(Request $request)
{
    $request->validate(['photo' => 'required|image|max:12000']);

    try {
        $bytes = RemoveBg::file($request->file('photo'))->getContents();
    } catch (\Mtownsend\RemoveBg\Exceptions\RemoveBgException $e) {
        report($e);
        return back()->withErrors('Background removal failed, try again.');
    }

    $path = "processed/".Str::uuid().".png";
    Storage::disk('s3')->put($path, $bytes);

    return response()->json(['path' => $path]);
}

Job pattern — asynchronous

remove.bg latency is typically 2–8 seconds; never block a web request on it in production. Wrap the call in a queued job:

class RemoveImageBackground implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $backoff = 30;

    public function __construct(public int $imageId) {}

    public function handle(): void
    {
        $image = Image::findOrFail($this->imageId);

        try {
            $bytes = RemoveBg::file(Storage::disk('local')->path($image->original_path))
                ->getContents();

            Storage::disk('s3')->put($image->clean_path, $bytes);
            $image->update(['status' => 'clean']);
        } catch (RemoveBgException $e) {
            // Don't retry 402 (out of credits) or 400 (bad input)
            if (in_array($e->getCode(), [400, 402])) {
                $image->update(['status' => 'failed']);
                return;
            }
            throw $e; // 5xx and network errors are worth retrying
        }
    }
}

The nuance: this package surfaces the upstream HTTP status in the exception code, so branch on getCode() to distinguish "retry" (5xx, timeouts) from "don't bother" (client errors, credit exhaustion).

Chaining / options

Where the wrapper exposes optional parameters it will be fluent:

RemoveBg::file($path)
    ->size('preview')   // 'preview' | 'full' | 'auto'
    ->save($dst);

Check the README for the exact supported set — the wrapper's surface is a subset of remove.bg's API, and features added upstream after the last release won't be there (see Gotchas).

Testing

Never call the real API in tests — you'll burn credits and slow CI. Either fake the facade or swap the boundary:

RemoveBg::shouldReceive('file')
    ->once()
    ->andReturnSelf();
RemoveBg::shouldReceive('getContents')
    ->once()
    ->andReturn(file_get_contents(base_path('tests/fixtures/clean.png')));

The fixture-based approach is preferable: it forces you to keep the file() → getContents() boundary narrow in production code, which makes it trivially mockable.

Integration tips

  • Cache the result. Background removal is deterministic for a given input + parameters; store the output keyed by a hash of the source so re-processing is a no-op.
  • Store the original and the clean image; users will want to revert.
  • For multi-image flows (gallery uploads), batch jobs with a concurrency limit — remove.bg rate-limits per-key, and hammering it from 20 workers in parallel will trigger 429s.

Gotchas and Tips

Package health is the biggest gotcha. Last release was 2023-06-08, zero dependents, low overall score. The wrapper is thin, so the risk is not "it will break tomorrow" but "new remove.bg API parameters won't be surfaced." If you need type=car, channels=rgba, bg_color, or add_shadow, verify the fluent methods actually exist in src/RemoveBg.php before architecting around them — otherwise you'll be subclassing or forking. Since it's MIT and one class, a local fork or a thin hand-rolled Guzzle client are equally viable if the API surface is insufficient.

Every successful call costs a credit. The remove.bg API is credit-based, with the free tier limited to preview size (roughly 625×400). If you need full-resolution output you must be on a paid plan and request size=full — a "free" preview that looks fine in dev can be silently upscaled garbage in prod. Add a hard alert on 402 responses; running out of credits mid-deploy is a classic outage.

Input constraints are enforced upstream, not by the package. remove.bg caps at ~12 MB and ~25 megapixels. Validate with Laravel's max:12000 (KB) rule and check dimensions, otherwise you'll pay for the round trip just to get a 400 back.

Base64 prefix will break you. removebg's base64 input expects a bare string. Passing a full data URI yields a 400 that reads like a generic "invalid image." Strip with Str::after($data, ',') defensively.

Exceptions are your only error signal. The wrapper throws rather than returning nulls, but the exception classes and codes are the upstream ones. Log $e->getCode() and $e->getMessage() — they carry the remove.bg reason text (insufficient_credits, unknown_foreground, etc.), which is far more useful than the class name.

Timeouts default to whatever Guzzle uses (usually none/infinite). If you don't wrap the call in a queue with a timeout, a hung remove.bg request can tie up a PHP-FPM worker. Set timeout in the config if the package exposes it, or wrap the whole job in a try { ... } finally with set_time_limit().

save() semantics vary with your filesystem. If you pass a relative path it resolves relative to the PHP working directory, not storage_path(). Use absolute paths or Storage::path(). In practice, prefer getContents() + Storage and avoid save() entirely in app code — it keeps the package out of your storage abstraction.

Facade alias collisions. The alias RemoveBg is generic. In a large app with another vendor package or your own class named similarly, you'll get a silent resolution to the wrong class. Register your own alias or inject Mtownsend\RemoveBg\RemoveBg via constructor rather than relying on the global facade.

API key handling. The key lives in config, which is cached. If you rotate keys, you must run php artisan config:cache again — a stale cached key produces 401s that look like a permissions issue. Also: don't log the key, and be aware remove.bg processes your images on their servers — for user-submitted or sensitive imagery, disclose this in your privacy policy and make sure it's in your data processing agreement.

Debugging recipe. When a call fails opaquely: (1) dd($e->getCode(), $e->getMessage()); (2) hit remove.bg's /api/v1/account endpoint with the same key to confirm credits are non-zero; (3) try the same file via curl -F image_file=@... against the raw API — if that succeeds and the wrapper fails, it's a payload/multipart issue in the wrapper, and you're now justified in forking or bypassing it.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource