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 Bundle Laravel Package

hautelook/instagram-bundle

Hautelook Instagram Bundle is a Symfony bundle that integrates Instagram API access into PHP applications. It provides configuration, service definitions, and helpers for retrieving Instagram media and user data, making it easier to add Instagram feeds and API-driven features to Symfony projects.

View on GitHub
Deep Wiki
Context7

Getting Started

What the package actually is: a thin Symfony DI wrapper around an Instagram API client (historically cosenary/Instagram-PHP-API, Instagram\Instagram). Almost all real work — login URLs, token exchange, endpoint calls — happens in the underlying client; the bundle just registers it as a service and feeds it config. That framing should drive how you read the code.

Minimal setup (Symfony 2/3 era):

composer require hautelook/instagram-bundle
// app/AppKernel.php
new Hautelook\InstagramBundle\HautelookInstagramBundle(),
# app/config/config.yml
hautelook_instagram:
    client_id:     "%instagram_client_id%"
    client_secret: "%instagram_client_secret%"
    redirect_uri:  "%instagram_redirect_uri%"

Where to look first, in order:

  1. DependencyInjection/Configuration.php — the authoritative list of config keys and defaults.
  2. Resources/config/services.xml — the exact service ID (commonly hautelook_instagram.client; verify against your installed tag, don't trust the README).
  3. README.md — usage snippets.
  4. The vendored client (vendor/cosenary/... or whatever composer.json pulls) — the actual method names (getLoginUrl, getOAuthToken, setAccessToken, getUser, getUserMedia) and exception types live here.

First use case — the OAuth handshake + one read:

// ConnectController::redirectAction
$instagram = $this->get('hautelook_instagram.client');
return $this->redirect($instagram->getLoginUrl());

// ConnectController::callbackAction
$instagram = $this->get('hautelook_instagram.client');
$token = $instagram->getOAuthToken($request->query->get('code'));
$instagram->setAccessToken($token);

$user  = $instagram->getUser();          // /users/self
$media = $instagram->getUserMedia();     // /users/self/media/recent

// Persist $token against your user before the request ends.

Persist the token in your own entity/table — the bundle does not manage token storage for you.

Implementation Patterns

Thin-wrapper discipline. Treat the bundle service as a stateful HTTP client, not a repository. Inject it, configure the token, make one or two calls, and let it go. Avoid stashing the service on a long-lived singleton with a hardcoded token.

Two auth models, two code paths.

  • Single-account feed (your brand's photos on your site): run the OAuth flow once, store the token in parameters/DB, and have a cron/console command refresh cached media. No per-user login needed.
  • Per-user login: store access_token + instagram_user_id on your User entity, set it on the client inside a request-scoped service or a controller helper, and re-run the handshake when it's missing. If you already use HWIOAuthBundle, wire the token into your user provider instead of duplicating the redirect/callback controllers.

Service wiring. Give the bundle service an alias so you depend on an interface-ish name, not the vendor ID:

services:
    app.instagram:
        alias: hautelook_instagram.client

Then constructor-inject app.instagram into controllers/commands. Makes swapping in a fake in tests trivial.

Caching is mandatory, not optional. Media feeds are read-heavy and rate-limited (5,000 calls/hour per token historically). Wrap getUserMedia() in a Symfony cache pool with a 10–30 minute TTL (or a DB table updated by cron). Serve your own pages from cache; never call the API in a page render.

Console command for sync. A app:instagram:sync command that pulls recent media into a local table is the cleanest integration: it decouples the Instagram rate limit and latency from user-facing requests, and lets you re-run after failures. Schedule it with cron.

$instagram->setAccessToken($this->token);
foreach ($this->paginate($instagram, 50) as $item) { $this->store($item); }

Pagination on this client is cursor-based (next_max_id / max_id in the response), so loop until the response has no next_url/next_max_id — don't assume one page.

Testing. Register a stub in config_test.yml under the same alias that returns canned JSON. The bundle's client makes real HTTP calls in its constructor path, so unit tests must never touch the live service.

Config hygiene. Keep client_id/client_secret in parameters or a secrets file, never in the committed config.yml. The bundle has no secrets-vault integration (pre-dates it), so it's on you.

Gotchas and Tips

The elephant: this targets the retired Instagram API v1. Instagram shut down the legacy platform (the one this bundle speaks) in 2020 in favor of the Basic Display API / Graph API. On a current project, the bundle will authenticate against endpoints that no longer exist. Before adopting, confirm which API version the vendored client hits; if it's /v1/, plan a replacement (Basic Display API via a maintained OAuth2 client) rather than a patch. This is the single biggest reason to treat the package as reference material rather than a runtime dependency. For a working legacy system that talks to a still-live internal endpoint, it remains usable as DI glue.

Maintenance status. Zero dependents, no recent releases, Symfony 2/3-only bundle registration (no Flex recipe, no services.yaml autoconfiguration). On Symfony 4+ you'll be hand-editing config/bundles.php and possibly overriding the extension's XML. Forking and modernizing the services.xml is usually faster than fighting the constraints.

PHP version pin. The composer constraints are old (PHP 5.5/7.0-era). Expect composer update conflicts on PHP 8; use --ignore-platform-reqs only as a last resort — the client may genuinely use removed functions.

Redirect URI must match byte-for-byte, including trailing slash and http vs https, and must be registered in the Instagram app dashboard. Mismatch is the #1 cause of redirect_uri_mismatch on the token exchange.

The code is single-use. If the callback action retries the getOAuthToken() call (e.g., after a validation exception), the second attempt fails. Exchange the code exactly once, then persist the token before doing anything else.

Sandbox mode. In sandbox, only users you've explicitly added can authenticate, and data is restricted. This looks like an API bug until you remember the sandbox invite list.

Scopes need approval. basic is granted by default; public_content, follower_list, likes, comments, relationships require an app review. The bundle doesn't abstract scopes — pass them to the login URL yourself if the client supports it, or fork it.

CSRF on the OAuth callback. Handle the state parameter in your controller. The bundle's getLoginUrl() historically generates state internally or not at all depending on version; don't assume it's validated for you.

Media URLs are signed and expire. Don't hotlink the CDN URLs into long-lived pages. Download or at least re-fetch on each sync cycle.

Errors are opaque. The underlying client tends to throw generic exceptions or return error payloads rather than typed HTTP exceptions. Wrap calls:

try {
    $media = $instagram->getUserMedia();
} catch (\Exception $e) {
    $this->logger->error('Instagram call failed', ['exception' => $e]);
    // surface 429 vs 400 vs auth failure yourself from the message
}

Log the raw response body during bring-up; the Symfony profiler won't show these calls unless you instrument the client's Guzzle handler.

Extension points. The realistic levers are: decorate hautelook_instagram.client with your own class implementing the same methods (cache + retry + logging live here), override the service definition to inject a custom Guzzle client, or replace the bundle outright with a small service around league/oauth2-instagram + a PSR-18 client. Given the package's age, the decorator route is the only one that stays clean as you migrate off 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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings