npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luisurrutia/gram

v0.1.0

Published

TypeScript ESM CLI for working with the Instagram account you are already logged into

Downloads

89

Readme

Gram

Gram is a TypeScript ESM CLI for working with the Instagram account you are already logged into. It can show account details, list relationships, list post likers, read the home timeline, inspect one post or reel, read media comments and replies, manage blocked accounts, read or set a Note, and update the profile bio.

The package is @luisurrutia/gram and requires Node >=22. When installed or built from this repo, it exposes the gram bin from dist/index.js.

What it does

  • Reads the logged-in account with whoami.
  • Lists following and followers for the current account or a target user.
  • Lists accounts that liked one Instagram post.
  • Prints safe fields from the logged-in home timeline.
  • Prints safe details for one Instagram post or reel.
  • Prints safe fields from a media comments page.
  • Prints safe fields from comment replies on a media comment.
  • Lists blocked accounts for the logged-in user.
  • Reads the current Instagram Note and sets an Instagram Note, with --dry-run available for set previews.
  • Updates the profile bio, blocks users, and unblocks users only after --yes confirmation.
  • Loads cookies from Chrome, Arc, Brave, Safari, Firefox, a manual Cookie header, an environment variable, or saved config.

Run and build

Run Gram without a global install:

npx @luisurrutia/gram --help
# or
bunx @luisurrutia/gram --help

The package exposes a single gram bin, so package runners invoke the CLI directly.

Or install and run it from a checkout.

pnpm install --frozen-lockfile
pnpm run build

After a build, run the compiled CLI directly:

node dist/index.js help
node dist/index.js whoami --browser chrome

During development, run the source entry with pnpm run dev --:

pnpm run dev -- help
pnpm run dev -- note set "gm" --browser chrome --dry-run

The examples below use gram because that is the bin name after the package is built and linked or installed from this repo.

Publishing

@luisurrutia/gram is published from .github/workflows/publish-npm.yml with npm Trusted Publishing. Configure the package on npmjs.com with these Trusted Publisher fields:

  • Publisher: GitHub Actions
  • Organization/user: LuisUrrutia
  • Repository: gram
  • Workflow filename: publish-npm.yml
  • Environment name: leave empty unless the workflow gains a matching GitHub environment
  • Allowed action: npm publish

The workflow publishes with GitHub OIDC, so it does not need an NPM_TOKEN secret. Create a GitHub release whose tag matches package.json as vX.Y.Z; the release workflow validates, packs, and publishes that exact tag.

Safety and privacy

  • gram note is read-only and prints only the current Note text plus created timestamp/date when present.
  • gram note set sends a live mutation by default. Use --dry-run first unless you already mean to update the Note.
  • gram profile bio set, gram blocked block, and gram blocked unblock require --yes.
  • Read-only commands are whoami, following, followers, likers, timeline, post, comments, replies, note, and blocked list.
  • blocked list is read-only, but it still makes authenticated private-web requests.
  • Gram does not print raw cookies, session IDs, CSRF tokens, LSD tokens, fb_dtsg, jazoest, email, phone number, profile image URLs, raw response JSON, or raw private-web payloads.
  • gram comments reads comment and caption text plus safe identity and pagination fields only; it does not fetch child comments or print private-web payloads.
  • gram comments --all follows headload and tail cursors until comments are exhausted and ignores --limit as the stop condition.
  • gram replies reads safe parent comment and reply fields from the child comments endpoint only; it does not fetch deeper nested replies or print private-web payloads.
  • Output keeps safe identity fields such as username, display name, user ID, and private or verified markers.
  • Treat --verbose, --media-links, and live cursor output as sensitive enough that you should not share it casually.

Use Gram only with accounts you control, and assume private-web behavior can change without notice.

Quick Start

Save a cookie source, then check which account Gram can see:

gram setup --browser chrome
gram whoami

Read a Note, or preview a Note change without sending it:

gram note
gram note set "gm" --dry-run

Read relationship, liker, or timeline data:

gram following -n 20
gram followers --user <handle> -n 20
gram likers https://www.instagram.com/p/DYj22UUMMYZ/ -n 20
gram timeline -n 20
gram post <shortcode-or-url>
gram comments <media-id|post-url|shortcode> -n 20
gram comments <media-id|post-url|shortcode> --all
gram replies <media-id|post-url|shortcode> <comment-id> -n 20

See blocked accounts:

gram blocked list

Common Workflows

Set up a browser cookie source once:

gram setup
gram setup --browser chrome --profile "Default"

Inspect the current account and its relationships:

gram whoami
gram following -n 50
gram followers --user <id-or-handle> -n 50

Inspect accounts that liked one Instagram post:

gram likers DYj22UUMMYZ -n 20

Read the home timeline, then continue with the cursor Gram prints when another page is available:

gram timeline -n 20
gram timeline --after '<cursor-from-previous-output>'

Inspect one post or reel without printing media CDN URLs by default:

gram post <shortcode-or-url>
gram post https://www.instagram.com/reel/<shortcode>/ --media-links

Read comments for a media id, post URL, or shortcode, then continue with the cursor Gram prints when another page is available:

gram comments https://www.instagram.com/p/<shortcode>/ -n 20
gram comments <media-id> --min-id '<cursor-from-previous-output>'
gram comments <media-id> --max-id '<cursor-from-previous-output>'
gram comments <media-id> --all --page-size 50

Read replies for a parent comment, then continue with the cursor Gram prints when another page is available:

gram replies https://www.instagram.com/p/<shortcode>/ <comment-id> -n 20
gram replies <media-id> <comment-id> --min-id '<cursor-from-previous-output>'
gram replies <media-id> <comment-id> --all --page-size 50

Read the current Note, then preview changes first. Remove --dry-run only when you mean to update the live Instagram Note:

gram note
gram note set "working on it" --dry-run

Run confirmed account changes only when you intend to mutate the logged-in account:

gram profile bio set "new bio text" --yes
gram blocked block <id-or-handle> --yes
gram blocked unblock <id-or-handle> --yes

Command Reference

gram setup [options]
gram whoami [options]
gram following [options]
gram followers [options]
gram likers <post-url-or-shortcode> [options]
gram timeline [options]
gram post <shortcode-or-url> [options]
gram comments <media-id|post-url|shortcode> [options]
gram replies <media-id|post-url|shortcode> <comment-id> [options]
gram note [options]
gram note set <text> [options]
gram profile bio set <text> --yes [options]
gram blocked list [options]
gram blocked block <id|handle> --yes [options]
gram blocked unblock <id|handle> --yes [options]
gram help [command]

gram setup

Detects a usable Instagram cookie source, validates it with a non-mutating whoami request, and saves cookie-source metadata. It does not save raw cookies or web tokens.

Useful options:

  • --browser <chrome|arc|brave|safari|firefox>
  • --profile <name>

gram whoami

Shows the logged-in Instagram account using non-mutating requests. It requires cookies containing at least sessionid.

Useful options:

  • --browser <chrome|arc|brave|safari|firefox>
  • --profile <name>
  • --cookie-header <header>
  • --user-agent <ua>

gram following and gram followers

Lists accounts a target user follows, or accounts following a target user. If --user is omitted, Gram uses ds_user_id from cookies. Numeric IDs are used directly. Handles, with or without @, are resolved first.

Useful options:

  • --user <id|handle>
  • -n, --limit <count> from 1 to 100, default 20
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram likers

Lists accounts that liked one Instagram post using authenticated, read-only Instagram /api/graphql doc_id requests. It requires cookies containing sessionid; csrftoken, LSD, fb_dtsg, and jazoest are sent when available.

Useful options:

  • -n, --limit <count> from 1 to 100, default 20; caps displayed rows unless --all is used
  • --all requests the current doc_id likers response once and prints every returned liker
  • --after <cursor> is accepted for parser compatibility but currently unsupported because this doc_id has no verified cursor
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

The positional post reference can be a canonical Instagram /p/, /reel/, or /tv/ URL, a path such as /reel/<shortcode>/, or a bare shortcode. Long share-style tokens inside supported Instagram post URLs are normalized to the canonical shortcode prefix; bare long tokens are rejected before any network request. Gram resolves the shortcode to the numeric media PK locally and sends that PK as variables: { "id": "<media_pk>" } with doc_id 24452425501069647.

Output includes only safe liker identity fields: username, display/full name, user ID, and private or verified markers. It does not print the post URL, shortcode, media PK, raw cookies, tokens, profile image URLs, raw response JSON, email, phone number, or private-web payloads.

-n/--limit limits displayed likers from the current doc_id response unless --all is used. --all performs the same one-shot doc_id request and prints every parsed user returned by that response. --after still fails with a sanitized unsupported-pagination error because no verified cursor field exists for this doc_id. The older query-hash edge_liked_by transport and REST follow_ranking_token pagination are not used.

gram timeline

Lists safe fields from the logged-in home timeline. By default it hides raw media IDs and media CDN URLs. If another page is available, Gram prints a follow-up gram timeline --after ... command.

Useful options:

  • -n, --limit <count> from 1 to 100, default 20
  • --after <cursor>
  • --doc-id <id>
  • --full-captions
  • --media-links
  • --verbose
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram post

Shows safe fields for one Instagram post or reel. It accepts a raw shortcode or an Instagram URL with /p/, /reel/, /reels/, or /tv/; query strings and hashes are ignored. By default it hides raw media IDs and media CDN URLs.

Useful options:

  • --doc-id <id>
  • --full-caption
  • --media-links
  • --verbose
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram comments

Lists safe fields from an Instagram media comments page using read-only comments requests. The target can be a numeric media ID, a bare shortcode, or an Instagram /p/, /reel/, or /tv/ URL. Shortcodes and post URLs resolve locally before fetching comments. If another page is available, Gram prints a follow-up gram comments <media-id> --min-id ... or --max-id ... command. With --all, Gram keeps following headload and tail cursors until comments are exhausted and ignores --limit as the stop condition.

Useful options:

  • -n, --limit <count> from 1 to 100, default 20
  • --all
  • --page-size <count> from 1 to 100, default 12, or 50 with --all
  • --min-id <cursor>
  • --max-id <cursor>
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram replies

Lists safe fields from a media comment's replies using read-only child comments requests. The target can be a numeric media ID, a bare shortcode, or an Instagram /p/, /reel/, or /tv/ URL. The second argument is the parent comment ID. Shortcodes and post URLs resolve locally before fetching replies. If another page is available, Gram prints a follow-up gram replies <media-id> <comment-id> --min-id ... command. With --all, Gram keeps following head child cursors until replies are exhausted and ignores --limit as the stop condition.

Useful options:

  • -n, --limit <count> from 1 to 100, default 20
  • --all
  • --page-size <count> from 1 to 100, default 12, or 50 with --all
  • --min-id <cursor>
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram note

Shows the current Instagram Note. This command is read-only and uses ds_user_id from cookies as the target user id. Mutation options such as --dry-run, --actor-id, --doc-id, --lsd, --fb-dtsg, --jazoest, and --resolve-web-tokens are for gram note set only.

Useful options:

  • --browser <chrome|arc|brave|safari|firefox>
  • --profile <name>
  • --cookie-header <header>
  • --user-agent <ua>

Output includes only the note text and created timestamp/date when present. If no Note is present, Gram prints No current Instagram Note found. It never prints raw cookies, tokens, raw JSON, profile image URLs, or unrelated payload fields.

gram note set

Sets the active Instagram Note. This command sends a live mutation by default when valid credentials and tokens are available. Use --dry-run to preview without sending.

Useful options:

  • --dry-run
  • --browser <chrome|arc|brave|safari|firefox>
  • --profile <name>
  • --cookie-header <header>
  • --actor-id <id>
  • --doc-id <id>
  • --lsd <token>
  • --fb-dtsg <token>
  • --jazoest <token>
  • --resolve-web-tokens
  • --user-agent <ua>

Dry runs do not fetch Instagram home HTML or resolve web tokens. Live sends can discover missing web tokens before the mutation.

gram profile bio set

Updates the logged-in profile biography. This is a mutating command and requires --yes plus cookies containing sessionid and csrftoken.

Useful options:

  • --yes
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram blocked list

Lists blocked accounts for the logged-in user. This command is read-only, but it still makes authenticated private-web requests and requires cookies containing sessionid and csrftoken.

Useful options:

  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

gram blocked block and gram blocked unblock

Blocks or unblocks an Instagram user ID or handle. These are mutating commands and require --yes plus cookies containing sessionid and csrftoken.

Useful options:

  • --yes
  • Common cookie options such as --browser, --profile, --cookie-header, and --user-agent

Cookies and config

Gram can get cookies from these sources:

  • Browser cookies with --browser <chrome|arc|brave|safari|firefox>.
  • Browser profiles with --profile <name> where supported.
  • Manual cookies with --cookie-header <header>.
  • Manual cookies from INSTAGRAM_COOKIE_HEADER.
  • Saved config from gram setup.

Saved config lives at $XDG_CONFIG_HOME/gram/config.json. If XDG_CONFIG_HOME is not set, Gram uses ~/.config/gram/config.json.

The config stores cookie-source metadata, not raw cookies:

{
  "cookies": {
    "browser": "chrome",
    "profile": "Default"
  }
}

Cookie source precedence is:

  1. --cookie-header
  2. INSTAGRAM_COOKIE_HEADER
  3. Explicit browser flags such as --browser and --profile
  4. Saved user config
  5. An error asking you to pass cookies, choose a browser source, or run gram setup

Development and validation

Useful local checks:

pnpm run format:check
pnpm run typecheck
pnpm test
pnpm run build
node dist/index.js --help
node dist/index.js help whoami
node dist/index.js help likers
node dist/index.js note set "hello" --cookie-header "csrftoken=fake-csrf; ds_user_id=12345; sessionid=fake-session" --lsd fake-lsd --dry-run

Do not validate gram note set without --dry-run unless you intend to update the live Instagram Note. Do not live-validate profile bio set, blocked block, or blocked unblock unless you intend to mutate the logged-in account. Avoid casual live validation of blocked list, likers, comments, or replies; they are read-only, but they still use authenticated private-web requests and produce account data.

Technical docs

Implementation details, request flows, parser notes, and lower-level protocol behavior belong in docs/README.md.