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

@seosorted/ai-crawl

v0.2.0

Published

One-line, server-side AI-crawler & bot traffic tracking for seosorted.ai. Zero runtime dependencies.

Readme

@seosorted/ai-crawl

One-line, server-side AI-crawler & bot traffic tracking. See exactly what ChatGPT, Claude, Perplexity, Google and others fetch on your site — including the pages they request that 404 (a signal you should build them).

It runs server-side because AI crawlers request raw HTML and skip frontend JavaScript, so a normal analytics tag never sees them. The tracker ignores static assets, framework internals and human browser traffic, and sends a tiny event only for detected bots. It's best-effort and won't slow your site down.

Install

npm install @seosorted/ai-crawl

Grab your websiteId from Dashboard → Bot Traffic → Enable tracking.

Integrate (pick your stack)

Next.js / Vercel — proxy.ts

import { NextResponse, type NextRequest, type NextFetchEvent } from "next/server";
import { trackAICrawlerRequest } from "@seosorted/ai-crawl";

export function proxy(request: NextRequest, event: NextFetchEvent) {
  trackAICrawlerRequest(request, event, { websiteId: "sst_xxxxxxxx" });
  return NextResponse.next();
}

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};

Cloudflare Workers

import { withAICrawlerTracking } from "@seosorted/ai-crawl";

export default {
  fetch: withAICrawlerTracking(
    async (request, env, ctx) => fetch(request),
    { websiteId: "sst_xxxxxxxx" },
  ),
};

Cloudflare Pages — functions/_middleware.ts

import { trackAICrawlerRequest } from "@seosorted/ai-crawl";

export async function onRequest(context) {
  trackAICrawlerRequest(context.request, context, { websiteId: "sst_xxxxxxxx" });
  return context.next();
}

Express

import express from "express";
import { createExpressAICrawlerMiddleware } from "@seosorted/ai-crawl";

const app = express();
app.use(createExpressAICrawlerMiddleware({ websiteId: "sst_xxxxxxxx" }));

Hono

import { Hono } from "hono";
import { trackAICrawlerResponse } from "@seosorted/ai-crawl";

const app = new Hono();
app.use("*", async (c, next) => {
  await next();
  trackAICrawlerResponse(c.req.raw, c.res, c.executionCtx, { websiteId: "sst_xxxxxxxx" });
});

Deploy, and bot traffic starts appearing in your dashboard.

No-code / hosted platforms

WordPress (self-hosted)

WordPress runs PHP on every request, so a tiny plugin is the equivalent of the middleware above — and it captures 404s natively. Save this as wp-content/plugins/seosorted-ai-crawl/seosorted-ai-crawl.php, set your websiteId, and activate it under Plugins.

<?php
/* Plugin Name: SEOSorted AI Crawl */
if (!defined('ABSPATH')) exit;

define('SEOSORTED_WEBSITE_ID', 'sst_xxxxxxxx'); // ← your website id

add_action('shutdown', function () {
  $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
  if ($ua === '' || !preg_match(
    '/bot|crawl|spider|slurp|gptbot|chatgpt|oai-|claude|anthropic|perplexity|applebot|amazonbot|bytespider|ccbot|baidu|grok|xai|duckassist|google-extended|meta-external|facebookexternal/i',
    $ua
  )) return;

  wp_remote_post('https://app.seosorted.ai/api/v1/track/' . SEOSORTED_WEBSITE_ID, [
    'blocking' => false, // fire-and-forget — never slows the page
    'timeout'  => 1,
    'headers'  => ['Content-Type' => 'application/json'],
    'body'     => wp_json_encode(['hits' => [[
      'path'       => $_SERVER['REQUEST_URI'] ?? '/',
      'method'     => $_SERVER['REQUEST_METHOD'] ?? 'GET',
      'statusCode' => http_response_code() ?: 200, // native 404 capture
      'userAgent'  => $ua,
      'ip'         => $_SERVER['HTTP_CF_CONNECTING_IP']
                      ?? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '')[0]
                      ?: ($_SERVER['REMOTE_ADDR'] ?? null),
      'referer'    => $_SERVER['HTTP_REFERER'] ?? null,
    ]]]),
  ]);
});

Behind Cloudflare (any origin, no npm)

If your domain is proxied through Cloudflare, add a Snippet (Rules → Snippets) or a Worker. Captures 100% of traffic — including 404s — whatever runs at the origin.

export default {
  async fetch(request, env, ctx) {
    const res = await fetch(request);
    const ua = request.headers.get("user-agent") || "";
    const path = new URL(request.url).pathname;
    const isBot = /bot|crawl|spider|gptbot|chatgpt|oai-|claude|anthropic|perplexity|applebot|amazonbot|bytespider|ccbot|baidu|grok|duckassist|google-extended|meta-external/i.test(ua);
    const isAsset = /\.(css|js|png|jpe?g|gif|svg|webp|ico|woff2?|map)$/i.test(path);
    if (isBot && !isAsset) {
      ctx.waitUntil(fetch("https://app.seosorted.ai/api/v1/track/sst_xxxxxxxx", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ hits: [{
          path, method: request.method, statusCode: res.status, userAgent: ua,
          ip: request.headers.get("cf-connecting-ip"),
          referer: request.headers.get("referer"), occurredAt: Date.now(),
        }] }),
      }));
    }
    return res;
  },
};

Shopify, Wix, Squarespace

These run your site entirely on their own servers and don't allow third-party server-side code. Because AI crawlers skip JavaScript, there is no reliable client-side workaround — bot tracking isn't supported on them today. If you can front the domain with Cloudflare (most custom domains, but not Shopify's storefront), use the Snippet above instead.

Direct API

Integrate from any language by POSTing hits yourself:

POST https://app.seosorted.ai/api/v1/track/<websiteId>
Content-Type: application/json

{ "hits": [{
  "path": "/pricing",          // required
  "method": "GET",             // optional (default "GET")
  "statusCode": 404,           // optional; omit at request time
  "userAgent": "GPTBot/1.1",   // optional but recommended
  "ip": "203.0.113.9",         // optional; needed to verify authenticity
  "referer": "https://…",      // optional
  "occurredAt": 1719000000000  // optional (ms epoch), default = ingest time
}] }

Batch 1–500 hits per request; returns 202 { accepted, jobId }. Send the visitor's IP (not your server's) — verification runs on it.

Platform support

| Platform | Method | Captures 404s? | |---|---|---| | Next.js / Vercel | trackAICrawlerRequest | ⚠️ request-time only | | Cloudflare Workers | withAICrawlerTracking / Snippet | ✅ | | Cloudflare Pages | trackAICrawlerRequest | ⚠️ request-time only | | Express / Node | createExpressAICrawlerMiddleware | ✅ | | Hono | trackAICrawlerResponse | ✅ | | WordPress (self-hosted) | plugin snippet | ✅ | | Behind Cloudflare (any origin) | Snippet / Worker | ✅ | | Shopify / Wix / Squarespace | not supported (platform limitation) | — |

Supported crawlers

Detected out of the box and grouped in your dashboard by what they're doing — each shown with its provider's logo. New crawlers are added regularly.

🟣 AI assistants — fetching to answer a user right now

  • OpenAI — ChatGPT-User
  • Anthropic — Claude-User
  • Google — Google-NotebookLM, Google-Read-Aloud, Google-Agent
  • Microsoft — Copilot
  • Perplexity — Perplexity-User
  • xAI — Grok-DeepSearch
  • Meta — meta-externalfetcher
  • Amazon — Amzn-User
  • DuckDuckGo — DuckAssistBot

🔵 Search indexing — discovering & refreshing content

  • OpenAI — OAI-SearchBot
  • Anthropic — Claude-SearchBot
  • Google — Googlebot
  • Microsoft — bingbot, BingPreview
  • Perplexity — PerplexityBot
  • Apple — Applebot
  • xAI — xAI-SearchBot
  • Meta — meta-webindexer
  • ByteDance — TikTokSpider
  • Baidu — Baiduspider
  • Moonshot — Kimi-SearchBot
  • You.com — YouBot

🟢 AI training — crawling for model data

  • OpenAI — GPTBot
  • Anthropic — ClaudeBot, anthropic-ai
  • Google — Google-Extended, Google-CloudVertexBot
  • Amazon — Amazonbot
  • Apple — Applebot-Extended
  • Common Crawl — CCBot
  • ByteDance — Bytespider
  • Meta — meta-externalagent, FacebookBot
  • xAI — xAI-Web-Crawler
  • DeepSeek — DeepSeekBot
  • Alibaba — QwenBot
  • Baidu — ERNIEBot
  • Cohere — cohere-ai
  • Allen AI — AI2Bot

🟠 SEO tools

  • AhrefsBot, SemrushBot, DataForSeoBot, DotBot, MJ12bot

⚪ Other

  • OpenAI OAI-AdsBot, Google GoogleOther, xAI GrokBot, Meta facebookexternalhit, Alibaba TongyiBot, Baidu YiyanBot, plus a generic catch-all for any User-Agent containing bot / crawler / spider.

Notes

  • 404 tracking: response-aware integrations (Workers, Express, Hono, WordPress) know the real status code, so bot 404s show up. Request-time hooks (Next.js / Pages edge middleware) run before the response, so they report requests without a status.
  • Options: { websiteId, endpoint? } — set endpoint to point at a self-hosted / local ingest host (defaults to production).
  • Verification: User-Agents are spoofable, so each hit is confirmed against the source IP (reverse-DNS forward-confirm, or the vendor's published IP ranges). Hits that fake a known bot UA are flagged as spoofed.
  • Privacy: IPs are used only to verify authenticity, then truncated before storage — full IPs are never persisted.