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

Instagram Laravel Package

cosenary/instagram

A Laravel wrapper for the Instagram API that makes it easy to authenticate users and work with media, comments, likes, and profile data through a clean, expressive PHP interface.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and orient yourself in one file

composer require cosenary/instagram

Expect a surprise on the namespace: the package is cosenary/instagram, but the class is MetzWeb\Instagram\Instagram. The whole library is effectively one file — src/Instagram/Instagram.php, with InstagramException.php alongside it. Open that file first. There is no service provider, no config publishing, no facade, no facade accessor, and no tests. The repo's examples/ directory is the real documentation, and its OAuth round-trip example is the fastest way to understand the intended flow.

Minimal Laravel wiring

// config/services.php
'instagram' => [
    'apiKey'      => env('INSTAGRAM_KEY'),
    'apiSecret'   => env('INSTAGRAM_SECRET'),
    'apiCallback' => env('INSTAGRAM_CALLBACK'), // must match Meta app config exactly
],
use MetzWeb\Instagram\Instagram;

$instagram = new Instagram([
    'apiKey'      => config('services.instagram.apiKey'),
    'apiSecret'   => config('services.instagram.apiSecret'),
    'apiCallback' => config('services.instagram.apiCallback'),
]);

First use case: OAuth login → fetch the user's media

  1. Redirect the user to $instagram->getLoginUrl(['basic']).
  2. In the callback route, exchange ?code= via $data = $instagram->getOAuthToken($request->code);.
  3. Persist $data->access_token (and $data->user) against your Eloquent user.
  4. On later requests, $instagram->setAccessToken($token); then $instagram->getUserMedia().

That four-step flow — login, token exchange, token storage, media fetch — is 90% of what anyone actually does with this package. Get it working end-to-end against a sandbox or a mock before you refactor anything.

A word on reality before you build further. This package targets Instagram's retired Platform API. The legacy endpoints it calls no longer answer for new integrations, so "getting started" against live Instagram means Meta's Graph API, not this wrapper. The practical onboarding path is: read this class as a compact reference implementation of the OAuth authorization-code exchange, pagination, and cURL error handling, then point your actual feature work at the Graph API. Everything below assumes you are maintaining or wrapping legacy code, running a spike, or pointing the class at a controlled proxy/mock.

Implementation Patterns

Bind it, but don't trust the singleton with a token. The client is stateful after setAccessToken(). A singleton is fine for construction and config, but you MUST resolve a fresh instance (or at least re-set the token) per user request:

$this->app->singleton('instagram.factory', fn () => new Instagram([
    'apiKey'      => config('services.instagram.apiKey'),
    'apiSecret'   => config('services.instagram.apiSecret'),
    'apiCallback' => config('services.instagram.apiCallback'),
]));

class InstagramClient
{
    public function forToken(string $token): Instagram
    {
        $client = app('instagram.factory');
        $client->setAccessToken($token);
        return $client;
    }
}

Wrap behind an interface; never inject the class directly. Define an application-owned InstagramGateway in your domain layer, implement it with a LegacyInstagramAdapter that owns the MetzWeb\Instagram\Instagram instance, and bind the interface in a service provider. This is the highest-leverage decision you will make: it converts an unmaintainable dependency into a replaceable one, lets you swap in a Graph API client later, and makes every caller mock-friendly.

Controllers stay thin; the adapter owns token lifecycle.

public function redirect(InstagramGateway $ig)
{
    return redirect($ig->loginUrl(['basic']));
}

public function callback(Request $request, InstagramGateway $ig, User $user)
{
    $token = $ig->exchangeCode($request->string('code'));
    $user->instagramTokens()->updateOrCreate([], [
        'access_token' => $token->access_token,
        'user_id'      => $token->user->id,
        'expires_at'   => now()->addSeconds(3600), // legacy tokens: ~1h
    ]);
    return redirect()->route('instagram.feed');
}

Queue any read that feeds a page. The class makes one blocking cURL call per invocation — no pooling, no batching. Feed pages, gallery widgets, and profile cards should enqueue a refresh job and render from cache. Caching reads is not an optimization here; it is a correctness requirement for keeping page latency sane.

Paginate deliberately. The API returns pagination->next_url (or a cursor); the client surfaces it in the decoded response. Store it, cap count, and guard against loops with a max-page counter — the legacy API occasionally returned the same cursor on empty pages.

Use PHPUnit with recorded fixtures. Since the class has a settable base endpoint in its config array (apiEndpoint/apiBase), point it at a local mock server that replays recorded legacy JSON. This pins the adapter's contract so your eventual Graph API swap is a contained diff, not a rewrite.

Feature-flag the swap. Implement a GraphInstagramGateway alongside the legacy one behind config('features.instagram_graph'). Run both in shadow mode against test accounts, diff responses, then flip traffic. Decommission the legacy path by deleting it from composer.json when traffic is zero.

Gotchas and Tips

The API is dead — validate before you commit. The package targets api.instagram.com v1 endpoints retired by Meta. The replacement Basic Display API was itself deprecated in December 2024; the Graph API (Business/Creator accounts, Facebook Login for Business) is the only live surface. Do not schedule feature work against this client. Use it as a reference implementation or an isolated adapter with a hard sunset date.

Namespace vs. package name. composer require cosenary/instagram installs MetzWeb\Instagram\Instagram. Autocomplete, IDE imports, and grep will all lie to you if you search for cosenary.

PHP 8.x deprecation noise. This is PHP 5-era code. Expect dynamic property deprecations, stale cURL option handling (removed constants like CURLOPT_SAFE_UPLOAD), and permissive constraints (>=5.3). It will probably install on Laravel 10/11 but will pollute logs. Wrap calls and set a PHP error handler scoped to the adapter if needed.

Token handling is naive. setAccessToken() stores the token on the instance; there is no refresh, no long-lived token exchange, and no secret management story. Treat tokens as sensitive: store encrypted, never in session, and build refresh logic yourself (or leave it to the Graph API migration).

Concurrency bug you will hit. Using one shared Instagram instance across a request that touches two users' tokens will silently mix them. Always resolve per-token via the wrapper above.

Silent 400s and opaque errors. Expired/revoked tokens return 400s; dead endpoints return unhelpful messages; HTTP 429 has no retry. Wrap every call in try/catch (InstagramException $e) with structured logging, and add a circuit breaker so a dead Instagram does not 500 adjacent request paths.

No rate limiting or backoff. You must add exponential backoff, jitter, and queueing yourself. There is nothing in this class you can tune.

Fork, don't wait. BSD-3-Clause permits forking. There is no upstream maintainer, no security patching, and zero Packagist dependents to share the burden. If you must keep it alive, pin the version, own the fork, and put an explicit retirement date in the sprint plan. The correct posture is containment this quarter, removal next — not evaluation as a strategic option.

Extension points are thin. The constructor config array is the only real seam (base endpoint, credentials, callback). Everything else — auth, HTTP, error shape — is baked into the class. Plan migrations around the adapter interface, not around subclassing.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource