Pick a random winner from any public Instagram post — no login, no API keys, no fuss.
Available in English & Spanish 🇺🇸🇪🇸
- 🔓 No authentication required — works with any public post
- 💬 Extracts all comments — top-level + replies via multi-pass GraphQL scraping
- 🖼️ Real profile pictures — served through a local reverse proxy (no CORS issues)
- ❤️ Real like count — extracted directly from Instagram's SSR HTML
- 🌐 Bilingual UI — English / Spanish with one-click toggle (persisted in localStorage)
- 🎰 Roulette animation — smooth, decelerating spin before revealing the winner
- 📱 Responsive — works on mobile, tablet, and desktop
- Node.js v18+
- npm
git clone https://github.com/andresayac/instapick.git
cd instapick
npm installnpm startThen open http://localhost:3000 in your browser.
For development with auto-reload:
npm run dev| Pass | Method | Description |
|---|---|---|
| 0 | HTML SSR | Parses Instagram's <script data-sjs> blobs for pre-loaded comments |
| 1 | GraphQL popular |
Paginates PolarisPostCommentsPaginationQuery with sort_order: popular |
| 2 | GraphQL recent |
Same query with sort_order: recent to catch remaining comments |
| 3 | Child Comments | Fetches replies via PolarisPostChildCommentsQuery for any parent with children |
All results are de-duplicated by comment pk (Instagram's comment ID).
Instagram blocks direct hotlinking of CDN images. The server includes a local reverse proxy at /proxy/image?url=... that:
- Fetches images server-side with proper
Refererheaders - Serves them to the browser from
localhost— zero CORS issues - Caches responses for 1 hour
Extracted from Microlink's metadata (which parses Instagram's Open Graph tags), with a fallback regex on the description field ("351 likes, 421 comments...").
instagram-giveaway-picker/
├── server.js # Express backend: API extraction, image proxy, static serving
├── index.html # SPA entry point with i18n data-attributes
├── script.js # Frontend logic: fetch, render, roulette animation
├── i18n.js # Translation strings (ES/EN) + language switcher
├── style.css # Dark glassmorphism UI + responsive layout
└── package.json
| Limit | Reason |
|---|---|
| ~300-400 top-level comments per pass | Instagram rate-limits anonymous GraphQL by session |
| Public posts only | Private accounts require authentication (not supported) |
doc_id may expire |
Instagram occasionally rotates GraphQL document IDs; update doc_id in server.js if extraction breaks |
The application uses standard environment variables. You can configure it by creating a .env file in the root directory (see .env.example):
PORT=4000If not specified, the server will default to 3000.
Other internal configurations live in server.js. Key constants:
doc_id: '26248690958161038' // PolarisPostCommentsPaginationQuery
doc_id: '26914912424764761' // PolarisPostChildCommentsQuery
maxPages: 30 // pages × 50 comments = max per pass
delay: 300-500ms // between requests (avoids HTTP 429)Translations are in i18n.js. To add a new language:
translations.fr = {
title: 'Tirage au sort Instagram',
// ... all keys from the ES object
};Then update the switchLang() cycle in i18n.js.
MIT — free to use, fork, and modify.
- Microlink — Open Graph metadata extraction
- Font Awesome — Icons
- Google Fonts — Outfit typeface