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

relatedposts

v3.0.0

Published

A utility package to find related posts or blogs based on semantic similarity of titles, categories, and tags. Works with standard content objects and Astro blog collections.

Readme

Related Posts

A utility function to find related content based on title, category, and tags using semantic embeddings and cosine similarity for more accurate content matching. Now with support for both standard content objects and Astro blog collections.

Features

  • Semantic similarity: Uses transformer-based embeddings to understand meaning beyond surface-level text matching
  • Cosine similarity: Calculate precise similarity scores between content embeddings
  • Multi-dimensional matching: Find related content based on title, category, and tags
  • Customizable weights: Adjust importance of title, category, and tags in similarity calculations
  • Smart preprocessing: Remove stopwords and non-letter characters for cleaner comparisons
  • Performance optimized: Cached embedding pipeline for faster subsequent operations

Installation

Install the package and its dependencies via npm:

bash

npm install relatedposts @xenova/transformers

bash

import getRelated, { getRelatedAstro } from 'relatedposts';

Function

The getRelated function evaluates and returns a list of Comparison objects that are most similar to a given Input object. Similarity is determined using semantic embeddings for titles, exact matching for categories, and overlap analysis for tags. The results are sorted by their similarity scores in descending order.

Note: This function uses machine learning embeddings and is asynchronous. The first call may take longer as it downloads and initializes the transformer model (~90MB).

Parameters

  1. input (Input):

    • An object representing the input data to be compared against.
    • Fields:
      • title (string): The title of the input.
      • category (string): The category of the input.
      • tags (string[]): An array of tags associated with the input.

    Example:

    typescript

    const input = {
      title: "The quick brown dog",
      category: "Animals",
      tags: ["quick", "brown", "dog"],
    };
  2. comparisons (Comparison[]):

    • An array of objects representing the items to be compared against the input.
    • Fields:
      • title (string): The title of the comparison item.
      • category (string): The category of the comparison item.
      • tags (string[]): An array of tags associated with the comparison item.

    Example:

    typescript

    const comparisons = [
      {
        title: "The quick brown fox",
        category: "Animals",
        tags: ["quick", "brown", "fox"],
      },
      {
        title: "The lazy dog",
        category: "Animals",
        tags: ["lazy", "dog"],
      },
      {
        title: "A fast brown cat",
        category: "Animals",
        tags: ["fast", "brown", "cat"],
      },
    ];
  3. numResults (number, optional):

    • The number of results to return. Defaults to 5.
  4. options (Options, optional):

    • An object containing weights to influence the similarity score calculations.
    • Fields:
      • weights (Weights, optional): Object containing weight values for different similarity components.
        • title (number, optional): Weight for the title similarity score. Defaults to 1.
        • category (number, optional): Weight for the category similarity score. Defaults to 1.
        • tags (number, optional): Weight for the tags similarity score. Defaults to 1.

    Example:

    typescript

    const options = {
      weights: {
        title: 2.0,    // Title similarity is twice as important
        category: 1.5, // Category matching is 1.5x as important
        tags: 1.0      // Tags have standard weight
      }
    };

Returns

  • A Promise that resolves to an array of ScoredComparison objects.
  • Fields:
    • All fields of the original Comparison object.
    • score (number): The computed similarity score (0-1 range) based on semantic similarity, category matching, and tag overlap.

Example output:

typescript

const results = [
  {
    title: "A fast brown cat",
    category: "Animals", 
    tags: ["fast", "brown", "cat"],
    score: 0.87,  // High semantic similarity between "quick dog" and "fast cat"
  },
  {
    title: "The quick brown fox",
    category: "Animals",
    tags: ["quick", "brown", "fox"],
    score: 0.82,  // Very similar words and structure
  },
  {
    title: "The lazy dog", 
    category: "Animals",
    tags: ["lazy", "dog"],
    score: 0.71,  // Same animal type but different characteristics
  },
];

Usage

typescript

// Basic usage
const results = await getRelated(input, comparisons, 5);
console.log(results);

// With custom weights
const results = await getRelated(input, comparisons, 3, {
  weights: {
    title: 2.0,
    category: 1.0,
    tags: 0.5
  }
});
console.log(results);

getRelatedAstro Function

The getRelatedAstro function is specifically designed for Astro blog collections. It works with Astro's data structure where content is nested under a data property and uses ID-based filtering to exclude the current blog post from related suggestions.

Parameters

  1. currentId (string):
    • The ID of the current blog post to exclude from results
  2. blogs (AstroBlog[]):
    • Array of Astro blog objects with nested data structure
  3. numResults (number, optional):
    • Number of results to return. Defaults to 5
  4. options (Options, optional):
    • Same weight options as getRelated function

Astro Blog Structure

interface AstroBlog {
  id: string;
  collection: string;
  data: {
    title: string;
    category?: string;
    tags?: string[];
    publishDate?: string;
    // ... other frontmatter properties
  };
  body: string;
}

Usage with Astro

import { getRelatedAstro } from 'relatedposts';

// Example: Finding related posts in an Astro project
const currentPostId = "my-current-post.md";
const allBlogPosts = [
  {
    id: "my-current-post.md",
    collection: "blog",
    data: {
      title: "Getting Started with TypeScript",
      category: "Development",
      tags: ["typescript", "programming", "tutorial"],
      publishDate: "2025-10-13"
    },
    body: "..."
  },
  {
    id: "advanced-typescript.md",
    collection: "blog",
    data: {
      title: "Advanced TypeScript Patterns",
      category: "Development",
      tags: ["typescript", "advanced", "patterns"],
      publishDate: "2025-10-10"
    },
    body: "..."
  }
  // ... more blog posts
];

const relatedPosts = await getRelatedAstro(currentPostId, allBlogPosts, 3);
console.log(relatedPosts);

Example Output

const relatedPosts = [
  {
    title: "Advanced TypeScript Patterns",
    category: "Development",
    tags: ["typescript", "advanced", "patterns"],
    score: 0.89
  },
  {
    title: "JavaScript Best Practices",
    category: "Development",
    tags: ["javascript", "best-practices"],
    score: 0.76
  }
];

How It Works

  1. Title Similarity: Converts titles to semantic embeddings using a pre-trained transformer model and calculates cosine similarity
  2. Category Matching: Performs exact string matching between categories (binary score)
  3. Tag Overlap: Calculates the proportion of input tags that appear in comparison tags
  4. Weighted Scoring: Combines all three scores using customizable weights and returns a final similarity score