Stalker akun Instagram (akun Public Only)
JavaScriptPublicby zx-apiOct 10, 2026, 11:45 AMExpires: Never224 views
1/**
2 * Stalker Instagram
3 * Source: https://igwatcher.com/
4 *
5 * Ngambil Info Akun Instagram Reels, Postingan, Story
6 * Khusus Akun Instagram Public No Privat
7 */
8
9
10/**
11 * Credit By Zx
12 * Sumber Kode: https://whatsapp.com/channel/0029VbDLqe7EquiSF4STU13o
13 * Note: Kalau Mau Di sher Lagi Minimal Credit atau sumber jangan di hapus dong
14 * Website React WhatsApp Gratis:
15 * https://react.v1.zfile.web.id/
16 */
17
18/**
19
20Yang Mau Beli Akun Netflix, Top-Up game, Sunt1k S0Smed
21Bisa Ke Zix Store.
22
23 https://zixstore.kiospremium.site/
24
25Terimakasih ๐๐
26*/
27
28const https = require('https');
29const crypto = require('crypto');
30const zlib = require('zlib');
31
32const BASE = 'https://igwatcher.com';
33
34const UA =
35 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Mobile Safari/537.36';
36
37const SIG_JS_VERSION = 478;
38
39let IGW_PT = '';
40
41function sleep(ms) {
42 return new Promise((resolve) => setTimeout(resolve, ms));
43}
44
45function normalizeUsername(raw) {
46 let s = String(raw || '').trim();
47
48 try {
49 if (/^https?:\/\//i.test(s)) {
50 const u = new URL(s);
51 if ((u.hostname || '').includes('instagram.com')) {
52 const parts = u.pathname.replace(/^\/+|\/+$/g, '').split('/');
53 if (parts[0] && parts[0].toLowerCase() === 'stories') {
54 s = parts[1] || '';
55 } else {
56 s = parts[0] || '';
57 }
58 }
59 }
60 } catch (err) {
61 }
62
63 if (s.startsWith('@')) s = s.slice(1);
64
65 s = s.toLowerCase().replace(/\/+$/g, '');
66
67 if (!/^[a-z0-9._]{1,30}$/.test(s) || /^[._]+$/.test(s)) {
68 throw new Error('Username tidak valid: ' + raw);
69 }
70
71 return s;
72}
73
74function canonicalize(urlObj) {
75 const ps = [];
76
77 for (const [k, v] of urlObj.searchParams.entries()) {
78 ps.push([k, v]);
79 }
80
81 ps.sort(function (a, b) {
82 if (a[0] === b[0]) {
83 if (a[1] < b[1]) return -1;
84 if (a[1] > b[1]) return 1;
85 return 0;
86 }
87
88 if (a[0] < b[0]) return -1;
89 if (a[0] > b[0]) return 1;
90 return 0;
91 });
92
93 const query = ps
94 .map((p) => {
95 return encodeURIComponent(p[0]) + '=' + encodeURIComponent(p[1]);
96 })
97 .join('&');
98
99 return urlObj.pathname + '?' + query;
100}
101
102function buildSignature(urlObj) {
103 if (!IGW_PT) {
104 throw new Error('IGW_PT belum di-set. Jalankan initToken() dulu.');
105 }
106
107 const ts = String(Date.now());
108 const canon = canonicalize(urlObj);
109
110 const payload = IGW_PT + '\n' + ts + '\n' + canon;
111
112 const s = crypto
113 .createHash('sha256')
114 .update(payload, 'utf8')
115 .digest('hex');
116
117 return `v=1;j=${SIG_JS_VERSION};t=${ts};p=${IGW_PT};s=${s}`;
118}
119
120function httpRequest(url, options, redirectCount) {
121 options = options || {};
122 redirectCount = redirectCount || 0;
123
124 return new Promise((resolve, reject) => {
125 let parsed;
126
127 try {
128 parsed = new URL(url);
129 } catch (err) {
130 reject(new Error('URL tidak valid: ' + url));
131 return;
132 }
133
134 const headers = Object.assign(
135 {
136 'User-Agent': UA,
137 'Accept': '*/*',
138 'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
139 'Accept-Encoding': 'identity',
140 'Referer': BASE + '/',
141 },
142 options.headers || {}
143 );
144
145 const reqOptions = {
146 protocol: parsed.protocol || 'https:',
147 hostname: parsed.hostname,
148 port: parsed.port || 443,
149 path: parsed.pathname + parsed.search,
150 method: options.method || 'GET',
151 headers: headers,
152 };
153
154 const req = https.request(reqOptions, function (res) {
155 if (
156 [301, 302, 303, 307, 308].includes(res.statusCode) &&
157 res.headers.location &&
158 redirectCount < 5
159 ) {
160 res.resume();
161 const nextUrl = new URL(res.headers.location, url).toString();
162 resolve(httpRequest(nextUrl, options, redirectCount + 1));
163 return;
164 }
165
166 const chunks = [];
167
168 res.on('data', function (chunk) {
169 chunks.push(chunk);
170 });
171
172 res.on('end', function () {
173 let buf = Buffer.concat(chunks);
174
175 const encoding = String(
176 res.headers['content-encoding'] || ''
177 ).toLowerCase();
178
179 try {
180 if (buf.length > 0) {
181 if (encoding.includes('gzip')) {
182 buf = zlib.gunzipSync(buf);
183 } else if (encoding.includes('br')) {
184 buf = zlib.brotliDecompressSync(buf);
185 } else if (encoding.includes('deflate')) {
186 try {
187 buf = zlib.inflateSync(buf);
188 } catch (err) {
189 buf = zlib.inflateRawSync(buf);
190 }
191 } else if (encoding.includes('zstd')) {
192 reject(
193 new Error(
194 'Response memakai zstd. Node bawaan belum tentu bisa decode zstd. Coba jalankan di Node versi lebih baru atau gunakan library HTTP lain.'
195 )
196 );
197 return;
198 }
199 }
200 } catch (err) {
201 reject(new Error('Gagal decode response: ' + err.message));
202 return;
203 }
204
205 resolve({
206 statusCode: res.statusCode,
207 headers: res.headers,
208 body: buf.toString('utf8'),
209 });
210 });
211 });
212
213 req.on('error', function (err) {
214 reject(err);
215 });
216
217 req.setTimeout(60000, function () {
218 req.destroy(new Error('Request timeout 60 detik'));
219 });
220
221 if (options.body) {
222 req.write(options.body);
223 }
224
225 req.end();
226 });
227}
228
229async function initToken(force) {
230 if (IGW_PT && !force) return IGW_PT;
231
232 const res = await httpRequest(BASE + '/', {
233 headers: {
234 Accept:
235 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
236 },
237 });
238
239 if (res.statusCode !== 200) {
240 throw new Error('Gagal membuka homepage igwatcher.com: HTTP ' + res.statusCode);
241 }
242
243 const m = res.body.match(/data-igw-pt\s*=\s*"([^"]+)"/i);
244
245 if (!m || !m[1]) {
246 throw new Error('data-igw-pt tidak ditemukan di HTML homepage.');
247 }
248
249 const pt = m[1];
250
251 // /^1\.\d{9,11}\.[0-9a-f]{32}$/
252 if (!/^1\.\d{9,11}\.[0-9a-f]{32}$/.test(pt)) {
253 throw new Error('Format data-igw-pt tidak dikenali: ' + pt);
254 }
255
256 IGW_PT = pt;
257
258 return IGW_PT;
259}
260
261async function apiGet(pathname, params) {
262 await initToken(false);
263
264 const url = new URL(pathname, BASE);
265
266 const keys = Object.keys(params || {}).sort();
267
268 for (const key of keys) {
269 const val = params[key];
270 if (val === undefined || val === null) continue;
271 url.searchParams.append(key, String(val));
272 }
273
274 const sig = buildSignature(url);
275
276 const res = await httpRequest(url.toString(), {
277 headers: {
278 'X-IGW-Sig': sig,
279 'X-IGW-TS': 'e=timeout',
280 Accept: 'application/json, text/plain, */*',
281 },
282 });
283
284 let json = null;
285
286 try {
287 json = JSON.parse(res.body);
288 } catch (err) {
289 json = null;
290 }
291
292 if (res.statusCode !== 200) {
293 let msg = 'HTTP ' + res.statusCode;
294
295 if (json && json.message) {
296 msg += ' | ' + json.message;
297 } else if (json && json.note) {
298 msg += ' | ' + json.note;
299 } else {
300 msg += ' | ' + res.body.slice(0, 300);
301 }
302
303 throw new Error(msg);
304 }
305
306 if (!json) {
307 throw new Error(
308 'Response bukan JSON dari ' + pathname + ': ' + res.body.slice(0, 300)
309 );
310 }
311
312 if (json.status && json.status !== 'success') {
313 throw new Error(
314 'API error: ' + (json.message || json.note || JSON.stringify(json).slice(0, 300))
315 );
316 }
317
318 return json;
319}
320
321function getItems(resp) {
322 if (!resp) return [];
323 return resp.data || resp.items || resp.reels || [];
324}
325
326async function stalkerig(username) {
327 username = normalizeUsername(username);
328
329 await initToken(false);
330
331 const errors = [];
332
333 async function safeCall(type, fn) {
334 try {
335 return await fn();
336 } catch (err) {
337 errors.push({
338 type: type,
339 message: err.message,
340 });
341 return null;
342 }
343 }
344
345 const search = await safeCall('search', function () {
346 return apiGet('/wp-json/igw/v1/search', {
347 username: username,
348 });
349 });
350
351 if (!search) {
352 const errMsg =
353 errors.find((e) => e.type === 'search')?.message ||
354 'Gagal mengambil data profil.';
355 throw new Error(errMsg);
356 }
357
358 const user =
359 search && search.data && search.data.user ? search.data.user : null;
360
361 if (!user || !user.username) {
362 throw new Error(
363 'Profil tidak ditemukan atau unavailable. note=' +
364 (search.note || 'unknown')
365 );
366 }
367
368 const result = {
369 username: user.username || username,
370 full_name: user.full_name || '',
371 is_private: Boolean(user.is_private),
372 is_verified: Boolean(user.is_verified),
373 biography: user.biography || '',
374 external_url: user.external_url || '',
375 profile_pic_url: user.profile_pic_url || '',
376 followers:
377 user.follower_count != null
378 ? user.follower_count
379 : user.edge_followed_by && user.edge_followed_by.count != null
380 ? user.edge_followed_by.count
381 : null,
382 following:
383 user.following_count != null
384 ? user.following_count
385 : user.edge_follow && user.edge_follow.count != null
386 ? user.edge_follow.count
387 : null,
388 posts_count:
389 user.edge_owner_to_timeline_media &&
390 user.edge_owner_to_timeline_media.count != null
391 ? user.edge_owner_to_timeline_media.count
392 : null,
393 latest_reel_media: user.latest_reel_media || null,
394 scraped_at: new Date().toISOString(),
395 media: {
396 stories: [],
397 reels: [],
398 posts: [],
399 highlights: [],
400 tagged: [],
401 },
402 meta: {
403 stories_total: null,
404 reels_total: null,
405 posts_total: null,
406 highlights_total: null,
407 tagged_total: null,
408 posts_has_more: false,
409 reels_has_more: false,
410 tagged_has_more: false,
411 },
412 profile_raw: user,
413 errors: errors,
414 };
415
416 if (result.is_private) {
417 result.errors.push({
418 type: 'private',
419 message: 'Akun private. Media tidak diambil.',
420 });
421
422 return result;
423 }
424
425 await sleep(1200);
426
427 const stories = await safeCall('stories', function () {
428 return apiGet('/wp-json/igw/v1/stories', {
429 username: username,
430 });
431 });
432
433 if (stories) {
434 result.media.stories = getItems(stories);
435 result.meta.stories_total =
436 stories.total != null ? stories.total : result.media.stories.length;
437 }
438
439 await sleep(1200);
440
441 const reels = await safeCall('reels', function () {
442 return apiGet('/api/reels', {
443 username: username,
444 limit: 24,
445 lazy: 1,
446 });
447 });
448
449 if (reels) {
450 result.media.reels = getItems(reels);
451 result.meta.reels_total =
452 reels.total != null ? reels.total : result.media.reels.length;
453 result.meta.reels_has_more = Boolean(reels.has_more);
454 }
455
456 await sleep(1200);
457
458 const posts = await safeCall('posts', function () {
459 return apiGet('/wp-json/igw/v1/posts', {
460 username: username,
461 limit: 24,
462 lazy: 1,
463 });
464 });
465
466 if (posts) {
467 result.media.posts = getItems(posts);
468 result.meta.posts_total =
469 posts.total != null ? posts.total : result.media.posts.length;
470 result.meta.posts_has_more = Boolean(posts.has_more);
471 }
472
473 await sleep(1200);
474
475 const highlights = await safeCall('highlights', function () {
476 return apiGet('/wp-json/igw/v1/highlights', {
477 username: username,
478 });
479 });
480
481 if (highlights) {
482 result.media.highlights = getItems(highlights);
483 result.meta.highlights_total =
484 highlights.total != null
485 ? highlights.total
486 : result.media.highlights.length;
487 }
488
489 await sleep(1200);
490
491 const tagged = await safeCall('tagged', function () {
492 return apiGet('/wp-json/igw/v1/tagged', {
493 username: username,
494 limit: 24,
495 });
496 });
497
498 if (tagged) {
499 result.media.tagged = getItems(tagged);
500 result.meta.tagged_total =
501 tagged.total != null ? tagged.total : result.media.tagged.length;
502 result.meta.tagged_has_more = Boolean(tagged.has_more);
503 }
504
505 return result;
506}
507
508module.exports = stalkerig;
509module.exports.stalkerig = stalkerig;
510
511/**
512 * CLI:
513 * node index.js username
514 */
515
516
517/**
518if (require.main === module) {
519 const username = process.argv[2];
520
521 if (!username) {
522 console.error('Usage: node index.js <username>');
523 console.error('Example: node index.js iniipasya__');
524 process.exit(1);
525 }
526
527 stalkerig(username)
528 .then((data) => {
529 console.log(JSON.stringify(data, null, 2));
530 })
531 .catch((err) => {
532 console.error('ERROR:', err.message);
533 process.exit(1);
534 });
535}
536**/536 linesยท12,490 charsยท12.2 KB
WwrapยทFfullscreen