glooby/pexels
A Laravel wrapper for the Pexels API that lets you search and retrieve photos and videos with a simple, fluent syntax. Easily pull curated imagery into your app for galleries, backgrounds, or media libraries using your Pexels API key.
Install and configure
composer require glooby/pexels
Add your key (get one at https://www.pexels.com/api/) to .env:
PEXELS_API_KEY=your-key-here
Publish the config if the package ships one:
php artisan vendor:publish --provider="Glooby\Pexels\PexelsServiceProvider"
If you're on Laravel < 5.5 (or auto-discovery is disabled), register the provider and facade manually in config/app.php. Verify the exact class names in the package's composer.json extra.laravel block or its service provider — the repo is unmaintained, so don't assume the README matches the code.
Where to look first
src/ — the client class and any facade. The package is a thin wrapper over the Pexels v1 REST API, so methods map almost 1:1 to endpoints: search, curated, popular, plus photo($id) / video($id).config('pexels.api_key') or PEXELS_API_KEY directly.src/.First use case: a search in Tinker
php artisan tinker
>>> Pexels::search('office workspace', 10, 1);
If that returns an array of photo payloads, you're wired up. From there the natural first feature is a "pick a stock image" field in your admin.
Inject the client, don't call the facade everywhere
Facades are fine for prototypes, but bind a small repository so you can swap/mock it:
namespace App\Services;
use Glooby\Pexels\Pexels; // confirm the real class name in src/
class StockPhotoService
{
public function __construct(private Pexels $pexels) {}
public function search(string $term, int $perPage = 20, int $page = 1): array
{
return $this->pexels->search($term, $perPage, $page);
}
}
$this->app->bind(Pexels::class, fn () => new Pexels(config('pexels.api_key'))); in a service provider makes this testable.
Cache aggressively — the free tier is 200 req/hour, 20k/month
Search results change slowly. Cache by normalized query + page:
public function search(string $term, int $perPage = 20, int $page = 1): array
{
$key = 'pexels:search:' . md5("{$term}|{$perPage}|{$page}");
return Cache::remember($key, now()->addHours(12), function () use ($term, $perPage, $page) {
return $this->pexels->search($term, $perPage, $page);
});
}
Build a media picker, not a bulk mirror
Typical day-to-day pattern: an admin page that searches Pexels, shows a grid, and on select downloads the chosen size to your disk and stores the path + attribution on the model.
public function import(string $photoUrl, string $filename): string
{
$contents = Http::timeout(15)->get($photoUrl)->throw()->body();
Storage::disk('public')->put("stock/{$filename}", $contents);
return "stock/{$filename}";
}
When selecting from the payload, prefer the ready-made variants (src->large, src->medium, src->tiny) over original — original is often 5–10 MB and will murder your page weight.
Pagination
Pexels uses page + per_page (max 80, default 15). Return page back to the UI and expose "load more" rather than trying to compute a total — the API returns next_page, not a reliable total count.
Queued ingestion
If you're seeding a demo catalogue, do the calls in a job with ->onQueue('media') and a rate limiter. Don't fan out 50 parallel requests from a synchronous request — you'll trip 429 and the package has no built-in backoff.
Testing
Mock at your own service boundary, not the package, and when you must test against the client, bind a fake:
$this->mock(StockPhotoService::class, fn ($m) => $m->shouldReceive('search')->andReturn([...]));
Use Http::fake() only if you're calling the Pexels endpoints directly; this package goes through its own HTTP layer.
retry(3, 250) or a Laravel RateLimiter, and handle 404s for deleted photos explicitly.photographer, photographer_url, and url alongside the file and render a credit line. It's good practice and required by the API terms in many contexts; it also saves you a painful retroactive cleanup.src->large (~940px) for cards, src->medium (~350px) for thumbs, original only for full-bleed hero downloads. The API gives you all variants; don't generate thumbnails yourself unless you need a specific crop.env() inside the package's service provider, php artisan config:cache will break it — the package was written before that was universally flagged. Move the key into config/pexels.php with env('PEXELS_API_KEY') there, and reference config() everywhere else.array all the way down; no typed objects, no IDE autocomplete. Define your own DTO/Data class (or a Spatie DataTransferObject) at the boundary so the rest of your app isn't coupled to untyped nested arrays.video_files at different resolutions and video_pictures for thumbnails. Pick by width/height rather than index — the ordering isn't guaranteed stable.StockPhotoProvider) and either delegate to this package or swap in a direct HTTP implementation later without touching call sites.grep -r "function " vendor/glooby/pexels/src/ to confirm method names, argument order, and whether it returns the raw Pexels envelope or just the photos array — the two differ and the README may be wrong.How can I help you explore Laravel packages today?