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

@michaelkory/notebooklm

v1.3.0

Published

CDP-native NotebookLM client: build & query notebooks from YouTube channels/playlists/search, a person's interviews, cross-creator topics, blogs & LinkedIn — via a logged-in Chrome bridge (bun, zero runtime deps)

Readme

@michaelkory/notebooklm

A bun CLI (zero runtime deps) that builds and queries Google NotebookLM notebooks programmatically. It drives NotebookLM over raw Chrome DevTools Protocol against a Chrome you're already signed into — no API key, no extension, no reimplemented auth. The in-page calls inherit your existing session.

Build notebooks from a YouTube channel, playlist, or search; from a person's teaching videos + interviews; from a cross-creator topic; from blogs; or from LinkedIn articles. Discover the directory channels and experts behind a niche, subscribe to channels, mine your watch history, and ask grounded, citation-backed questions.

⚠️ Unofficial. This automates NotebookLM's private web backend from your own logged-in session. Keep volume human-scale; everything depends on the one signed-in tab. Not affiliated with Google. (LinkedIn/YouTube scraping is likewise ToS-sensitive — go gently.)

Install

bunx @michaelkory/notebooklm <command>      # no install
bun add -g @michaelkory/notebooklm          # or: global `notebooklm` binary

Prerequisites

  • bun installed (runs the TypeScript directly).
  • A logged-in NotebookLM Chrome reachable over CDP — default http://127.0.0.1:9224 (override with NBLM_CDP). For LinkedIn/YouTube features that Chrome should also be signed into those.
  • list is the health check — if it errors with "no CSRF token" or a connection failure, open/sign into NotebookLM in that Chrome.

Commands

Harvest / inspect (read-only — return data, create nothing)

| Command | Action | |---|---| | list | Notebooks [{id,title,emoji,source_count}] — also the health check. | | harvest <channel> [maxScrolls] | A channel's videos (handle/URL/id) + duration/views/age. | | harvest-playlist <playlistUrl> [maxScrolls] | A playlist's videos, in order. | | harvest-search <query…> | YouTube search results (title/duration/views/channel). | | harvest-person <name> [ownChannelHandle] | A person's teaching videos (own channel + interviews, filtered). | | harvest-blog <rootUrl> [limit] | Article URLs from a site (sitemap → RSS fallback). | | harvest-linkedin <profileUrl> | A LinkedIn profile's articles → text cached as markdown. | | history <takeout.zip\|watch-history.json> [sinceISO] | Your watch history → channels ranked by views (music filtered). | | caption-check <videoUrl…> | Whether each video has captions. |

Build notebooks (always create new; record a manifest)

| Command | Action | |---|---| | build <label> <channel> [maxScrolls] [filters] | From a channel. | | build-urls <label> <url…> | From explicit URLs. | | build-directory <label> <channelNameOrHandle> [maxScrolls] | Resolve real channel → harvest → drop Shorts → 300 most-recent. | | build-person <label> <name> [ownChannelHandle] | A person's teaching corpus. | | build-topic <label> '<q1\|q2\|…>' | Cross-creator topic (teaching-filtered, \|-separated queries). | | build-linkedin <label> <profileUrl> | LinkedIn articles → pasted-text sources. |

build filters: --limit N --min-duration SEC --max-age-months M --min-views N --include kw,kw --exclude kw,kw

Discover / curate

| Command | Action | |---|---| | find-directories <seed…> | Rank channels by how many of your seed people they host (interview directories). | | person-hosts <name> [ownChannelHandle] | The channels that host a given person. | | find-experts <topic> <notebookId…> | Ask each notebook who the topic's experts are → per-notebook answers + citations. | | subscribe <name\|handle…> | Subscribe to a channel (resolver-guarded). Unsubscribe must be done manually — YouTube needs a real click. | | delete-notebook <id…> | PERMANENTLY delete notebooks (no undo). | | ask <notebookId> <question…> | Grounded answer → {answer, citations}. |

bunx @michaelkory/notebooklm build-directory "My First Million" "My First Million"
bunx @michaelkory/notebooklm find-directories "Alex Hormozi" "Rob Walling" "Dan Koe"
bunx @michaelkory/notebooklm find-experts "first 100 SaaS customers" <nbId1> <nbId2> …
bunx @michaelkory/notebooklm build-linkedin "Justin Welsh" https://www.linkedin.com/in/justinwelsh/

Configuration

| Env var | Default | Purpose | |---|---|---| | NBLM_CDP | http://127.0.0.1:9224 | CDP endpoint of your logged-in Chrome. | | NBLM_NOTEBOOKS_DIR | ~/projects/ideacode/Atlas/NotebookLM | Manifests, per-notebook markdown notes, and the LinkedIn text cache (sources/linkedin/). |

How it picks sources (the curation model)

  • Teaching density over views. Ranking favors instructional content (how-to / framework / playbook / teardown), not popularity; views are at most a tiebreak, never a gate.
  • Own-channel-first for teachers; search for the channel-less. A teacher's lessons live on their channel; people like Seth Godin / Justin Welsh live in others' interviews + their writing — so person/topic notebooks pull from search and LinkedIn too.
  • Directories = multi-guest interview shows, found by who repeatedly hosts your seeds.
  • Channel resolution is squatter-guardedresolveChannel requires ≥5k subs + a distinctive-name match and picks the highest-sub result, so a 3-video imposter can't slip in.
  • NotebookLM cap: 300 sources / notebook. build-directory takes the 300 most-recent long-form videos. NotebookLM does not reject captionless videos (verified).

Notes

  • Always creates NEW notebooks — no get-or-create matching.
  • Builds record a canonical manifest.json (keyed by notebook id) + a per-notebook markdown note — handy for an Obsidian vault.
  • LinkedIn URLs can't be ingested by NotebookLM directly (auth wall), so build-linkedin scrapes the text via your session, caches it as markdown, and adds it as pasted text.
  • Runtime: bun only (raw CDP over bun's native WebSocket; no Playwright, no Node).
  • Maintainer release steps: see PUBLISHING.md.