@boruto_vk7/insta-fetcher
v0.2.3
Published
Cliente TypeScript para metadados do Instagram autenticado por cookie — versão corrigida para parecer um usuário de navegador real.
Downloads
571
Readme
@boruto_vk7/insta-fetcher — versão "navegador" (0.2.0)
Fork corrigido do pacote original, com foco em parecer um usuário real no navegador (anti-bloqueio/anti-fingerprint) — não apenas em "funcionar".
Cliente TypeScript para consultar metadados do Instagram usando
exclusivamente um cookie de sessão já existente. Esta versão não recebe
usuário, senha, getCookie() de login ou qualquer credencial: o cookie deve ser
obtido pelo próprio usuário (DevTools → Application → Cookies) e armazenado de
forma segura.
O que foi corrigido para parecer navegador
O pacote publicado (0.1.x) misturava sinais contraditórios que entregam "sou um bot de Node":
| Problema no original | Correção nesta versão |
| --- | --- |
| User-Agent de app móvel (iPhone/Android) em endpoints do frontend web (/graphql/query, /web/search/...) | Tudo em www.instagram.com usa um Chrome/Windows atual e coerente (UA + Sec-CH-UA + Sec-CH-UA-Platform + Sec-CH-UA-Mobile que batem entre si) |
| Chrome 125 de 2024 (UA e CH-UA não acompanhavam o sec-ch-ua) | Chrome 152 (stable de set/2026), tripla de Client Hints consistente |
| authority, origin e x-requested-with em toda requisição | Headers por tipo de requisição: GET XHR sem Origin (navegador só manda em POST/CORS), navegação HTML com Sec-Fetch-Dest: document, upload com app-id próprio |
| Sem Sec-Fetch-* nem Sec-CH-UA-* (impressão digital clássica de bot/axios) | Sec-Fetch-Site/Mode/Dest coerentes (same-origin/cors/empty) + Priority: u=1, i |
| Accept-Language: pt-BR... fixo, sem relação com a sessão | Accept-Language derivado do locale (configurável) |
| Sem X-ASBD-ID/X-Web-Session-ID (o frontend envia nos XHR do www) | Enviados nos XHR web (129477 + id de sessão aleatório por instância) |
| Sem Sec-CH-UA-* | Tríade de Client Hints incluída |
| Referer sempre https://www.instagram.com/ | Referer contextual: página do perfil, da story, do highlight, do post, de /reels/... como quem clica |
| Cookie sessionid=abc%3Adef era URL-decodificado antes de enviar | Valores enviados verbatim, como o navegador faz — decodificar altera o fio e pode invalidar a sessão |
| Ritmo de robô (chamadas em rajada) | Pacing opcional entre chamadas encadeadas (off/light/human ou intervalo custom) |
| Headers de app (i.instagram.com) usados contra sessão web e vice-versa sem critério | Dois perfis coerentes: web (Chrome/Windows × www) e android/iphone (app × i.instagram.com), nunca misturados na mesma chamada |
| Upload/publicação com data em UTC | Data/hora local (timezone_offset em segundos), como o app do usuário |
URLs auditadas ao vivo (0.2.2)
Auditoria método-a-método contra o Instagram real (sessão autenticada). As
rotas corrigidas foram validadas respondendo 200 com dados:
| Método | URL correta (host) | Status ao vivo |
| --- | --- | --- |
| fetchPost / fetchPostByMediaId | www/api/v1/media/{media_id}/info/ | ✅ |
| fetchPostByShortcode | converte shortcode→media_id e usa /media/{id}/info/ | ✅ (antes: rota /media/{shortcode}/info/ dava 400) |
| fetchUserV2 / getIdByUsername | www/api/v1/users/web_profile_info/?username= → fallback www/api/v1/web/search/topsearch/ | ✅ própria conta; terceiros limitados por IP (429/checkpoint) |
| fetchUserIDPostsV2 | www/api/v1/feed/user/{id}/ | ✅ |
| fetchStories / fetchUserIDStories | i.instagram.com/api/v1/feed/user/{id}/reel_media/ (app) | ✅ |
| fetchHighlights (tray) | www/api/v1/highlights/{id}/highlights_tray/ → fallback app | ✅ |
| fetchHighlights (mídia) | página HTML www/stories/highlights/{id}/ (extrai xdt_api__v1__feed__reels_media__connection) | ✅ (0.2.3: 210 mídias ao vivo) |
| fetchUserReel (aba Reels) | www/api/v1/clips/user/ → fallback doc_id → fallback feed filtrando clips | ✅ (0.2.3) |
| getReelData | página www/reel/{code}/ (navegação HTML) | ⚠️ login wall/recaptcha por IP |
| searchFollower/Following | www/api/v1/friendships/{id}/followers\|following/ | ✅ rota responde |
Notas do mundo real (não são bugs do pacote):
/api/v1/users/{username}/usernameinfo/(www e app) está descontinuada (volta 200 com corpo vazio/erro) — por isso o módulo não a usa./users/{id}/info/só traz corpo completo para a própria conta; para terceiros volta vazio (o módulo segue comweb_profile_info/topsearch).- Ids de highlight vêm como
highlight:12345…— o módulo remove o prefixo antes de pedir a mídia. web_profile_infode terceiros, HTML de perfil ereels_mediapodem cair em 429/checkpoint/recaptcha dependendo do IP e do volume — são limitações de ambiente, não de headers. Use com calma (pacing) e em IP residencial limpo.
O que mudou em 0.2.3 (pós-captcha)
- Mídia de highlights: o Instagram hoje carrega a mídia na página HTML
/stories/highlights/{id}/(JSONxdt_api__v1__feed__reels_media__connectioncom os itens completos). O pacote extrai esse JSON com parse balanceado — antes a rota/feed/reels_media/voltava vazia para highlights e o resultado erahighlights: []. Validado ao vivo: 7 destaques / 210 mídias com covers. - Cover dos destaques: lê
cover_media.cropped_image_version/full_image_version(shape real do tray). - Aba Reels (
fetchUserReel): agora tentaclips/user(XDT do frontend) → doc_id GraphQL (legado) → fallback filtrando os clips do feed — nunca mais devolve vazio por causa de um doc_id desatualizado (403). Validado ao vivo. - Perfil de terceiro: com a sessão limpa,
/users/{id}/info/volta a responder com corpo completo —fetchUserentrega bio + contagens + foto.
Stories corrigidos (0.2.1)
- Bug: o endpoint "web"
/api/v1/feed/reels_media/vinha retornandoreels_media: []mesmo quando o perfil tinha story ativo (rota morta para consulta por usuário). - Fix:
fetchStoriesusa o endpoint que o app realmente preenche —i.instagram.com/api/v1/feed/user/{id}/reel_media/— com impressão digital de app Android coerente. Funciona para qualquer perfil público (seguido ou não). - Novo método
fetchUserIDStories(userId)para quando a resolução de username estiver limitada na sessão mas o ID já for conhecido. - Highlights (
fetchHighlights) agora tentam web e caem para o app automaticamente (tray e mídia) se a rota web vier vazia.
Além do fingerprint
- Perfil agora usa
web_profile_info(/api/v1/users/web_profile_info/?username=…), o endpoint que o frontend React chama de verdade (antes:usernameinfode app). - Stories e highlights usam os fluxos do navegador:
/api/v1/feed/reels_media/e/api/v1/highlights/{id}/highlights_tray/. - Fallback automático: se uma rota
/api/v1/…do www responder 404/405 (rota removida pelo Instagram), a mesma chamada é repetida emi.instagram.comtrocando a impressão digital para Android — nunca mistura os dois perfis. - Captura de reel pela página HTML (
/reel/{code}/) mais robusta. - Retries com backoff com jitter e respeito ao
Retry-Afterdo 429; 401/403 não são re-tentados e geram mensagens claras (cookie expirado / checkpoint).
Instalação
Via arquivo local (pasta ou tarball desta versão corrigida):
npm install /caminho/para/insta-fetcher-fixed
# ou, mantendo o mesmo nome de pacote nos imports:
npm install "@boruto_vk7/insta-fetcher@file:/caminho/para/insta-fetcher-fixed.tgz"Uso
import { InstagramEngine } from '@boruto_vk7/insta-fetcher';
const instagram = new InstagramEngine({
cookiesFile: './cookies.txt', // export Netscape ou JSON ou header
pacing: 'light', // 'off' | 'light' | 'human' (+ pacingRange)
locale: 'en_US', // espelha no Accept-Language
timeoutMs: 20_000,
});
// API pública idêntica à versão 0.1.x:
const id = await instagram.getIdByUsername('instagram');
const post = await instagram.fetchPost('https://www.instagram.com/p/SHORTCODE/');
const posts = await instagram.fetchUserPostsV2('instagram');
const reels = await instagram.fetchUserReel('instagram');
const stories = await instagram.fetchStories('instagram');
const hl = await instagram.fetchHighlights('instagram');
const account = await instagram.accountInfo();IgApi, igApi e createInstagramClient continuam como aliases. Helpers de
cookie e de shortcode também.
Opções novas
| Opção | Padrão | Descrição |
| --- | --- | --- |
| surface | 'web' | web (navegador desktop) · android/iphone (app) |
| pacing | 'light' | ritmo entre chamadas: light (~120–450 ms), human (~700–2200 ms), off |
| pacingRange | – | intervalo próprio { minMs, maxMs } |
| acceptLanguage | derivado de locale | header Accept-Language |
| locale | 'en_US' | usado para derivar o Accept-Language |
| mobileFallback | true | repete rota www removida no host do app com perfil Android |
| appId / asbdId | do frontend | sobrescreve X-IG-App-ID / X-ASBD-ID |
| debug | false | logs de diagnóstico (nunca imprime o cookie) |
Avisos
- O Instagram muda endpoints, headers e respostas sem aviso. Rotas marcadas como
legadas (ex.:
fetchUserPosts) podem deixar de existir — prefira as variantesV2. - Use somente em contas e dados para os quais você tenha autorização. Este pacote não contorna CAPTCHA, checkpoint, desafios ou limites — e não deve ser usado para isso.
- Nunca publique cookies, não os coloque no Git nem em logs.
Build e testes
npm install
npm run typecheck
npm run build
npm testOs testes rodam contra um servidor HTTP local e verificam os headers reais
(UA, Client Hints, Sec-Fetch-*, ausência de Origin em GET, presença em POST,
referers, fallback de host) — ou seja, a "cara de navegador" fica travada por
testes, não só por boas intenções.
Rotas Express
O exemplo em examples/instagram.routes.ts (do upstream) não faz parte do pacote
publicado; se precisar, o padrão de uso continua o mesmo.
