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

instagram-caption

v0.1.0

Published

Resolve the author and caption of a public Instagram post, with no credentials

Readme

instagram-caption

Resolve the author and caption of a public Instagram post. No credentials, no dependencies, no browser.

Why this exists

An anonymous request to an Instagram page returns no og:title and no og:description - only og:site_name, which is always just "Instagram". That is why link savers, read-later apps and RSS pipelines show Instagram links titled "Instagram" and nothing else. No amount of Puppeteer, user-agent or timeout tuning fixes it: the data is not on the page.

It is on the public embed endpoint, and this package reads it.

Install

npm install instagram-caption

Requires Node.js 24 or later. The published JavaScript itself needs nothing newer than Node 18, but the floor has not been tested below 24, and this package does not claim support it has not measured.

TypeScript consumers need ambient fetch types, which means @types/node for Node or "lib": ["dom"] for the browser. The package's Fetcher type is typeof fetch, so a project with neither will not compile against it.

Use

import { resolve } from "instagram-caption";

const outcome = await resolve("https://www.instagram.com/p/DTyxjPyAa18/");

switch (outcome.kind) {
  case "found":         console.log(outcome.author, outcome.caption); break;
  case "gone":          console.log("the post was removed"); break;
  case "unknown":       console.log("the page arrived but did not parse:", outcome.reason); break;
  case "unavailable":   console.log("could not fetch it; retryable:", outcome.retryable); break;
  case "not-instagram": console.log("not an Instagram post URL"); break;
}

Five outcomes, because each one calls for a different action. unknown and unavailable are deliberately separate: the first means the page arrived and was not understood, which is evidence the page shape may have changed; the second means no page arrived at all.

From the command line

$ npx instagram-caption https://www.instagram.com/p/DTyxjPyAa18/
{"url":"https://www.instagram.com/p/DTyxjPyAa18/","kind":"found","author":"astronautgio","caption":"..."}

One JSON object per line, in input order. Reads URLs from arguments or stdin. Exit code is 0 when every URL produced an outcome, 1 when at least one was retryably unavailable, 2 on a usage error.

Identify yourself

The default User-Agent names this package. If you set your own, name your own client:

await resolve(url, { userAgent: "my-reader/2.1 (+https://example.com)" });

A User-Agent naming a known browser family with a version token is refused with an error, on purpose. Instagram serves those a JavaScript app shell instead of the rendered embed, and the shell does not fail - it parses as unknown for every post. Refusing up front beats resolving nothing forever.

What it does not do

It does not download media, does not archive content, and uses no Instagram credentials. It reads the same public embed endpoint any website uses to show an embedded post, so it can never resolve a private or age-restricted post. Which outcome such a post produces has not been tested against a real private account, so this README does not claim one - do not assume it is unknown rather than gone.

Rate limiting is your responsibility. The CLI pauses 1.5s between requests; the library does not pause at all, because it does not know what else you are doing.

License

MIT