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

@hiprax/use-seo

v0.1.0

Published

A production-ready React hook for managing SEO and social meta tags with full TypeScript support

Readme

use-seo

License: MIT TypeScript npm version

A production-ready React hook for managing SEO meta tags, Open Graph, Twitter Cards, structured data (JSON-LD), and more. Fully typed with TypeScript and optimized for all React versions (16.8+).

Features

  • 🎯 Complete SEO Management - Title, description, keywords, canonical URLs, and more
  • 📱 Open Graph Support - Full OG tag support including multiple images and locale alternates
  • 🐦 Twitter Cards - Summary, summary_large_image, app, and player cards
  • 🤖 Robots Control - Flexible robots meta with Googlebot-specific directives
  • 🌍 International SEO - Hreflang alternates for multi-language sites
  • 📊 Structured Data - JSON-LD support for rich search results
  • Performance Optimized - Minimal re-renders with change detection
  • 🔒 SSR Safe - Works with Next.js, Remix, and other SSR frameworks
  • 📝 Fully Typed - Complete TypeScript support with IntelliSense
  • 🧪 100% Test Coverage - Thoroughly tested for reliability

Installation

npm install @hiprax/use-seo

Quick Start

import { useSEO } from '@hiprax/use-seo';

function ProductPage() {
  useSEO({
    title: 'Amazing Product',
    titleSuffix: 'My Store',
    description:
      'The best product you will ever find. High quality and great value.',
    canonical: 'https://mystore.com/products/amazing-product',
    ogImage: 'https://mystore.com/images/product.jpg',
  });

  return <div>Product content</div>;
}

API Reference

Basic SEO

useSEO({
  // Page title (recommended: 30-60 characters)
  title: 'Page Title',

  // Meta description (recommended: 120-160 characters)
  description: 'A compelling description of your page content.',

  // Meta keywords (comma-separated, max 10 recommended)
  keywords: 'react, seo, meta tags',

  // Canonical URL
  canonical: 'https://example.com/page',

  // Auto-generate canonical from current URL (default: true)
  autoCanonical: true,

  // Page language (sets <html lang="">)
  language: 'en',

  // Content author
  author: 'John Doe',
});

Title Formatting

// With suffix (result: "Contact | My Site")
useSEO({
  title: 'Contact',
  titleSuffix: 'My Site',
});

// With prefix (result: "My Site | Contact")
useSEO({
  title: 'Contact',
  titlePrefix: 'My Site',
});

// With template using %s placeholder
useSEO({
  title: 'Contact',
  titleTemplate: '%s - My Website',
});

// With template using {title} placeholder
useSEO({
  title: 'Contact',
  titleTemplate: '{title} | Brand',
});

Open Graph

useSEO({
  // OG type (default: 'website')
  ogType: 'article',

  // Site name
  ogSiteName: 'My Website',

  // OG title (falls back to formatted title)
  ogTitle: 'Article Title',

  // OG description (falls back to description)
  ogDescription: 'Article description for social sharing.',

  // OG URL (falls back to canonical)
  ogUrl: 'https://example.com/article',

  // Locale
  ogLocale: 'en_US',

  // Alternate locales
  ogLocaleAlternates: ['en_GB', 'de_DE', 'fr_FR'],

  // Single image (simple)
  ogImage: 'https://example.com/og-image.jpg',
  ogImageWidth: 1200,
  ogImageHeight: 630,
  ogImageAlt: 'Description of the image',

  // Multiple images with full metadata (preferred)
  ogImages: [
    {
      url: 'https://example.com/image1.jpg',
      width: 1200,
      height: 630,
      alt: 'Primary image',
      type: 'image/jpeg',
    },
    {
      url: 'https://example.com/image2.png',
      width: 800,
      height: 600,
      alt: 'Secondary image',
    },
  ],
});

Twitter Cards

useSEO({
  // Card type (default: 'summary_large_image')
  twitterCard: 'summary_large_image',

  // Twitter title (falls back to ogTitle or title)
  twitterTitle: 'Tweet-optimized Title',

  // Twitter description (falls back to ogDescription or description)
  twitterDescription: 'Description for Twitter.',

  // Twitter image (falls back to ogImage or first ogImages entry)
  twitterImage: 'https://example.com/twitter-image.jpg',
  twitterImageAlt: 'Image description',

  // Twitter handles (include @)
  twitterCreator: '@author_handle',
  twitterSite: '@site_handle',
});

Article Metadata

useSEO({
  ogType: 'article',

  // Publication date (ISO 8601)
  publishedTime: '2024-01-15T10:30:00Z',

  // Last modification date (ISO 8601)
  modifiedTime: '2024-02-01T14:20:00Z',

  // Expiration date (ISO 8601)
  expirationTime: '2025-12-31T23:59:59Z',
});

Robots Directives

// Simple string format
useSEO({
  robots: 'noindex,nofollow',
});

// Detailed object format
useSEO({
  robots: {
    index: true,
    follow: true,
    noarchive: false,
    nosnippet: false,
    noimageindex: false,
    maxSnippet: 150,
    maxImagePreview: 'large',
    maxVideoPreview: 30,

    // Googlebot-specific directives
    googlebot: {
      index: true,
      follow: true,
      maxVideoPreview: 0,
    },
  },
});

International SEO (Hreflang)

useSEO({
  hreflangs: [
    { href: 'https://example.com/', hrefLang: 'x-default' },
    { href: 'https://example.com/en/', hrefLang: 'en' },
    { href: 'https://example.com/en-gb/', hrefLang: 'en-GB' },
    { href: 'https://example.com/de/', hrefLang: 'de' },
    { href: 'https://example.com/es/', hrefLang: 'es' },
  ],
});

Pagination

useSEO({
  prev: 'https://example.com/posts?page=1',
  next: 'https://example.com/posts?page=3',
});

Structured Data (JSON-LD)

// Single schema
useSEO({
  structuredData: {
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: 'Article Title',
    author: {
      '@type': 'Person',
      name: 'John Doe',
    },
    datePublished: '2024-01-15',
    dateModified: '2024-02-01',
    image: ['https://example.com/image.jpg'],
  },
});

// Multiple schemas
useSEO({
  structuredData: [
    {
      '@context': 'https://schema.org',
      '@type': 'Article',
      headline: 'Article Title',
    },
    {
      '@context': 'https://schema.org',
      '@type': 'BreadcrumbList',
      itemListElement: [
        {
          '@type': 'ListItem',
          position: 1,
          name: 'Home',
          item: 'https://example.com/',
        },
        {
          '@type': 'ListItem',
          position: 2,
          name: 'Blog',
          item: 'https://example.com/blog',
        },
      ],
    },
  ],
});

Additional Custom Tags

useSEO({
  // Custom meta tags
  additionalMetaTags: [
    { name: 'theme-color', content: '#000000' },
    { name: 'format-detection', content: 'telephone=no' },
    { property: 'fb:app_id', content: '123456789' },
    { httpEquiv: 'content-language', content: 'en' },
  ],

  // Custom link tags
  additionalLinkTags: [
    { rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' },
    {
      rel: 'apple-touch-icon',
      href: '/apple-touch-icon.png',
      sizes: '180x180',
    },
    { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
    {
      rel: 'preload',
      href: '/fonts/main.woff2',
      as: 'font',
      type: 'font/woff2',
      crossOrigin: 'anonymous',
    },
  ],
});

Advanced Options

useSEO({
  // Prevent duplicate meta tags (default: true)
  preventDuplicates: true,

  // Enable development warnings (default: true in dev, false in prod)
  enableWarnings: true,

  // Validate URLs in meta/link tags (default: true)
  validateUrls: true,
});

Hook Return Methods

The hook returns an object with methods for programmatic tag management:

const { updateMetaTag, updateLinkTag, clearSEOTags, getCurrentSEO } = useSEO({
  title: 'My Page',
});

// Update a meta tag programmatically
updateMetaTag({ name: 'description' }, 'Updated description');
updateMetaTag({ property: 'og:title' }, 'Updated OG Title');

// Update a link tag programmatically
updateLinkTag('stylesheet', 'https://example.com/style.css', {
  type: 'text/css',
});

// Remove all SEO tags added by this hook
clearSEOTags();

// Get the current SEO configuration
const currentConfig = getCurrentSEO();
console.log(currentConfig.title); // 'My Page'

TypeScript Support

All types are exported for use in your TypeScript projects:

import type {
  SEOProps,
  SEOHookReturn,
  OpenGraphImage,
  HreflangLink,
  RobotsOptions,
  RobotsObject,
  AdditionalMetaTag,
  AdditionalLinkTag,
  StructuredData,
  MetaTagKey,
  LinkTagAttrs,
} from '@hiprax/use-seo';

// Use types in your code
const seoConfig: SEOProps = {
  title: 'My Page',
  description: 'Page description',
};

const images: OpenGraphImage[] = [
  { url: 'https://example.com/image.jpg', width: 1200, height: 630 },
];

SSR Considerations

The hook is SSR-safe and will not throw errors during server-side rendering. However, it only manipulates the DOM on the client side. For server-side meta tag rendering, consider:

Next.js (App Router)

Use Next.js's built-in metadata API for server-rendered meta tags, and use @hiprax/use-seo for client-side dynamic updates:

// app/page.tsx
export const metadata = {
  title: 'Static Title',
  description: 'Static description',
};

// For dynamic client-side updates:
('use client');
import { useSEO } from '@hiprax/use-seo';

function DynamicSection({ dynamicTitle }) {
  useSEO({
    title: dynamicTitle,
  });
  return <div>Content</div>;
}

Next.js (Pages Router)

import Head from 'next/head';
import { useSEO } from '@hiprax/use-seo';

function Page() {
  // For SSR
  return (
    <>
      <Head>
        <title>My Page</title>
      </Head>
      <ClientSideComponent />
    </>
  );
}

function ClientSideComponent() {
  // For client-side dynamic updates
  useSEO({ title: 'Dynamic Title' });
  return <div>Content</div>;
}

Constants

The package exports useful constants for customization:

import {
  DEFAULT_OG_TYPE, // 'website'
  DEFAULT_TWITTER_CARD, // 'summary_large_image'
  DEFAULT_AUTO_CANONICAL, // true
  DEFAULT_PREVENT_DUPLICATES, // true
  DEFAULT_VALIDATE_URLS, // true
  MIN_TITLE_LENGTH, // 30
  MAX_TITLE_LENGTH, // 60
  MIN_DESCRIPTION_LENGTH, // 120
  MAX_DESCRIPTION_LENGTH, // 160
  MAX_KEYWORDS_COUNT, // 10
} from '@hiprax/use-seo';

Best Practices

Title

  • Keep titles between 30-60 characters
  • Put important keywords at the beginning
  • Make each page title unique
  • Include your brand name (use titleSuffix)

Description

  • Keep descriptions between 120-160 characters
  • Include a call-to-action when relevant
  • Make each description unique and compelling
  • Include relevant keywords naturally

Open Graph Images

  • Use 1200x630 pixels for optimal display
  • Provide alt text for accessibility
  • Use high-quality, relevant images
  • Test with Facebook's Sharing Debugger

Structured Data

  • Validate with Google's Rich Results Test
  • Use appropriate schema types for your content
  • Keep structured data accurate and up-to-date

Canonical URLs

  • Always set canonical URLs to prevent duplicate content
  • Use absolute URLs
  • Point to the preferred version of the page

Browser Support

Supports all modern browsers and IE11+ (with appropriate polyfills).

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.

License

MIT © Hiprax


Made with ❤️ for the React community