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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@omnidyon/ngx-seo-meta

v1.0.0

Published

Lightweight SEO meta management for Angular (standalone & router-aware).

Readme

npm version npm downloads License: MIT types Angular angular compatibility

A lightweight, declarative SEO meta-tag management library for Angular 19+.

It gives you:

  • Path-based SEO, driven by a central config.
  • Route-driven SEO, driven by route.data.seo.
  • Automatic updates on every navigation.
  • A single, focused service that applies <title> and <meta> tags.

Works with standalone apps and classic NgModule setups.


Features

  • ✅ Angular 19+ compatible
  • ✅ Standalone & NgModule friendly
  • ✅ Auto-update SEO on NavigationEnd
  • ✅ Two parallel SEO systems:
    • Path-based SEO via SEO_META_CONFIG
    • Route-based SEO via route.data.seo
  • ✅ Central SeoMetaService with:
    • updateForPath(path: string)
    • applyRouteMeta(entry: SeoMetaDefinition)
  • ✅ Open Graph meta integration (documented via SeoMetaDefinition)
  • 🚧 Roadmap for:
    • Social meta helpers (Twitter, richer OG)
    • JSON-LD helpers
    • Canonical + hreflang utilities
    • SSR-aware tweaks
    • Typed config builder & dev-time diagnostics

Installation

npm install @omnidyon/ngx-seo-meta

Peer dependencies: Angular 19+.


Core Concepts

ngx-seo-meta is intentionally simple:

  • One service: SeoMetaService
  • One config token: SEO_META_CONFIG
  • Two ways to supply SEO:
    1. A central path-based config
    2. Route metadata using route.data.seo

The service API is stable and must not be broken:

class SeoMetaService {
  updateForPath(path: string): void;
  applyRouteMeta(entry: SeoMetaDefinition): void;
}

Internally it uses Angular's Title and Meta services and, if available, Router to react to navigation.


SEO Meta Definition

All SEO definitions (config-based or route-based) share the same shape:

export interface SeoMetaDefinition {
  title: string;
  description: string;

  ogTitle?: string;
  ogDescription?: string;
  ogUrl?: string;

  ogImage?: string;
  ogType?: string;
  ogSiteName?: string;
  twitterTitle?: string;
  twitterDescription?: string;
  twitterImage?: string;
  twitterCard?: string;
  twitterSite?: string;
  twitterCreator?: string;
}

The library:

  • Always sets <title> from title.
  • Updates the <meta name="description">.
  • Applies OG fields when present, with sensible fallbacks (e.g. ogTitle ?? title).

Path-Based SEO (Config-Driven)

This is the original mechanism: map normalized URL paths to SEO definitions.

1. Define the config

// seo-config.ts
import type { SeoMetaConfig } from '@omnidyon/ngx-seo-meta';

export const SEO_CONFIG: SeoMetaConfig = {
  '/': {
    title: 'Home – My App',
    description: 'Welcome to my Angular application.',
    ogUrl: 'https://example.com/',
  },
  '/about': {
    title: 'About Us',
    description: 'Learn more about the team behind this project.',
  },
  '/blog': {
    title: 'Blog',
    description: 'Articles, tutorials and release notes.',
  },
};

SeoMetaConfig is just:

export type SeoMetaConfig = Record<string, SeoMetaDefinition>;

2. Provide the config

Using standalone bootstrap:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
import { provideSeoMeta } from '@omnidyon/ngx-seo-meta';
import { SEO_CONFIG } from './seo-config';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideSeoMeta(SEO_CONFIG),
  ],
});

3. How it works at runtime

  • SeoMetaService listens to Router.events (if Router is present).
  • On every NavigationEnd:
    • It normalizes the URL:
      • strips query & hash
      • trims trailing slashes (except /)
    • Looks up the path in SEO_CONFIG.
    • Applies the SeoMetaDefinition via the internal apply() method.

You can also trigger it manually:

constructor(private readonly seo: SeoMetaService) {}

ngOnInit() {
  this.seo.updateForPath('/blog');
}

Route-Driven SEO (data.seo)

This is the new mechanism: put SEO definitions directly on your routes.

1. Add seo to your route data

// app.routes.ts
import { Routes } from '@angular/router';
import type { SeoMetaDefinition } from '@omnidyon/ngx-seo-meta';

export const routes: Routes = [
  {
    path: '',
    loadComponent: () => import('./home/home.component'),
    data: {
      seo: {
        title: 'Home – My App',
        description: 'Welcome to the homepage.',
      } satisfies SeoMetaDefinition,
    },
  },
  {
    path: 'blog/:slug',
    loadComponent: () => import('./blog/blog.component'),
    data: {
      seo: (route): SeoMetaDefinition => {
        const slug = route.paramMap.get('slug') ?? 'article';
        return {
          title: `Blog – ${slug}`,
          description: `Reading article: ${slug}`,
        };
      },
    },
  },
];

The seo data supports:

type RouteSeoMeta = SeoMetaDefinition;

type RouteSeoMetaConfig =
  | RouteSeoMeta
  | ((route: ActivatedRouteSnapshot) => RouteSeoMeta);

2. Enable route-driven SEO

import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
import { provideSeoMetaRouting } from '@omnidyon/ngx-seo-meta';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideSeoMetaRouting(),
  ],
});

3. What provideSeoMetaRouting() does

  • Uses provideEnvironmentInitializer (Angular 16+/19+ style).
  • On app init:
    • Injects EnvironmentInjector.
    • Resolves Router and SeoMetaService.
    • Subscribes to router.events.
  • On every NavigationEnd:
    • Walks to the deepest ActivatedRouteSnapshot.
    • Reads data['seo'].
    • If present:
      • If it's a function: calls it with the snapshot.
      • If it's an object: uses it directly.
      • Calls seo.applyRouteMeta(definition).

4. Coexisting with path-based SEO

You can use both providers together:

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideSeoMeta(SEO_CONFIG),       // path-based
    provideSeoMetaRouting(),          // route-based
  ],
});

They do not override each other:

  • Path-based SEO still responds to updateForPath() and config entries.
  • Route-based SEO calls applyRouteMeta() with route-specific metadata.

Manual Usage

You can also use the service directly if you need full control.

Imperative route-style application

constructor(private readonly seo: SeoMetaService) {}

setDynamicSeoForProduct(product: Product) {
  this.seo.applyRouteMeta({
    title: `Buy ${product.name} – My Store`,
    description: product.shortDescription,
    ogUrl: `https://example.com/products/${product.slug}`,
  });
}

Imperative path-based lookup

constructor(private readonly seo: SeoMetaService) {}

ngOnInit() {
  // Forces the service to use the config entry for /special
  this.seo.updateForPath('/special');
}

Angular 19+ & Standalone

This library is designed with Angular 19+ and standalone APIs in mind:

  • Uses provideEnvironmentInitializer.
  • Plays well with bootstrapApplication.
  • Still compatible with NgModule apps via a simple module wrapper if needed.

Example (NgModule-style):

import { NgModule } from '@angular/core';
import { BrowserModule, bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { provideSeoMeta, provideSeoMetaRouting } from '@omnidyon/ngx-seo-meta';

@NgModule({
  imports: [BrowserModule],
  bootstrap: [AppComponent],
  providers: [
    provideSeoMeta(SEO_CONFIG),
    provideSeoMetaRouting(),
  ],
})
export class AppModule {}

Testing

The library is tested with Vitest, but:

  • We do not mock @angular/core internals.
  • SeoMetaService is tested in isolation with spies for Title and Meta.
  • Providers (provideSeoMeta, provideSeoMetaRouting) are tested via Angular's TestBed and simple fakes (for Router etc.) where needed.

If you’re testing in your own app:

  • Use TestBed.configureTestingModule.
  • Provide SeoMetaService, Title, Meta, and a fake or real Router depending on the scenario.
  • Avoid mocking Angular’s core module directly.

Roadmap

Planned / in-progress features:

  1. Social meta helper
    • Better ergonomics for OG + Twitter tags.
  2. JSON-LD helper
    • Quick helpers for common schemas (e.g. Article, BreadcrumbList).
  3. Canonical + hreflang utilities
  4. Guards / directives
    • Small helpers to glue SEO configuration to templates & guards.
  5. Environment / SSR-aware behavior
    • Avoid touching document on the server.
  6. Dev-time diagnostics
    • Warnings for missing descriptions, duplicate titles, etc.
  7. Typed configuration & builder
    • Fluent, fully typed config building API.

License

MIT. Use it, fork it, break it, fix it.


Credits

Built for people who are tired of rewriting the same <title> and <meta> boilerplate across Angular apps.