This repo packages a dependency-free HTML widget that turns a public Instagram profile into a clean tiled gallery with a full-size lightbox view.
- instagram-gallery.js: the embeddable web component
- index.html: a placeholder demo page using
your_instagram_handle - server.mjs: a local Node demo server with the feed endpoint and image proxy
- api/instagram-feed.js: a Vercel-style serverless feed endpoint
- api/image-proxy.js: a serverless proxy for Instagram CDN images
Instagram blocks reliable browser-side cross-origin requests, so a pure front-end widget is not a stable way to do this. The included backend fetches the public profile feed on your behalf and returns normalized image data to the widget.
This setup gives you:
- No Instagram API key required
- Only public uploads
- Server-side image proxying so full-size images display cleanly
- 30-minute caching with 24-hour stale fallback if Instagram temporarily rate-limits requests
- Optional cookie-backed fallback if anonymous Instagram requests start returning
401or429
npm startThen open http://localhost:8787.
If Instagram starts returning 401 or 429, run the backend with a private server-side cookie:
export INSTAGRAM_COOKIE='sessionid=...; csrftoken=...; ds_user_id=...'
npm startUse .env.example as the shape for that value. Keep this on the server only and never expose it in client-side code.
Serve instagram-gallery.js and expose /api/instagram-feed from either server.mjs or your serverless platform.
<script type="module" src="/instagram-gallery.js"></script>
<instagram-gallery
username="your_instagram_handle"
endpoint="/api/instagram-feed"
heading="Latest posts"
subheading="Public uploads from @your_instagram_handle"
limit="12"
refresh-ms="1800000"
></instagram-gallery>This repo already includes api/instagram-feed.js and api/image-proxy.js, so you can import the repo into Vercel directly and keep the front end pointed at /api/instagram-feed.
GET /api/instagram-feed?username=your_instagram_handle&limit=12
Returns:
profile: public account details such as name and follower countitems: normalized image records withimageUrl,thumbnailUrl, dimensions, alt text, caption, and permalinkfetchedAt: when your server refreshed the payloadsource:publicorauthenticateddepending on whether the cookie fallback was usedstale:trueif a cached payload was served after a temporary Instagram failure
- This viewer is image-first. Videos are skipped on purpose.
- Instagram can change its public endpoints at any time, so this is practical but not guaranteed forever.
- The demo uses
your_instagram_handleas a placeholder. Swap that value anywhere you embed the widget.