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

seomatic

v0.3.0

Published

SEO + agent-readiness audits from your terminal, and the full SEOmatic API - Search Console data, insights, and every agent tool - for scripts and coding agents.

Readme

seomatic

SEO and agent-readiness audits from your terminal, plus the full SEOmatic API - Search Console data, insights, and every agent tool - for scripts and coding agents.

No install, zero dependencies, Node >= 18.

npx seomatic audit https://example.com

Two commands (audit, logs) need no account and no key. For everything else, run seomatic login once: it opens your browser, you approve, and the key comes back to the terminal.

Contents

Quick start

# 1. Audit any URL. No account.
npx seomatic audit https://example.com

# 2. Find crawl-budget waste in a server log. No account.
npx seomatic logs /var/log/nginx/access.log

# 3. Sign in (creates a free account if you have none), then read your
#    Search Console data.
npx seomatic login
npx seomatic gsc top-queries --days 28

Commands

Notation: <required>, [optional], a|b alternatives.


seomatic audit <url>

Auth: none. Cost: free.

Fetches one URL and runs 10 checks (11 when the site has a robots.txt) covering both classic SEO and whether an AI answer engine can read the page.

npx seomatic audit https://example.com
npx seomatic audit https://example.com --json

Scored checks: reachable, title, meta_description, canonical, h1, json_ld, robots_txt, ai_bots_allowed (only when robots.txt exists), sitemap.

ai_bots_allowed fails only when an AI search crawler is blocked (OAI-SearchBot, Claude-SearchBot, PerplexityBot). A blocked training crawler (GPTBot, ClaudeBot, Google-Extended) is noted in detail but does not fail: it keeps content out of model training, not out of AI search.

Shown but not scored ("scored": false): llms_txt (optional; no measured effect on AI citations) and security_txt.

{
  "url": "https://example.com",
  "score": 30,
  "passed": 3,
  "total": 10,
  "checks": [{ "id": "reachable", "ok": true, "detail": "HTTP 200 in 133ms" }]
}

score is passed / total over the scored checks, as a percentage. Exit is 0 even when checks fail - a failing check is a finding, not a CLI error. Branch on score or passed, not on the exit code. See Scripting recipes for a CI gate.


seomatic logs <file>|-

Auth: none. Cost: free.

Parses a combined-format access log and reports what crawlers actually fetched, which is the only direct evidence of how your crawl budget is spent. Pass - to read stdin.

npx seomatic logs access.log
zcat access.log.*.gz | npx seomatic logs -
npx seomatic logs access.log --json

Bots are identified by user agent, so the log must include the UA field (the last quoted field in combined format). A log without user agents parses cleanly and reports zero bots.

seomatic logs  (3 lines parsed, 0 skipped)
bots: 100% of traffic (3/3)  AI bots: 33% (1)

Googlebot  2 hits, 2 paths, 50% wasted (4xx/5xx)
        1  /a
        1  /b
OAI-SearchBot [AI]  1 hits, 1 paths, 0% wasted (4xx/5xx)

--json returns { lines, totals, bots[] }, where each bot carries isAiBot, hits, uniquePaths, statuses, wastedCrawlPct and topPaths. wastedCrawlPct is the share of that bot's requests answered 4xx or 5xx: crawl budget spent on nothing.


seomatic login

Opens your browser on SEOmatic's approval screen. Sign in (or create a free account), pick the workspace, approve, and the key lands in your terminal. No copying from the dashboard.

  • Picking a workspace needs the admin role there, the same right as creating a key in Settings. The screen only lists workspaces you administer.
  • The key is kept in the OS credential store: the macOS Keychain, the Linux keyring (GNOME Keyring / KWallet, when a desktop session is running), or encrypted with Windows DPAPI to your Windows account. Where none is available (a bare server) it goes to ~/.config/seomatic/credentials.json ($XDG_CONFIG_HOME and %APPDATA% are respected), readable only by you. seomatic me says which (--json: cli.key_storage). If the OS store is locked (a Mac keychain over SSH), commands say so (KEYRING_LOCKED) instead of claiming you are signed out. SEOMATIC_KEYRING=file always uses the file.
  • It is valid for one year and shows in Settings -> AI Agents -> API Keys as OAuth: SEOmatic CLI (<computer name>). Each computer gets its own key; logging in again on the same one replaces it.
  • On a server, over SSH, or in a container, seomatic login --device prints a short code (BCDF-GHJK) and a link. Open the link on any computer or phone, sign in, type the code, and approve; the terminal picks the key up within seconds. It is chosen automatically over SSH and on Linux with no display (--browser forces the browser flow). Codes last 10 minutes and work once. Only type a code that your own terminal showed: SEOmatic never sends anyone a sign-in code.
  • --no-browser prints the browser link instead of opening it. That link must be opened on the same computer, because the approval hands the key back to a listener on 127.0.0.1; elsewhere, use --device.
  • login refuses to run in CI (CI set): use SEOMATIC_API_KEY there.

seomatic logout

Revokes the saved key on SEOmatic and removes it from this computer. If SEOmatic cannot be reached, the local copy is still removed and the command tells you to revoke the key in Settings.

seomatic me

Auth: key. Introspects the key: workspace, scopes, what the plan allows (acting over the API, webhooks, Zapier), GSC connection, and where the key came from. Run it first when something is not working. whoami is an alias.

npx seomatic me --json

seomatic gsc top-queries|top-pages

Auth: key, scope read:gsc. Reads the workspace's connected Search Console property. Data is Google-finalized with a 2-3 day lag.

npx seomatic gsc top-queries --days 28 --limit 25
npx seomatic gsc top-pages --days 7 --json

--days defaults to 28, --limit to 25.


seomatic tools [list]

Auth: key. Lists every tool this key can call, which depends on its scopes, plan and connections. --group read|acts filters read-only from acting tools.

npx seomatic tools
npx seomatic tools --group read --json

seomatic tools describe <name>

Auth: key. Shows one tool's description and parameters (? marks optional ones). --json prints the full JSON Schema.

npx seomatic tools describe get_search_queries

seomatic tools call <name> [--data '<json>' | @file.json | -]

Auth: key. Invokes any tool by name, proxying POST /v1/tools/{name}. This is the whole product surface: every keyword, backlink, SERP, analytics, task and campaign tool, identical to what REST and MCP expose.

npx seomatic tools call get_search_queries --data '{"days":28}'
npx seomatic tools call create_seo_tasks --data @tasks.json --json
echo '{"days":7}' | npx seomatic tools call get_search_queries --data -

--data takes inline JSON, @path to read a file (no shell quoting, and the argument stays out of the process list), or - for stdin. It must be a JSON object. Without --json the tool's result is printed as formatted JSON; with --json the raw envelope { "tool", "result" } is printed, where result is the tool's answer as a string.

Run seomatic tools for the list and seomatic tools describe <name> for a tool's arguments. Acting tools need the agents:act scope and the Infrastructure plan.

Tool calls are idempotent. Every tools call carries an Idempotency-Key, so an acting tool (one that stages changes) runs at most once however often the call is repeated. That makes the dangerous cases safe:

  • A dropped connection or a proxy 502/503/504 is retried with the same key: if an acting tool already ran, the retry returns its answer instead of running it again. A fast read tool is simply run again, which is harmless (SEOmatic does not keep read answers, only acting ones and slow ones).
  • A tool slower than the API's 60s response limit keeps running on the server (it is not stopped). The CLI waits for it, up to --wait seconds (default 300), then prints its answer.
  • If it is still running after --wait, the CLI exits 2 with TOOL_STILL_RUNNING and the key. Collect the answer later (kept 24 hours for acting tools, 1 hour for reads) by running the same command with --idempotency-key <key>:
npx seomatic tools call create_seo_tasks --data @tasks.json --idempotency-key 3f0c...

Pass your own --idempotency-key to make a script's retries safe across runs. Reusing a key for different arguments is refused (IDEMPOTENCY_KEY_REUSED), never silently answered with the old result. An answer over 64 KB is returned the first time but not kept: a repeat gets IDEMPOTENCY_RESULT_NOT_KEPT (the call ran; it is not run again).

seomatic completion bash|zsh|fish|powershell

Prints a tab-completion script: commands, flags, --group values, your profile names, and tool names for tools call / tools describe (from the last seomatic tools you ran, so completing never waits on the network).

seomatic completion bash >> ~/.bashrc
seomatic completion zsh > "${fpath[1]}/_seomatic"      # then restart zsh
seomatic completion fish > ~/.config/fish/completions/seomatic.fish
seomatic completion powershell >> $PROFILE

Completion needs seomatic on your PATH (npm i -g seomatic), not npx.

Authentication

On your own computer, run seomatic login (see above). For CI and scripts, mint a key in the dashboard under Settings -> AI Agents -> API Keys (needs the admin role on that workspace - if the section is not there, check which workspace is selected and whether you are an admin on it rather than a member), then pass it by environment variable (preferred) or --key:

export SEOMATIC_API_KEY=smk_live_...
npx seomatic me

Precedence: --key, then SEOMATIC_API_KEY, then the key saved by seomatic login. Prefer the variable in CI so the key never lands in shell history or a process list.

Several workspaces (agencies): give each one a profile.

npx seomatic login --profile acme      # approve the Acme workspace
npx seomatic login --profile globex    # approve the Globex workspace
npx seomatic gsc top-queries --profile acme
SEOMATIC_PROFILE=globex npx seomatic me
npx seomatic logout --profile acme

Each profile keeps its own key. Signing in again to the same profile revokes the key it replaces, so no old key is left alive on the server.

The key is only ever sent over https (plain http is allowed to localhost for development); any other --api is refused before the key is read.

Scopes are the boundary:

| Scope | Unlocks | Cost | | ------------ | ---------------------------------------- | ------------------- | | read:gsc | Search Console reads, me, most tools | free | | chat:ask | Ask-style tools | free | | agents:act | Tools that stage changes to a site | Infrastructure plan |

Global flags

| Flag | Meaning | | -------------------- | ------------------------------------------------------- | | --json | JSON to stdout. Works on every command. | | --key <key> | API key. Overrides SEOMATIC_API_KEY and your login. | | --profile <name> | Use a separate saved login. Or env SEOMATIC_PROFILE. | | --device | login with a code approved from any browser. | | --browser | login opens a browser even over SSH. | | --no-browser | login prints the link instead of opening a browser. | | --wait <seconds> | How long tools call waits for a slow tool (300). | | --idempotency-key | Collect or safely repeat an earlier tools call. | | --api <base> | API base URL. Default https://app.seomatic.ai/api/v1. | | --days <n> | Lookback window for gsc. Default 28. | | --limit <n> | Max rows for gsc. Default 25. | | --data <json> | Body for tools call: JSON, @file.json, or -. | | --group read\|acts | Filter tools by read-only or acting. | | --version, -v | Print the version and exit 0. | | --help, -h | Usage and exit 0. |

Flags take --flag value or --flag=value. An unknown flag (including short ones like -d; only -h and -v exist), a flag missing its value, or an empty value (--key "", which would otherwise fall back to another saved login) is a usage error (exit 1) rather than being ignored.

Environment variables

| Variable | Effect | | -------------------------- | --------------------------------------------------------------- | | SEOMATIC_API_KEY | API key (after --key, before your login). | | SEOMATIC_PROFILE | Profile to use, like --profile. | | SEOMATIC_KEYRING=file | Keep the saved key in the file, not the OS store. | | SEOMATIC_CONFIG_DIR | Where credentials and caches live. | | SEOMATIC_NO_UPDATE_CHECK | No update notice (so does NO_UPDATE_NOTIFIER). | | NODE_USE_ENV_PROXY=1 | Node 22.21+/24: use HTTPS_PROXY (Node ignores it by default). |

Update notice. At most once a day, a background process asks npm for the latest version; the next command prints one line on stderr if there is a newer one. It never delays a command and never runs in CI, with --json, or when output is not a terminal.

Exit codes

| Code | Meaning | Examples | | ---- | ------------------ | ------------------------------------------------------------------------------------------------------------------ | | 0 | Success | Command ran. Includes an audit where checks failed. | | 1 | Usage or API error | Unknown command or flag, missing argument, no key, 401, 403, 402 plan gate. Also bare seomatic. | | 2 | Runtime failure | Network unreachable, DNS failure, HTTP 5xx, 429 still hit after waiting, tool still running (TOOL_STILL_RUNNING) |

The distinction that matters in CI: 1 means you asked for something wrong, 2 means we could not complete it. Retry on 2, fix the call on 1.

The CLI already retries what is safe to retry before it exits:

  • 429 on any command: waits for Retry-After (up to 30s) and tries again, up to 3 attempts. The limit is checked before anything runs, so this never repeats work. A longer wait exits 2 with retry_after in the JSON error.
  • Network errors and proxy 502/503/504: 3 attempts with backoff, on reads and on tools call (its Idempotency-Key makes the retry safe).
  • A slow tool is waited for, up to --wait (see tools call).
  • A tool that failed (TOOL_FAILED) is not retried: rerun the command, which uses a fresh key.

JSON output

With --json, stdout carries exactly one JSON value: the result, or on failure an error object. Progress (such as login's instructions) goes to stderr. Without --json, errors go to stderr as error: ....

npx seomatic audit https://example.com --json | jq .score

Error objects have one shape. Branch on code and status; error is a human sentence and may change wording:

{
  "error": "Free monthly limit reached (5 questions). Upgrade ...",
  "status": 402,
  "code": "FREE_QUOTA_EXCEEDED",
  "upgrade_url": "https://app.seomatic.ai/..."
}

code is the API's error code when it sent one (INVALID_API_KEY, MISSING_SCOPE, SCOPE_REVOKED_BY_PLAN, BILLING_INACTIVE, FREE_QUOTA_EXCEEDED, REST_ACT_REQUIRES_INFRA, UNKNOWN_TOOL, INVALID_ARGUMENTS, TOOL_FAILED), or one of the CLI's own: USAGE, NOT_SIGNED_IN, RATE_LIMITED, INSECURE_API_BASE, INTERACTIVE_ONLY, KEYRING_LOCKED, LOGIN_FAILED, NETWORK_ERROR (nothing was sent), TIMEOUT, TOOL_STILL_RUNNING and TOOL_STATE_UNKNOWN (both with idempotency_key: repeat with it to collect or safely re-run), and the API's IDEMPOTENCY_UNAVAILABLE (the tool was not run; retry). upgrade_url, details and retry_after appear when they apply.

Scripting recipes

Fail a build when a page regresses:

score=$(npx seomatic audit "$URL" --json | jq -r .score)
[ "$score" -ge 80 ] || { echo "SEO score $score < 80"; exit 1; }

List every check that failed:

npx seomatic audit "$URL" --json | jq -r '.checks[] | select(.ok|not) | .id'

Find AI crawlers wasting budget on errors:

npx seomatic logs access.log --json \
  | jq -r '.bots[] | select(.isAiBot and .wastedCrawlPct > 20)
           | "\(.bot) \(.wastedCrawlPct)% wasted"'

Retry only on runtime failures:

for i in 1 2 3; do
  npx seomatic me --json && break
  [ $? -eq 2 ] || break   # 1 is our fault; do not retry
  sleep $((i * 2))
done

Troubleshooting

| Symptom | Cause | Fix | | ----------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------- | | No API Keys section in Settings | Wrong workspace, or you are not an admin on it | It lives under Settings -> AI Agents -> API Keys and needs the admin role | | not signed in | No login, no key | seomatic login, or export SEOMATIC_API_KEY=smk_live_... | | saved sign-in is no longer valid | Key revoked in Settings, or a year old | seomatic login | | Signing in on a server or over SSH | No browser on that machine | seomatic login --device (automatic over SSH) | | TOOL_STILL_RUNNING (exit 2) | The tool ran past --wait; it was not stopped | Same command with --idempotency-key <key from the error> | | Missing or invalid API key | Wrong or revoked --key / env key | Check the key in Settings, then seomatic me | | A tool is missing from tools | Scope, plan or a missing connection | seomatic me shows scopes, plan and GSC state | | gsc returns nothing | No connected property, or the 2-3 day lag | Connect Search Console; widen --days | | Acting tool returns a plan gate | agents:act needs the Infrastructure plan | Upgrade, or use read-only tools | | logs reports 0 bots | Log has no user-agent field | Use combined format, which ends with the quoted UA | | could not reach ... | Network, DNS, or a wrong --api | Check connectivity; omit --api unless self-hosting | | Fails only behind a company proxy | Node ignores HTTPS_PROXY by default | Node 22.21+ or 24: export NODE_USE_ENV_PROXY=1 | | refusing to send your API key | --api is plain http to another host | Use the https URL |

Still stuck? seomatic me --json is the fastest first report to include.

See also

License

MIT