ultra-igdl 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,594 +1,622 @@
1
- # ultra-igdl
2
-
3
- **Production-grade Instagram media extractor for Node.js 20+**
4
-
5
- Fetch direct CDN URLs for reels, posts, carousels, stories, and highlights. Built from scratch with a multi-layer HTML/JSON parser, optional logged-in session API, connection pooling, LRU cache, and a CLI — **no wrapper around other Instagram downloader packages**.
6
-
7
- ---
8
-
9
- ## Table of contents
10
-
11
- 1. [Who is this for?](#who-is-this-for)
12
- 2. [Requirements](#requirements)
13
- 3. [Installation](#installation)
14
- 4. [Quick start (beginner)](#quick-start-beginner)
15
- 5. [Instagram session (important)](#instagram-session-important)
16
- 6. [CLI guide](#cli-guide)
17
- 7. [Supported URLs](#supported-urls)
18
- 8. [Response format](#response-format)
19
- 9. [Content types explained](#content-types-explained)
20
- 10. [JavaScript / TypeScript API](#javascript--typescript-api)
21
- 11. [Configuration options](#configuration-options)
22
- 12. [Pro features](#pro-features)
23
- 13. [Error codes & troubleshooting](#error-codes--troubleshooting)
24
- 14. [Examples in this repo](#examples-in-this-repo)
25
- 15. [Architecture](#architecture)
26
- 16. [Development](#development)
27
- 17. [Publishing to npm](#publishing-to-npm)
28
- 18. [Legal & disclaimer](#legal--disclaimer)
29
- 19. [License](#license)
30
-
31
- ---
32
-
33
- ## Who is this for?
34
-
35
- | Level | You can… |
36
- |--------|-----------|
37
- | **Beginner** | Install with npm, run `npx ultra-igdl <url> --json`, paste a browser cookie for full carousels |
38
- | **Intermediate** | Use `ultraigdl` in Express/Fastify bots, batch URLs, download files with `--download` |
39
- | **Pro** | Tune cache/Redis, `fastMode` + `prefetch`, `maxConcurrency`, integrate `DownloaderCore` |
40
-
41
- ---
42
-
43
- ## Requirements
44
-
45
- - **Node.js** 20.18.1+ or 22 (LTS recommended)
46
- - **npm** 9+ (or pnpm/yarn)
47
- - Public Instagram URLs (no login required for basic post/reel preview)
48
- - **Optional:** Instagram `sessionid` cookie for carousels (all slides), reel MP4, stories, highlights
49
-
50
- ---
51
-
52
- ## Installation
53
-
54
- ```bash
55
- npm install ultra-igdl
56
- ```
57
-
58
- CLI only (no install into project):
59
-
60
- ```bash
61
- npx ultra-igdl --help
62
- ```
63
-
64
- ---
65
-
66
- ## Quick start (beginner)
67
-
68
- ### 1. Programmatic (ESM)
69
-
70
- ```js
71
- import { ultraigdl } from "ultra-igdl";
72
-
73
- const ig = new ultraigdl();
74
- const result = await ig.download("https://www.instagram.com/reel/SHORTCODE/");
75
-
76
- if (result.code === 200) {
77
- console.log("User:", result.username);
78
- console.log("Caption:", result.caption);
79
- console.log("Files:", result.media.length);
80
- result.media.forEach((m, i) => console.log(i + 1, m.type, m.url));
81
- } else {
82
- console.error(result.code, result.message);
83
- }
84
- ```
85
-
86
- ### 2. CommonJS
87
-
88
- ```js
89
- const { ultraigdl } = require("ultra-igdl");
90
-
91
- (async () => {
92
- const ig = new ultraigdl();
93
- const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
94
- console.log(result);
95
- })();
96
- ```
97
-
98
- ### 3. CLI (JSON)
99
-
100
- ```bash
101
- npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
102
- ```
103
-
104
- On **Windows PowerShell**, always wrap URLs in **double quotes** (see [CLI guide](#cli-guide)).
105
-
106
- ---
107
-
108
- ## Instagram session (important)
109
-
110
- Instagram limits what **logged-out** visitors see:
111
-
112
- | Feature | Without session | With session (`sessionId` / `cookies`) |
113
- |---------|-----------------|----------------------------------------|
114
- | Single post image | Usually yes | Yes (full resolution) |
115
- | **Carousel (2+ photos)** | Often **1 slide only** | **All slides** |
116
- | **Reel MP4** | Often thumbnail only | **Video URL** |
117
- | **Story** | Usually fails / preview | **Media URL** |
118
- | **Highlight** | Limited | **Video** when available |
119
-
120
- ### How to get cookies (browser)
121
-
122
- 1. Log in to [instagram.com](https://www.instagram.com) in Chrome/Edge/Firefox.
123
- 2. Open DevTools → **Application** → **Cookies** → `https://www.instagram.com`.
124
- 3. Copy:
125
- - `sessionid`
126
- - `csrftoken`
127
- - `ds_user_id`
128
-
129
- ### Option A — full cookie string (recommended)
130
-
131
- ```js
132
- const ig = new ultraigdl({
133
- cookies:
134
- "sessionid=YOUR_ID; csrftoken=YOUR_CSRF; ds_user_id=YOUR_USER_ID",
135
- });
136
- ```
137
-
138
- ### Option B session id only
139
-
140
- ```js
141
- const ig = new ultraigdl({
142
- sessionId: "YOUR_SESSIONID_VALUE",
143
- });
144
- ```
145
-
146
- ### Environment variables (CLI)
147
-
148
- The CLI auto-loads `.env` from the current directory or `../ultra-igdl-live-test/.env`.
149
-
150
- ```bash
151
- # Linux / macOS
152
- export INSTAGRAM_COOKIES="sessionid=...; csrftoken=...; ds_user_id=..."
153
- npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
154
- ```
155
-
156
- ```powershell
157
- # Windows PowerShelluse TWO lines, or semicolon before npx
158
- $env:INSTAGRAM_COOKIES = "sessionid=...; csrftoken=...; ds_user_id=..."
159
- npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
160
- ```
161
-
162
- **Never commit real cookies to git.** Add `.env` to `.gitignore` (already included).
163
-
164
- ---
165
-
166
- ## CLI guide
167
-
168
- ```bash
169
- npx ultra-igdl <url> [options]
170
- npx ultra-igdl urls.txt # one URL per line
171
- ```
172
-
173
- | Flag | Short | Description |
174
- |------|-------|-------------|
175
- | `--json` | `-j` | Print full API response as JSON |
176
- | `--download` | `-d` | Save media files under `--output` |
177
- | `--output <dir>` | `-o` | Download folder (default: `./downloads`) |
178
- | `--verbose` | `-v` | Debug logging |
179
- | `--help` | `-h` | Show help |
180
-
181
- ### PowerShell rules
182
-
183
- 1. Wrap URLs in `"quotes"` when the link contains `&` (e.g. `?igsh=...&...`).
184
- 2. Set env vars on **line 1**, run `npx` on **line 2**, **or** use `;` between them:
185
-
186
- ```powershell
187
- $env:INSTAGRAM_COOKIES = "sessionid=...; csrftoken=...; ds_user_id=..."; npx ultra-igdl "https://www.instagram.com/p/ABC/" --json
188
- ```
189
-
190
- ### CLI examples
191
-
192
- ```bash
193
- # Human-readable summary
194
- npx ultra-igdl "https://www.instagram.com/reel/ABC123/"
195
-
196
- # JSON for scripts
197
- npx ultra-igdl "https://www.instagram.com/p/ABC123/" --json
198
-
199
- # Download all carousel images
200
- npx ultra-igdl "https://www.instagram.com/p/ABC123/" --download -o ./downloads
201
-
202
- # Batch file (urls.txt)
203
- npx ultra-igdl urls.txt --json
204
- ```
205
-
206
- ---
207
-
208
- ## Supported URLs
209
-
210
- | Type | Example pattern |
211
- |------|-----------------|
212
- | Post | `https://www.instagram.com/p/{shortcode}/` |
213
- | Reel | `https://www.instagram.com/reel/{shortcode}/` |
214
- | IGTV | `https://www.instagram.com/tv/{shortcode}/` |
215
- | Story | `https://www.instagram.com/stories/{username}/{storyId}/` |
216
- | Highlight (path) | `https://www.instagram.com/stories/highlights/{id}/` |
217
- | Highlight (share) | `https://www.instagram.com/s/{token}?story_media_id=...` |
218
-
219
- Validate before download:
220
-
221
- ```js
222
- const { valid, type, normalized } = await ig.validate(url);
223
- ```
224
-
225
- ---
226
-
227
- ## Response format
228
-
229
- ### Success (`code: 200`)
230
-
231
- ```json
232
- {
233
- "code": 200,
234
- "meta": { "extractor": "ultra-igdl", "version": "1.0.0" },
235
- "media": [
236
- {
237
- "type": "image",
238
- "url": "https://...cdninstagram.../....jpg",
239
- "width": 1440,
240
- "height": 1800
241
- },
242
- {
243
- "type": "video",
244
- "url": "https://...mp4",
245
- "thumbnail": "https://...jpg",
246
- "width": 1080,
247
- "height": 1920,
248
- "duration": 24
249
- }
250
- ],
251
- "caption": "Post caption as a single clean line for posts",
252
- "username": "creator",
253
- "engagement": {
254
- "likes": 1200,
255
- "comments": 45
256
- },
257
- "tags": ["carousel"]
258
- }
259
- ```
260
-
261
- ### Media object
262
-
263
- | Field | Type | Description |
264
- |-------|------|-------------|
265
- | `type` | `"image"` \| `"video"` | Primary media type |
266
- | `url` | `string` | Direct CDN URL (signed; do not edit query params) |
267
- | `thumbnail` | `string?` | Poster frame for video |
268
- | `width` / `height` | `number?` | Pixel dimensions when known |
269
- | `duration` | `number?` | Video length in seconds |
270
-
271
- ### Tags (`tags` array)
272
-
273
- | Tag | Meaning |
274
- |-----|---------|
275
- | `carousel` | Multi-slide post; `media.length` ≥ 2 |
276
- | `partial_carousel` | Carousel detected but only one slide returned |
277
- | `session_recommended` | Add `sessionId` / `cookies` for full carousel |
278
- | `likes_hidden` | Creator hid like counts |
279
- | `comments_hidden` | Comments disabled or hidden |
280
- | `engagement_hidden` | Both likes and comments hidden |
281
-
282
- ### Error (`code` ≠ 200)
283
-
284
- ```json
285
- {
286
- "code": 404,
287
- "message": "Media not found",
288
- "meta": { "extractor": "ultra-igdl", "version": "1.0.0" }
289
- }
290
- ```
291
-
292
- Some responses include `retryAfterMs` when using `fastMode` / `responseBudgetMs` (background fetch still running).
293
-
294
- ---
295
-
296
- ## Content types explained
297
-
298
- ### Posts (single image)
299
-
300
- ```js
301
- const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
302
- // result.media.length === 1 typically
303
- ```
304
-
305
- ### Carousels (2+ photos)
306
-
307
- - **Auto-detected** from any `/p/` URL — no special URL or env var.
308
- - Without session: often 1 image + tags `partial_carousel`, `session_recommended`.
309
- - With session: all slides, tag `carousel`.
310
-
311
- ```js
312
- const ig = new ultraigdl({ cookies: process.env.INSTAGRAM_COOKIES });
313
- const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
314
- console.log(result.media.length); // e.g. 4
315
- console.log(result.tags); // ["carousel"]
316
- ```
317
-
318
- ### Reels
319
-
320
- ```js
321
- const ig = new ultraigdl({ sessionId: process.env.INSTAGRAM_SESSION_ID });
322
- const result = await ig.download("https://www.instagram.com/reel/SHORTCODE/");
323
- const video = result.media.find((m) => m.type === "video");
324
- ```
325
-
326
- ### Stories
327
-
328
- Requires session. Story must still be live (not expired).
329
-
330
- ```js
331
- const result = await ig.download(
332
- "https://www.instagram.com/stories/username/1234567890/"
333
- );
334
- ```
335
-
336
- ### Highlights
337
-
338
- Works with highlight URLs or `/s/` share links; session improves reliability.
339
-
340
- ---
341
-
342
- ## JavaScript / TypeScript API
343
-
344
- ```ts
345
- import { ultraigdl, type ApiResponse, type DownloadResponse } from "ultra-igdl";
346
-
347
- const ig = new ultraigdl({ cache: true, retries: 2 });
348
- ```
349
-
350
- | Method | Returns | Description |
351
- |--------|---------|-------------|
352
- | `download(url)` | `Promise<ApiResponse>` | Full extraction (main method) |
353
- | `info(url)` | `Promise<ApiResponse>` | Alias of `download` |
354
- | `validate(url)` | `Promise<{ valid, type?, normalized? }>` | URL check + normalization |
355
- | `media(url)` | `Promise<Media[] \| ErrorResponse>` | Media array only |
356
- | `batch(urls)` | `Promise<BatchResult[]>` | Parallel downloads with per-URL timing |
357
- | `prefetch(url)` | `Promise<ApiResponse>` | Warm cache for `fastMode` |
358
- | `health()` | `Promise<HealthStatus>` | Cache stats, pool, version |
359
- | `clearCache()` | `void` | Clear in-memory LRU cache |
360
-
361
- ### TypeScript
362
-
363
- Types are shipped in `dist/index.d.ts`. Narrow success responses:
364
-
365
- ```ts
366
- const result = await ig.download(url);
367
- if (result.code === 200) {
368
- const data = result as DownloadResponse;
369
- data.media.forEach((m) => { /* ... */ });
370
- }
371
- ```
372
-
373
- ### Helpers (also exported)
374
-
375
- ```ts
376
- import { validateUrl, parseInstagramUrl, isInstagramUrl } from "ultra-igdl";
377
- ```
378
-
379
- ---
380
-
381
- ## Configuration options
382
-
383
- ```ts
384
- const ig = new ultraigdl({
385
- // Cache
386
- cache: true, // default: true
387
- cacheTtlMs: 300_000, // 5 min fresh TTL
388
- staleCacheTtlMs: 86_400_000, // 24h stale-while-revalidate
389
- cacheMaxSize: 500,
390
-
391
- // Network
392
- maxConcurrency: 100,
393
- timeoutMs: 15_000,
394
- retries: 3,
395
- userAgentRotation: true,
396
-
397
- // Session
398
- sessionId: "...",
399
- cookies: "sessionid=...; csrftoken=...; ds_user_id=...",
400
-
401
- // Low-latency mode (bots that reply in <500ms)
402
- fastMode: true, // sets responseBudgetMs: 500, retries: 0
403
- responseBudgetMs: 800,
404
-
405
- // Optional Redis (implement RedisAdapter interface)
406
- redis: myRedisAdapter,
407
-
408
- verbose: false,
409
- });
410
- ```
411
-
412
- ---
413
-
414
- ## Pro features
415
-
416
- ### Batch processing
417
-
418
- ```ts
419
- const results = await ig.batch([
420
- "https://www.instagram.com/p/A/",
421
- "https://www.instagram.com/reel/B/",
422
- ]);
423
- for (const { url, result, durationMs } of results) {
424
- console.log(url, result.code, `${durationMs}ms`);
425
- }
426
- ```
427
-
428
- ### Fast mode + prefetch (Telegram/Discord bots)
429
-
430
- ```ts
431
- const ig = new ultraigdl({ fastMode: true, cookies: "..." });
432
-
433
- // Warm extraction while user types
434
- await ig.prefetch(url);
435
-
436
- // Often returns from cache within budget
437
- let result = await ig.download(url);
438
- if (result.code === 503 && result.retryAfterMs) {
439
- await new Promise((r) => setTimeout(r, result.retryAfterMs));
440
- result = await ig.download(url);
441
- }
442
- ```
443
-
444
- ### Redis cache adapter
445
-
446
- ```ts
447
- import { ultraigdl, type RedisAdapter } from "ultra-igdl";
448
-
449
- const redis: RedisAdapter = {
450
- async get(key) { /* return string | null */ },
451
- async set(key, value, ttlMs) { /* ... */ },
452
- };
453
-
454
- const ig = new ultraigdl({ redis });
455
- ```
456
-
457
- ### Download files to disk (library)
458
-
459
- Use your own `fetch` on `media[].url`, or the CLI `--download` flag (uses built-in file downloader).
460
-
461
- ---
462
-
463
- ## Error codes & troubleshooting
464
-
465
- | Code | Typical cause | What to do |
466
- |------|---------------|------------|
467
- | **400** | Invalid URL | Use `validate()`; check link format |
468
- | **403** | Private account | Cannot extract without access |
469
- | **404** | Deleted / wrong id / expired story | Verify URL in browser |
470
- | **429** | Rate limited | Slow down; reduce concurrency; wait |
471
- | **500** | Parse/network failure | Retry; update package; report issue |
472
- | **503** | `fastMode` budget exceeded | Retry after `retryAfterMs` or disable fast mode |
473
- | **504** | Timeout | Increase `timeoutMs` |
474
-
475
- | Symptom | Fix |
476
- |---------|-----|
477
- | Carousel returns 1 image | Set `cookies` or `sessionId` |
478
- | Reel has no MP4 | Add session cookie |
479
- | CLI `Unexpected token 'npx'` | Use `;` or two lines in PowerShell |
480
- | `Invalid or unexpected token` on CLI | Run `npm run build`; use published version |
481
- | Caption has weird dots/lines | Post captions are flattened to one line by design |
482
- | 403 on CDN URL when downloading | Do not modify signed URL query string |
483
-
484
- ---
485
-
486
- ## Examples in this repo
487
-
488
- | File | Description |
489
- |------|-------------|
490
- | [`examples/basic.mjs`](./examples/basic.mjs) | Minimal JSON dump |
491
- | [`examples/bot-example.ts`](./examples/bot-example.ts) | Generic bot handler |
492
- | [`examples/express-api.ts`](./examples/express-api.ts) | REST API with Express |
493
- | [`examples/fastify-api.ts`](./examples/fastify-api.ts) | REST API with Fastify |
494
- | [`examples/telegram-bot.ts`](./examples/telegram-bot.ts) | Telegram-style handler |
495
- | [`examples/discord-bot.ts`](./examples/discord-bot.ts) | Discord-style handler |
496
- | [`examples/cookie-generator.mjs`](./examples/cookie-generator.mjs) | Cookie helper notes |
497
-
498
- Run locally after build:
499
-
500
- ```bash
501
- npm run build
502
- node examples/basic.mjs "https://www.instagram.com/p/SHORTCODE/"
503
- ```
504
-
505
- **Live Instagram tests** are kept in a separate repo folder: `ultra-igdl-live-test` (not published to npm).
506
-
507
- ---
508
-
509
- ## Architecture
510
-
511
- ```
512
- src/
513
- ├── core/ # downloader orchestration, cache, parser, extractor
514
- ├── extractors/ # post, reel, story, highlight
515
- ├── network/ # undici client, headers, retry, pool, Instagram API
516
- ├── utils/ # captions, carousel, media quality, URLs
517
- ├── cli/ # CLI entry (published as ultra-igdl bin)
518
- └── types/ # TypeScript definitions
519
- ```
520
-
521
- **Extraction layers** (first useful result wins, posts scan multiple layers for carousels):
522
-
523
- 1. Open Graph / meta tags
524
- 2. Embedded `application/json` / script blobs
525
- 3. `window.__additionalDataLoaded` / `_sharedData`
526
- 4. Next.js `__NEXT_DATA__`
527
- 5. GraphQL / CDN discovery in HTML
528
- 6. Regex fallback
529
-
530
- With **session**: parallel `media/info` API for posts (carousels), reels, stories, highlights.
531
-
532
- ---
533
-
534
- ## Development
535
-
536
- ```bash
537
- git clone https://github.com/your-username/ultra-igdl.git
538
- cd ultra-igdl
539
- npm install
540
- npm run build
541
- npm test
542
- npm run test:coverage
543
- npm run test:stress
544
- ```
545
-
546
- | Script | Purpose |
547
- |--------|---------|
548
- | `npm run build` | Compile ESM + CJS + CLI to `dist/` |
549
- | `npm test` | Unit + integration tests (mocked HTTP; excludes stress) |
550
- | `npm run cli -- "<url>" --json` | Run CLI from source tree |
551
- | `npm run lint` | Typecheck |
552
-
553
- ---
554
-
555
- ## Publishing to npm
556
-
557
- Maintainers:
558
-
559
- ```bash
560
- # 1. Login
561
- npm login
562
-
563
- # 2. Set author/repository in package.json (your GitHub username)
564
-
565
- # 3. Dry run — only dist/, README, LICENSE should be listed
566
- npm pack --dry-run
567
-
568
- # 4. Publish (runs build + tests via prepublishOnly)
569
- npm publish
570
- ```
571
-
572
- Consumers install with:
573
-
574
- ```bash
575
- npm install ultra-igdl
576
- ```
577
-
578
- **Before first publish:** change `repository`, `bugs`, and `homepage` in `package.json` from `your-username` to your real GitHub path.
579
-
580
- ---
581
-
582
- ## Legal & disclaimer
583
-
584
- - This project is **not affiliated with Instagram / Meta**.
585
- - You are responsible for complying with Instagram's Terms of Use and applicable laws.
586
- - Only download content you have the right to access and use.
587
- - Session cookies are credentials — treat them like passwords.
588
- - CDN URLs are **signed** and expire; download promptly and do not strip query parameters.
589
-
590
- ---
591
-
592
- ## License
593
-
1
+ # ultra-igdl
2
+
3
+ **Production-grade Instagram media extractor for Node.js 20+**
4
+
5
+ Fetch direct CDN URLs for reels, posts, carousels, stories, and highlights. Built from scratch with a multi-layer HTML/JSON parser, optional logged-in session API, connection pooling, LRU cache, and a CLI — **no wrapper around other Instagram downloader packages**.
6
+
7
+ ---
8
+
9
+ ## Table of contents
10
+
11
+ 1. [Who is this for?](#who-is-this-for)
12
+ 2. [Requirements](#requirements)
13
+ 3. [Installation](#installation)
14
+ 4. [Quick start (beginner)](#quick-start-beginner)
15
+ 5. [Instagram session (important)](#instagram-session-important)
16
+ 6. [CLI guide](#cli-guide)
17
+ 7. [Supported URLs](#supported-urls)
18
+ 8. [Response format](#response-format)
19
+ 9. [Content types explained](#content-types-explained)
20
+ 10. [JavaScript / TypeScript API](#javascript--typescript-api)
21
+ 11. [Configuration options](#configuration-options)
22
+ 12. [Pro features](#pro-features)
23
+ 13. [Error codes & troubleshooting](#error-codes--troubleshooting)
24
+ 14. [Examples in this repo](#examples-in-this-repo)
25
+ 15. [Architecture](#architecture)
26
+ 16. [Development](#development)
27
+ 17. [Publishing to npm](#publishing-to-npm)
28
+ 18. [Legal & disclaimer](#legal--disclaimer)
29
+ 19. [License](#license)
30
+
31
+ ---
32
+
33
+ ## Who is this for?
34
+
35
+ | Level | You can… |
36
+ |--------|-----------|
37
+ | **Beginner** | Install with npm, run `npx ultra-igdl <url> --json`, paste a browser cookie for full carousels |
38
+ | **Intermediate** | Use `ultraigdl` in Express/Fastify bots, batch URLs, download files with `--download` |
39
+ | **Pro** | Tune cache/Redis, `fastMode` + `prefetch`, `maxConcurrency`, integrate `DownloaderCore` |
40
+
41
+ ---
42
+
43
+ ## Requirements
44
+
45
+ - **Node.js** 20.18.1+ or 22 (LTS recommended)
46
+ - **npm** 9+ (or pnpm/yarn)
47
+ - Public Instagram URLs (no login required for basic post/reel preview)
48
+ - **Optional:** Instagram `sessionid` cookie for carousels (all slides), reel MP4, stories, highlights
49
+
50
+ ---
51
+
52
+ ## Installation
53
+
54
+ ### npm (recommended)
55
+
56
+ ```bash
57
+ npm install ultra-igdl
58
+ ```
59
+
60
+ [![npm version](https://img.shields.io/npm/v/ultra-igdl.svg)](https://www.npmjs.com/package/ultra-igdl)
61
+
62
+ ### GitHub Packages
63
+
64
+ Scoped package: `@wh173-5p1d3r/ultra-igdl` (published on release tags `v*`).
65
+
66
+ 1. Create a [GitHub PAT](https://github.com/settings/tokens) with `read:packages`.
67
+ 2. Add `.npmrc` (see [`.npmrc.github.example`](./.npmrc.github.example)):
68
+
69
+ ```ini
70
+ @wh173-5p1d3r:registry=https://npm.pkg.github.com
71
+ //npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
72
+ ```
73
+
74
+ 3. Install:
75
+
76
+ ```bash
77
+ npm install @wh173-5p1d3r/ultra-igdl
78
+ ```
79
+
80
+ ```js
81
+ import { ultraigdl } from "@wh173-5p1d3r/ultra-igdl";
82
+ ```
83
+
84
+ Package page: https://github.com/WH173-5P1D3R/ultra-igdl/packages
85
+
86
+ CLI only (no install into project):
87
+
88
+ ```bash
89
+ npx ultra-igdl --help
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Quick start (beginner)
95
+
96
+ ### 1. Programmatic (ESM)
97
+
98
+ ```js
99
+ import { ultraigdl } from "ultra-igdl";
100
+
101
+ const ig = new ultraigdl();
102
+ const result = await ig.download("https://www.instagram.com/reel/SHORTCODE/");
103
+
104
+ if (result.code === 200) {
105
+ console.log("User:", result.username);
106
+ console.log("Caption:", result.caption);
107
+ console.log("Files:", result.media.length);
108
+ result.media.forEach((m, i) => console.log(i + 1, m.type, m.url));
109
+ } else {
110
+ console.error(result.code, result.message);
111
+ }
112
+ ```
113
+
114
+ ### 2. CommonJS
115
+
116
+ ```js
117
+ const { ultraigdl } = require("ultra-igdl");
118
+
119
+ (async () => {
120
+ const ig = new ultraigdl();
121
+ const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
122
+ console.log(result);
123
+ })();
124
+ ```
125
+
126
+ ### 3. CLI (JSON)
127
+
128
+ ```bash
129
+ npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
130
+ ```
131
+
132
+ On **Windows PowerShell**, always wrap URLs in **double quotes** (see [CLI guide](#cli-guide)).
133
+
134
+ ---
135
+
136
+ ## Instagram session (important)
137
+
138
+ Instagram limits what **logged-out** visitors see:
139
+
140
+ | Feature | Without session | With session (`sessionId` / `cookies`) |
141
+ |---------|-----------------|----------------------------------------|
142
+ | Single post image | Usually yes | Yes (full resolution) |
143
+ | **Carousel (2+ photos)** | Often **1 slide only** | **All slides** |
144
+ | **Reel MP4** | Often thumbnail only | **Video URL** |
145
+ | **Story** | Usually fails / preview | **Media URL** |
146
+ | **Highlight** | Limited | **Video** when available |
147
+
148
+ ### How to get cookies (browser)
149
+
150
+ 1. Log in to [instagram.com](https://www.instagram.com) in Chrome/Edge/Firefox.
151
+ 2. Open DevTools → **Application** → **Cookies** → `https://www.instagram.com`.
152
+ 3. Copy:
153
+ - `sessionid`
154
+ - `csrftoken`
155
+ - `ds_user_id`
156
+
157
+ ### Option Afull cookie string (recommended)
158
+
159
+ ```js
160
+ const ig = new ultraigdl({
161
+ cookies:
162
+ "sessionid=YOUR_ID; csrftoken=YOUR_CSRF; ds_user_id=YOUR_USER_ID",
163
+ });
164
+ ```
165
+
166
+ ### Option B — session id only
167
+
168
+ ```js
169
+ const ig = new ultraigdl({
170
+ sessionId: "YOUR_SESSIONID_VALUE",
171
+ });
172
+ ```
173
+
174
+ ### Environment variables (CLI)
175
+
176
+ The CLI auto-loads `.env` from the current directory or `../ultra-igdl-live-test/.env`.
177
+
178
+ ```bash
179
+ # Linux / macOS
180
+ export INSTAGRAM_COOKIES="sessionid=...; csrftoken=...; ds_user_id=..."
181
+ npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
182
+ ```
183
+
184
+ ```powershell
185
+ # Windows PowerShell — use TWO lines, or semicolon before npx
186
+ $env:INSTAGRAM_COOKIES = "sessionid=...; csrftoken=...; ds_user_id=..."
187
+ npx ultra-igdl "https://www.instagram.com/p/SHORTCODE/" --json
188
+ ```
189
+
190
+ **Never commit real cookies to git.** Add `.env` to `.gitignore` (already included).
191
+
192
+ ---
193
+
194
+ ## CLI guide
195
+
196
+ ```bash
197
+ npx ultra-igdl <url> [options]
198
+ npx ultra-igdl urls.txt # one URL per line
199
+ ```
200
+
201
+ | Flag | Short | Description |
202
+ |------|-------|-------------|
203
+ | `--json` | `-j` | Print full API response as JSON |
204
+ | `--download` | `-d` | Save media files under `--output` |
205
+ | `--output <dir>` | `-o` | Download folder (default: `./downloads`) |
206
+ | `--verbose` | `-v` | Debug logging |
207
+ | `--help` | `-h` | Show help |
208
+
209
+ ### PowerShell rules
210
+
211
+ 1. Wrap URLs in `"quotes"` when the link contains `&` (e.g. `?igsh=...&...`).
212
+ 2. Set env vars on **line 1**, run `npx` on **line 2**, **or** use `;` between them:
213
+
214
+ ```powershell
215
+ $env:INSTAGRAM_COOKIES = "sessionid=...; csrftoken=...; ds_user_id=..."; npx ultra-igdl "https://www.instagram.com/p/ABC/" --json
216
+ ```
217
+
218
+ ### CLI examples
219
+
220
+ ```bash
221
+ # Human-readable summary
222
+ npx ultra-igdl "https://www.instagram.com/reel/ABC123/"
223
+
224
+ # JSON for scripts
225
+ npx ultra-igdl "https://www.instagram.com/p/ABC123/" --json
226
+
227
+ # Download all carousel images
228
+ npx ultra-igdl "https://www.instagram.com/p/ABC123/" --download -o ./downloads
229
+
230
+ # Batch file (urls.txt)
231
+ npx ultra-igdl urls.txt --json
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Supported URLs
237
+
238
+ | Type | Example pattern |
239
+ |------|-----------------|
240
+ | Post | `https://www.instagram.com/p/{shortcode}/` |
241
+ | Reel | `https://www.instagram.com/reel/{shortcode}/` |
242
+ | IGTV | `https://www.instagram.com/tv/{shortcode}/` |
243
+ | Story | `https://www.instagram.com/stories/{username}/{storyId}/` |
244
+ | Highlight (path) | `https://www.instagram.com/stories/highlights/{id}/` |
245
+ | Highlight (share) | `https://www.instagram.com/s/{token}?story_media_id=...` |
246
+
247
+ Validate before download:
248
+
249
+ ```js
250
+ const { valid, type, normalized } = await ig.validate(url);
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Response format
256
+
257
+ ### Success (`code: 200`)
258
+
259
+ ```json
260
+ {
261
+ "code": 200,
262
+ "meta": { "extractor": "ultra-igdl", "version": "1.0.0" },
263
+ "media": [
264
+ {
265
+ "type": "image",
266
+ "url": "https://...cdninstagram.../....jpg",
267
+ "width": 1440,
268
+ "height": 1800
269
+ },
270
+ {
271
+ "type": "video",
272
+ "url": "https://...mp4",
273
+ "thumbnail": "https://...jpg",
274
+ "width": 1080,
275
+ "height": 1920,
276
+ "duration": 24
277
+ }
278
+ ],
279
+ "caption": "Post caption as a single clean line for posts",
280
+ "username": "creator",
281
+ "engagement": {
282
+ "likes": 1200,
283
+ "comments": 45
284
+ },
285
+ "tags": ["carousel"]
286
+ }
287
+ ```
288
+
289
+ ### Media object
290
+
291
+ | Field | Type | Description |
292
+ |-------|------|-------------|
293
+ | `type` | `"image"` \| `"video"` | Primary media type |
294
+ | `url` | `string` | Direct CDN URL (signed; do not edit query params) |
295
+ | `thumbnail` | `string?` | Poster frame for video |
296
+ | `width` / `height` | `number?` | Pixel dimensions when known |
297
+ | `duration` | `number?` | Video length in seconds |
298
+
299
+ ### Tags (`tags` array)
300
+
301
+ | Tag | Meaning |
302
+ |-----|---------|
303
+ | `carousel` | Multi-slide post; `media.length` ≥ 2 |
304
+ | `partial_carousel` | Carousel detected but only one slide returned |
305
+ | `session_recommended` | Add `sessionId` / `cookies` for full carousel |
306
+ | `likes_hidden` | Creator hid like counts |
307
+ | `comments_hidden` | Comments disabled or hidden |
308
+ | `engagement_hidden` | Both likes and comments hidden |
309
+
310
+ ### Error (`code` ≠ 200)
311
+
312
+ ```json
313
+ {
314
+ "code": 404,
315
+ "message": "Media not found",
316
+ "meta": { "extractor": "ultra-igdl", "version": "1.0.0" }
317
+ }
318
+ ```
319
+
320
+ Some responses include `retryAfterMs` when using `fastMode` / `responseBudgetMs` (background fetch still running).
321
+
322
+ ---
323
+
324
+ ## Content types explained
325
+
326
+ ### Posts (single image)
327
+
328
+ ```js
329
+ const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
330
+ // result.media.length === 1 typically
331
+ ```
332
+
333
+ ### Carousels (2+ photos)
334
+
335
+ - **Auto-detected** from any `/p/` URL — no special URL or env var.
336
+ - Without session: often 1 image + tags `partial_carousel`, `session_recommended`.
337
+ - With session: all slides, tag `carousel`.
338
+
339
+ ```js
340
+ const ig = new ultraigdl({ cookies: process.env.INSTAGRAM_COOKIES });
341
+ const result = await ig.download("https://www.instagram.com/p/SHORTCODE/");
342
+ console.log(result.media.length); // e.g. 4
343
+ console.log(result.tags); // ["carousel"]
344
+ ```
345
+
346
+ ### Reels
347
+
348
+ ```js
349
+ const ig = new ultraigdl({ sessionId: process.env.INSTAGRAM_SESSION_ID });
350
+ const result = await ig.download("https://www.instagram.com/reel/SHORTCODE/");
351
+ const video = result.media.find((m) => m.type === "video");
352
+ ```
353
+
354
+ ### Stories
355
+
356
+ Requires session. Story must still be live (not expired).
357
+
358
+ ```js
359
+ const result = await ig.download(
360
+ "https://www.instagram.com/stories/username/1234567890/"
361
+ );
362
+ ```
363
+
364
+ ### Highlights
365
+
366
+ Works with highlight URLs or `/s/` share links; session improves reliability.
367
+
368
+ ---
369
+
370
+ ## JavaScript / TypeScript API
371
+
372
+ ```ts
373
+ import { ultraigdl, type ApiResponse, type DownloadResponse } from "ultra-igdl";
374
+
375
+ const ig = new ultraigdl({ cache: true, retries: 2 });
376
+ ```
377
+
378
+ | Method | Returns | Description |
379
+ |--------|---------|-------------|
380
+ | `download(url)` | `Promise<ApiResponse>` | Full extraction (main method) |
381
+ | `info(url)` | `Promise<ApiResponse>` | Alias of `download` |
382
+ | `validate(url)` | `Promise<{ valid, type?, normalized? }>` | URL check + normalization |
383
+ | `media(url)` | `Promise<Media[] \| ErrorResponse>` | Media array only |
384
+ | `batch(urls)` | `Promise<BatchResult[]>` | Parallel downloads with per-URL timing |
385
+ | `prefetch(url)` | `Promise<ApiResponse>` | Warm cache for `fastMode` |
386
+ | `health()` | `Promise<HealthStatus>` | Cache stats, pool, version |
387
+ | `clearCache()` | `void` | Clear in-memory LRU cache |
388
+
389
+ ### TypeScript
390
+
391
+ Types are shipped in `dist/index.d.ts`. Narrow success responses:
392
+
393
+ ```ts
394
+ const result = await ig.download(url);
395
+ if (result.code === 200) {
396
+ const data = result as DownloadResponse;
397
+ data.media.forEach((m) => { /* ... */ });
398
+ }
399
+ ```
400
+
401
+ ### Helpers (also exported)
402
+
403
+ ```ts
404
+ import { validateUrl, parseInstagramUrl, isInstagramUrl } from "ultra-igdl";
405
+ ```
406
+
407
+ ---
408
+
409
+ ## Configuration options
410
+
411
+ ```ts
412
+ const ig = new ultraigdl({
413
+ // Cache
414
+ cache: true, // default: true
415
+ cacheTtlMs: 300_000, // 5 min fresh TTL
416
+ staleCacheTtlMs: 86_400_000, // 24h stale-while-revalidate
417
+ cacheMaxSize: 500,
418
+
419
+ // Network
420
+ maxConcurrency: 100,
421
+ timeoutMs: 15_000,
422
+ retries: 3,
423
+ userAgentRotation: true,
424
+
425
+ // Session
426
+ sessionId: "...",
427
+ cookies: "sessionid=...; csrftoken=...; ds_user_id=...",
428
+
429
+ // Low-latency mode (bots that reply in <500ms)
430
+ fastMode: true, // sets responseBudgetMs: 500, retries: 0
431
+ responseBudgetMs: 800,
432
+
433
+ // Optional Redis (implement RedisAdapter interface)
434
+ redis: myRedisAdapter,
435
+
436
+ verbose: false,
437
+ });
438
+ ```
439
+
440
+ ---
441
+
442
+ ## Pro features
443
+
444
+ ### Batch processing
445
+
446
+ ```ts
447
+ const results = await ig.batch([
448
+ "https://www.instagram.com/p/A/",
449
+ "https://www.instagram.com/reel/B/",
450
+ ]);
451
+ for (const { url, result, durationMs } of results) {
452
+ console.log(url, result.code, `${durationMs}ms`);
453
+ }
454
+ ```
455
+
456
+ ### Fast mode + prefetch (Telegram/Discord bots)
457
+
458
+ ```ts
459
+ const ig = new ultraigdl({ fastMode: true, cookies: "..." });
460
+
461
+ // Warm extraction while user types
462
+ await ig.prefetch(url);
463
+
464
+ // Often returns from cache within budget
465
+ let result = await ig.download(url);
466
+ if (result.code === 503 && result.retryAfterMs) {
467
+ await new Promise((r) => setTimeout(r, result.retryAfterMs));
468
+ result = await ig.download(url);
469
+ }
470
+ ```
471
+
472
+ ### Redis cache adapter
473
+
474
+ ```ts
475
+ import { ultraigdl, type RedisAdapter } from "ultra-igdl";
476
+
477
+ const redis: RedisAdapter = {
478
+ async get(key) { /* return string | null */ },
479
+ async set(key, value, ttlMs) { /* ... */ },
480
+ };
481
+
482
+ const ig = new ultraigdl({ redis });
483
+ ```
484
+
485
+ ### Download files to disk (library)
486
+
487
+ Use your own `fetch` on `media[].url`, or the CLI `--download` flag (uses built-in file downloader).
488
+
489
+ ---
490
+
491
+ ## Error codes & troubleshooting
492
+
493
+ | Code | Typical cause | What to do |
494
+ |------|---------------|------------|
495
+ | **400** | Invalid URL | Use `validate()`; check link format |
496
+ | **403** | Private account | Cannot extract without access |
497
+ | **404** | Deleted / wrong id / expired story | Verify URL in browser |
498
+ | **429** | Rate limited | Slow down; reduce concurrency; wait |
499
+ | **500** | Parse/network failure | Retry; update package; report issue |
500
+ | **503** | `fastMode` budget exceeded | Retry after `retryAfterMs` or disable fast mode |
501
+ | **504** | Timeout | Increase `timeoutMs` |
502
+
503
+ | Symptom | Fix |
504
+ |---------|-----|
505
+ | Carousel returns 1 image | Set `cookies` or `sessionId` |
506
+ | Reel has no MP4 | Add session cookie |
507
+ | CLI `Unexpected token 'npx'` | Use `;` or two lines in PowerShell |
508
+ | `Invalid or unexpected token` on CLI | Run `npm run build`; use published version |
509
+ | Caption has weird dots/lines | Post captions are flattened to one line by design |
510
+ | 403 on CDN URL when downloading | Do not modify signed URL query string |
511
+
512
+ ---
513
+
514
+ ## Examples in this repo
515
+
516
+ | File | Description |
517
+ |------|-------------|
518
+ | [`examples/basic.mjs`](./examples/basic.mjs) | Minimal JSON dump |
519
+ | [`examples/bot-example.ts`](./examples/bot-example.ts) | Generic bot handler |
520
+ | [`examples/express-api.ts`](./examples/express-api.ts) | REST API with Express |
521
+ | [`examples/fastify-api.ts`](./examples/fastify-api.ts) | REST API with Fastify |
522
+ | [`examples/telegram-bot.ts`](./examples/telegram-bot.ts) | Telegram-style handler |
523
+ | [`examples/discord-bot.ts`](./examples/discord-bot.ts) | Discord-style handler |
524
+ | [`examples/cookie-generator.mjs`](./examples/cookie-generator.mjs) | Cookie helper notes |
525
+
526
+ Run locally after build:
527
+
528
+ ```bash
529
+ npm run build
530
+ node examples/basic.mjs "https://www.instagram.com/p/SHORTCODE/"
531
+ ```
532
+
533
+ **Live Instagram tests** are kept in a separate repo folder: `ultra-igdl-live-test` (not published to npm).
534
+
535
+ ---
536
+
537
+ ## Architecture
538
+
539
+ ```
540
+ src/
541
+ ├── core/ # downloader orchestration, cache, parser, extractor
542
+ ├── extractors/ # post, reel, story, highlight
543
+ ├── network/ # undici client, headers, retry, pool, Instagram API
544
+ ├── utils/ # captions, carousel, media quality, URLs
545
+ ├── cli/ # CLI entry (published as ultra-igdl bin)
546
+ └── types/ # TypeScript definitions
547
+ ```
548
+
549
+ **Extraction layers** (first useful result wins, posts scan multiple layers for carousels):
550
+
551
+ 1. Open Graph / meta tags
552
+ 2. Embedded `application/json` / script blobs
553
+ 3. `window.__additionalDataLoaded` / `_sharedData`
554
+ 4. Next.js `__NEXT_DATA__`
555
+ 5. GraphQL / CDN discovery in HTML
556
+ 6. Regex fallback
557
+
558
+ With **session**: parallel `media/info` API for posts (carousels), reels, stories, highlights.
559
+
560
+ ---
561
+
562
+ ## Development
563
+
564
+ ```bash
565
+ git clone https://github.com/your-username/ultra-igdl.git
566
+ cd ultra-igdl
567
+ npm install
568
+ npm run build
569
+ npm test
570
+ npm run test:coverage
571
+ npm run test:stress
572
+ ```
573
+
574
+ | Script | Purpose |
575
+ |--------|---------|
576
+ | `npm run build` | Compile ESM + CJS + CLI to `dist/` |
577
+ | `npm test` | Unit + integration tests (mocked HTTP; excludes stress) |
578
+ | `npm run cli -- "<url>" --json` | Run CLI from source tree |
579
+ | `npm run lint` | Typecheck |
580
+
581
+ ---
582
+
583
+ ## Publishing to npm
584
+
585
+ Maintainers:
586
+
587
+ ```bash
588
+ # 1. Login
589
+ npm login
590
+
591
+ # 2. Set author/repository in package.json (your GitHub username)
592
+
593
+ # 3. Dry run — only dist/, README, LICENSE should be listed
594
+ npm pack --dry-run
595
+
596
+ # 4. Publish (runs build + tests via prepublishOnly)
597
+ npm publish
598
+ ```
599
+
600
+ Consumers install with:
601
+
602
+ ```bash
603
+ npm install ultra-igdl
604
+ ```
605
+
606
+ **Before first publish:** change `repository`, `bugs`, and `homepage` in `package.json` from `your-username` to your real GitHub path.
607
+
608
+ ---
609
+
610
+ ## Legal & disclaimer
611
+
612
+ - This project is **not affiliated with Instagram / Meta**.
613
+ - You are responsible for complying with Instagram's Terms of Use and applicable laws.
614
+ - Only download content you have the right to access and use.
615
+ - Session cookies are credentials — treat them like passwords.
616
+ - CDN URLs are **signed** and expire; download promptly and do not strip query parameters.
617
+
618
+ ---
619
+
620
+ ## License
621
+
594
622
  [MIT](./LICENSE) © 2026 ultra-igdl contributors