pgrimaud/instagram-user-feed
Fetch public Instagram user feeds in PHP without the official API or access tokens. Retrieve profile info, posts, photos, videos, and stories via a simple, dependency-light crawler with pagination and caching. Works standalone or in Laravel.
Architecture fit. pgrimaud/instagram-user-feed is a framework-agnostic Composer library, not a Laravel package — it ships no service provider, config, facade, or migrations. That is a fit advantage and a governance gap at the same time: it drops into app/Services or a dedicated packages/ namespace cleanly and is trivially mockable behind an interface, but every integration concern (config, DI binding, caching, rate limiting, logging, retries) is ours to write. Its transport dependency is Guzzle, which Laravel already pulls in, so there is no dependency-tree conflict risk on a modern Laravel 9–11 / PHP 8.1+ stack. The core value is not the code — it is a set of undocumented Instagram web endpoints (?__a=1, the GraphQL query hash, the web login/session flow). We are effectively adopting a thin, unversioned client for a private API that Meta does not publish, does not support, and actively defends.
Integration feasibility. Happy-path read integration is genuinely cheap: composer require, instantiate with a cache implementation, call getFeed($username) / getUserInfo(), normalize into our own DTOs. A spike can be done in a day. Authenticated actions (like, follow, comment) require a live sessionid/csrftoken cookie, which raises the bar substantially — credential custody, account ownership, per-account session rotation, and the fact that these calls are indistinguishable from bot traffic. Write actions also carry account-level consequences (action blocks, shadow bans, checkpoint challenges) that land on whichever business account we point it at.
Technical risk. High, and concentrated in three places:
login_required; response shapes change without notice. Failure is not a clean 500 — it is silent empty payloads and partial data.Key questions for the team before committing:
Stack fit. The package integrates as a domain adapter, not as an application dependency. Recommended shape:
InstagramFeedProvider interface in our domain layer; PgrimaudProvider as one implementation, with room for GraphApiProvider and ThirdPartyProvider siblings.config/instagram.php with session/cookie, cache TTL, timeout, retry count, and proxy settings — never inline credentials.RateLimiter::for('instagram')), retry/backoff, and a circuit breaker keyed on consecutive auth/429 failures.Migration path. Do not start with the scraper as the long-term plan. Sequence it as a disposable implementation detail:
Compatibility. Watch three things: the PHP version floor of the release we pin, the Guzzle major (Laravel's own HTTP client wraps Guzzle, so avoid version drift across the app), and the cache abstraction — earlier majors used Doctrine Cache, later ones PSR-16; pin an exact version and vendor-fork it rather than floating ^. Also verify there is no conflict between the package's internal retry behavior and Laravel's queue retry policy, or you will get multiplicative retries against a rate-limited endpoint.
Sequencing (roughly 3–4 sprints for a hardened read-only integration):
Maintenance. This is the dominant cost and it is not optional. Expect the library to break when Meta changes endpoint gating or response shape — historically this happens without warning and often more than once a year. That means: a named owner in the team, a pinned and vendored fork we can patch in hours rather than waiting on upstream, a fixture-based test suite so a break is caught by CI before customers see it, and a documented "degraded mode" (serve stale cache, hide the widget) so breakage is cosmetic instead of an outage.
Support. There is no vendor. Upstream is effectively a single maintainer with community issues; security fixes and compatibility patches will lag our needs. We should assume we own the code and plan for a fork-and-patch cadence, including a periodic dependency review. Budget it as a line item, not goodwill.
Scaling. Throughput is bounded by IP reputation, not by our infrastructure. Realistic levers: connection pooling to a proxy pool (a real cost with real procurement lead time), a token-bucket limiter per account and per IP, aggressive caching to keep request volume down, and a queue with backpressure so a 429 storm doesn't cascade into the rest of the app. Estimate cost per 1,000 successful fetches including proxy spend and retry overhead before committing to any volume target — scraping rarely scales linearly and the marginal request is often the most expensive one.
Failure modes to instrument and alert on:
| Mode | Symptom | Mitigation |
|---|---|---|
Session expiry / login_required |
401/redirect, empty feed | Circuit breaker, alert, manual session refresh |
| Rate limiting | 429, growing queue depth | Backoff, per-IP budget, shed load |
| Checkpoint / challenge | checkpoint_required |
Hard stop, do not retry — retries worsen it |
| Endpoint/shape drift | Parse failure, missing keys | Schema validation in adapter, fixture tests, stale-cache fallback |
| IP/ASN block | Elevated failure rate from datacenter range | Proxy rotation, egress diversity |
| Write-action ban | Account flagged after like/follow | Avoid write actions in production entirely |
Ramp-up. Low for the happy path — a competent PHP engineer is productive in an afternoon. High for production hardening, because the hard parts are anti-bot dynamics, proxy/egress management, and failure-mode observability, which are scraping-domain skills rather than Laravel skills. Plan for one engineer to own it with a second able to respond to alerts.
TPM recommendation. Approve only as a time-boxed, read-only, internal enrichment source behind a provider interface, with legal sign-off, a pinned fork, a circuit breaker, and a scheduled sunset review at 90 days. Reject for anything touching write actions on business-owned accounts, and reject any design where the scraper is the sole source of a customer-facing feature with no fallback.
How can I help you explore Laravel packages today?