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

@farmtrace/seo

v1.0.3

Published

Comprehensive SEO toolkit for Next.js applications with programmatic SEO, JSON-LD schema, and content generation support

Downloads

35

Readme

@farmtrace/seo

A comprehensive, plugin-based SEO toolkit for React applications. Handles metadata generation, JSON-LD structured data, sitemaps, breadcrumbs, and programmatic SEO — all configured with a single createSEO() call.

Works with any React framework: Next.js, Remix, Vite, Gatsby, Astro, or plain React.

Features

  • Framework-agnostic — works with Next.js, Remix, Vite, Gatsby, Astro, or plain React
  • Zero-config defaults — only name and domain required, everything else has smart defaults
  • Plugin architecture — extend with custom schemas, templates, page types, and middleware
  • JSON-LD schema — Organization, WebSite, Article, FAQ, BreadcrumbList, SoftwareApplication, HowTo, Person
  • Metadata API — generates structured metadata objects compatible with Next.js Metadata and any other framework
  • Page registry — register pages for automatic sitemap generation and breadcrumbs
  • AutoSEO component — React component that auto-injects JSON-LD from conventions
  • Programmatic SEO — templates, content hashing, and uniqueness scoring for generated pages
  • March 2026 Core Update compliant — E-E-A-T Person schema, Information Gain scoring, content uniqueness validation
  • Tree-shakeable — subpath imports for each module

Installation

# npm
npm install @farmtrace/seo

# bun
bun add @farmtrace/seo

# pnpm
pnpm add @farmtrace/seo

Peer Dependencies

{
  "react": ">=18"
}

Next.js is optional — the package works without it.

Quick Start

1. Initialize

Call createSEO() once in your app (e.g., in lib/seo/config.ts):

import { createSEO } from '@farmtrace/seo';

createSEO({
  name: 'MyApp',
  domain: 'myapp.com',
  tagline: 'Build better apps',
  social: {
    twitter: '@myapp',
    linkedin: 'https://linkedin.com/company/myapp',
  },
  images: {
    logo: '/logo.png',
    ogDefault: '/og-image.jpg',
  },
});

2. Generate Metadata

// Works with any framework — returns a plain Metadata object
import { generateMetadata as genMeta } from '@farmtrace/seo';
import type { Metadata } from '@farmtrace/seo';

function getPageMetadata(): Metadata {
  return genMeta({
    title: 'About Us',
    description: 'Learn about our mission and team.',
    path: '/about',
    type: 'generic',
  });
}

3. Add JSON-LD Schema

import { AutoSEO } from '@farmtrace/seo';

export default function AboutPage() {
  return (
    <AutoSEO path="/about" schemaOptions={{ name: 'About Us', description: '...' }}>
      <main>{/* page content */}</main>
    </AutoSEO>
  );
}

API Reference

Core

| Export | Description | |--------|-------------| | createSEO(options) | Initialize the SEO system. Returns an SEOInstance with runtime extension methods. | | configureSEO(config) | Legacy configuration (use createSEO instead). | | definePlugin(plugin) | Type-safe plugin definition helper. | | getSiteConfig() | Get the resolved SiteConfig. | | getTitleTemplates() | Get all title templates as Record<string, string>. | | getDescriptionTemplates() | Get all description templates as Record<string, string>. | | getKeywords() | Get the keyword dictionary. | | addTemplate(kind, key, template) | Register a title or description template at runtime. | | resolveTemplate(kind, key, vars) | Interpolate a registered template with variables. | | addSchema(type, generator) | Register a custom schema generator. | | addMiddleware(fn) | Add metadata middleware. | | addPageType(type, config) | Register a custom page type. |

Metadata

| Export | Description | |--------|-------------| | generateMetadata(options) | Generate a Next.js Metadata object. | | generateProgrammaticMetadata(options) | Metadata for programmatic/template pages. | | generateBlogPostMetadata(options) | Specialized blog post metadata. | | generateIntegrationMetadata(options) | Specialized integration page metadata. | | generateFeatureMetadata(options) | Specialized feature page metadata. | | generateUseCaseMetadata(options) | Specialized use-case page metadata. | | generateLocationMetadata(options) | Specialized location page metadata. | | mergeMetadata(...sources) | Deep-merge multiple metadata objects. | | createMetadataGenerator(defaults) | Create a reusable metadata generator with defaults. | | formatTitle(title) | Apply the default title template. | | stripHtml(str) | Remove HTML tags from a string. | | truncateText(text, max) | Truncate text to a max length with ellipsis. |

Schema (JSON-LD)

| Export | Description | |--------|-------------| | generateOrganizationSchema() | Organization schema from site config. | | generateWebSiteSchema() | WebSite schema with search action. | | generateWebPageSchema(path, options) | WebPage (or subtype) schema. | | generateArticleSchema(path, options) | Article schema with author and dates. | | generatePersonSchema(person) | Person schema with E-E-A-T signals. | | generateBreadcrumbSchema(items) | BreadcrumbList schema from items. | | generateBreadcrumbsFromPath(path) | Auto-generate breadcrumbs from a URL path. | | generateFAQSchema(items) | FAQPage schema. | | generateSoftwareSchema(options) | SoftwareApplication schema. | | generateHowToSchema(options) | HowTo schema with steps. | | wrapSchema(schema) | Wrap a schema with @context. | | generateSchemaGraph(schemas) | Combine schemas into a @graph. | | schemaToJsonString(schema) | Serialize schema to JSON string. | | isValidSchema(schema) | Validate a schema has required @type. |

Page Registry

| Export | Description | |--------|-------------| | registerStaticPages(pages) | Register known pages. | | registerDynamicPages(generator) | Register a dynamic page generator. | | getStaticPages() | Get all static pages. | | getDynamicPages() | Resolve and get all dynamic pages. | | getAllPages() | Get all pages (static + dynamic). | | findPageByPath(path) | Look up a page by its path. | | getPageConfig(path, overrides?) | Get config or auto-generate from conventions. | | generatePageConfigFromPath(path) | Generate page config from URL conventions. | | generateSitemapFromRegistry(baseUrl) | Generate sitemap entries from all registered pages. | | generateBreadcrumbsFromRegistry(path) | Generate breadcrumb trail from registry. | | getRelatedPages(path, limit?) | Find related pages by relevance scoring. |

Auto-SEO

| Export | Description | |--------|-------------| | AutoSEO | React component — auto-injects JSON-LD schema markup. | | createPageMetadata(path, options?) | Convention-based metadata generation. | | generateAutoSchema(path, options?) | Convention-based schema generation. | | createFullPageSEO(path, options) | Returns both { metadata, schema } in one call. |

Constants

| Constant | Description | |----------|-------------| | PAGE_TYPES | Maps page types → Schema.org types (homeWebSite, articleArticle, etc.) | | SEO_LIMITS | Title/description character limits ({ min, max, optimal }) | | REVALIDATION | ISR revalidation intervals by content type (seconds) | | SITEMAP_CONFIG | Sitemap defaults: max URLs, priorities, change frequencies | | CONTENT_REQUIREMENTS | Minimum word counts, required sections, unique content ratio |

Utilities

| Export | Description | |--------|-------------| | getCanonicalUrl(path) | Build canonical URL from path and site config. | | getAlternateUrls(path) | Generate alternate language URLs. | | validateTitle(title) | Check title against SEO_LIMITS. | | validateDescription(desc) | Check description against SEO_LIMITS. | | generateContentHash(content) | Generate a hash for content uniqueness tracking. |

Subpath Imports

Import only the module you need to keep bundles minimal:

import { createSEO, definePlugin } from '@farmtrace/seo/core';
import { generateArticleSchema } from '@farmtrace/seo/schema';
import { generateMetadata } from '@farmtrace/seo/metadata';
import { registerStaticPages } from '@farmtrace/seo/registry';
import { AutoSEO } from '@farmtrace/seo/auto-seo';
import type { SEOPlugin } from '@farmtrace/seo/types';
import { PAGE_TYPES } from '@farmtrace/seo/constants';
import { getCanonicalUrl } from '@farmtrace/seo/utils';

Plugin System

Plugins bundle related functionality — schemas, templates, page types, and middleware:

import { definePlugin, createSEO } from '@farmtrace/seo';

const analyticsPlugin = definePlugin({
  name: 'analytics',
  middleware: [
    (metadata, ctx) => {
      // Add tracking parameters to all pages
      metadata['other'] = { ...metadata['other'], 'analytics-page-type': ctx.type };
      return metadata;
    },
  ],
});

const ecommercePlugin = definePlugin({
  name: 'ecommerce',
  schemas: {
    product: (data) => ({
      '@type': 'Product',
      name: data?.name,
      description: data?.description,
      offers: { '@type': 'Offer', price: data?.price, priceCurrency: 'USD' },
    }),
  },
  pageTypes: {
    product: { schemaType: 'Product', ogType: 'product', priority: 0.8 },
    collection: { schemaType: 'CollectionPage', ogType: 'website', priority: 0.7 },
  },
  templates: {
    title: { product: '%s | Shop', collection: '%s Collection | Shop' },
    description: { product: 'Buy %s at great prices.' },
  },
  setup: (seo) => {
    console.log(`Ecommerce plugin loaded for ${seo.config.site.name}`);
  },
});

createSEO({
  name: 'MyShop',
  domain: 'myshop.com',
  plugins: [analyticsPlugin, ecommercePlugin],
});

Page Registry & Sitemap

import {
  registerStaticPages,
  registerDynamicPages,
  generateSitemapFromRegistry,
} from '@farmtrace/seo';

// Register your pages
registerStaticPages([
  { path: '/', title: 'Home', description: 'Welcome', type: 'home', priority: 1.0 },
  { path: '/about', title: 'About', description: 'About us', type: 'about', parent: '/' },
  { path: '/blog', title: 'Blog', description: 'Latest posts', type: 'blog-listing' },
]);

registerDynamicPages({
  pattern: '/blog/[slug]',
  type: 'blog-post',
  generate: async () => {
    const posts = await fetchPosts();
    return posts.map(p => ({
      path: `/blog/${p.slug}`,
      title: p.title,
      description: p.excerpt,
      type: 'blog-post' as const,
    }));
  },
});

// In your sitemap.ts
export default async function sitemap() {
  return generateSitemapFromRegistry('https://myshop.com');
}

Architecture

src/
├── index.ts          # Public API (barrel exports)
├── types.ts          # All type definitions
├── constants.ts      # PAGE_TYPES, SEO_LIMITS, REVALIDATION, etc.
├── utils.ts          # URL helpers, validators, hashing
├── core/
│   ├── state.ts      # Singleton config store
│   ├── factory.ts    # createSEO() + configureSEO()
│   ├── getters.ts    # Config accessor functions
│   ├── templates.ts  # Template registration + interpolation
│   ├── plugins.ts    # definePlugin() + applyPlugin()
│   └── extensions.ts # Runtime schema/middleware/pageType registration
├── schema/
│   ├── types.ts      # Schema.org TypeScript interfaces
│   ├── generators.ts # All generate*Schema() functions
│   └── utils.ts      # wrapSchema, generateSchemaGraph, etc.
├── metadata/
│   ├── generator.ts  # generateMetadata, generateProgrammaticMetadata
│   ├── specialized.ts # Blog, integration, feature, use-case, location generators
│   └── utils.ts      # mergeMetadata, formatTitle, stripHtml, truncateText
├── registry/
│   ├── store.ts      # Page registration + lookup
│   ├── conventions.ts # Path-based page config inference
│   └── sitemap.ts    # Sitemap + breadcrumbs + related pages
└── auto-seo/
    ├── metadata.ts   # createPageMetadata (convention-based)
    ├── schema.ts     # generateAutoSchema (convention-based)
    └── component.tsx # <AutoSEO> React component + createFullPageSEO

Requirements

  • React ≥ 18
  • TypeScript ≥ 5 (recommended)
  • Next.js ≥ 14 (optional — for generateMetadata integration)

License

MIT