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

@changelog-saas/widget

v0.1.0

Published

Embeddable changelog widget for websites

Downloads

55

Readme

Changelog Widget

A lightweight, customizable changelog widget that can be embedded on any website. Built with Web Components for maximum compatibility and minimal dependencies.

Features

  • Multiple Widget Types: List, Modal, and Card variants
  • No Dependencies: Pure JavaScript and Web Components
  • Lightweight: ~5KB gzipped
  • Customizable: CSS variables for easy styling
  • Secure: Embed key validation
  • Responsive: Works on all devices

Getting Started

1. Generate Embed Key

First, generate an embed key for your workspace through the dashboard or API:

curl -X POST https://api.changelog.example.com/workspaces/{workspaceId}/embed/generate-key \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

This returns:

{
  "embed_key": "550e8400-e29b-41d4-a716-446655440000"
}

2. Get Your Embed Code

Use the workspace ID and embed key to generate your embed code:

import { generateEmbedCode } from '@changelog-saas/widget';

const embedCode = generateEmbedCode({
  workspaceId: 'your-workspace-id',
  embedKey: 'your-embed-key',
  apiUrl: 'https://api.changelog.example.com',
  widgetType: 'modal', // 'list', 'modal', or 'card'
  limit: 10
});

console.log(embedCode);

3. Embed on Your Website

Copy the generated code and paste it into your HTML:

<!-- Changelog Widget -->
<script src="https://api.changelog.example.com/embed/widget.umd.js"></script>
<changelog-modal workspace-id="workspace-id" embed-key="embed-key" api-url="https://api.changelog.example.com" limit="10" label="Changelog"></changelog-modal>

Widget Types

List Widget

Displays all changelog entries in a scrollable list:

<changelog-list 
  workspace-id="workspace-id" 
  embed-key="embed-key" 
  api-url="https://api.changelog.example.com"
  limit="10"
></changelog-list>

Modal Widget

Displays a button that opens a modal with changelog entries:

<changelog-modal 
  workspace-id="workspace-id" 
  embed-key="embed-key" 
  api-url="https://api.changelog.example.com"
  limit="10"
  label="What's New"
></changelog-modal>

Card Widget

Displays a compact card with featured entries:

<changelog-card 
  workspace-id="workspace-id" 
  embed-key="embed-key" 
  api-url="https://api.changelog.example.com"
  limit="3"
  title="Latest Updates"
  view-all-url="https://changelog.example.com"
></changelog-card>

Customization

CSS Variables

Customize the appearance using CSS variables:

<style>
  changelog-list {
    --primary: #3b82f6;
    --primary-dark: #1e40af;
    --text: #1f2937;
    --text-light: #6b7280;
    --border: #e5e7eb;
    --background: #ffffff;
  }
</style>

Custom Styling

All components use Shadow DOM with CSS scoped to the component:

<style>
  changelog-modal::part(button) {
    background: #your-color;
  }
</style>

API Reference

Methods

fetchChangelogEntries(options)

Fetch changelog entries programmatically:

import { fetchChangelogEntries } from '@changelog-saas/widget';

const entries = await fetchChangelogEntries({
  apiUrl: 'https://api.changelog.example.com',
  workspaceId: 'workspace-id',
  embedKey: 'embed-key',
  limit: 10,
  skip: 0
});

Returns:

interface ChangelogEntry {
  id: string;
  title: string;
  content: string;
  type: 'feature' | 'improvement' | 'fix';
  published_at: string;
  tags: string[];
}

Attributes

Common Attributes

  • workspace-id (required): Your workspace ID
  • embed-key (required): Your embed key for authentication
  • api-url (optional): API URL (defaults to http://localhost:3000)
  • limit (optional): Number of entries to display (defaults to 10)

Modal-Specific Attributes

  • label: Button label (defaults to "Changelog")

Card-Specific Attributes

  • title: Card title (defaults to "Latest Updates")
  • view-all-url: URL for "View All" button

Backend API

Public Changelog Endpoint

GET /public/workspaces/{workspaceId}/changelog

Headers:

X-Embed-Key: your-embed-key

Query Parameters:

  • limit: Number of entries (1-100, default: 10)
  • skip: Number of entries to skip (default: 0)

Response:

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "New Feature Released",
    "content": "We've released a new feature...",
    "type": "feature",
    "published_at": "2024-01-15T10:30:00Z",
    "tags": ["new", "api"]
  }
]

Embed Key Management

Generate Embed Key

POST /workspaces/{workspaceId}/embed/generate-key

Headers:

Authorization: Bearer YOUR_JWT_TOKEN

Response:

{
  "embed_key": "550e8400-e29b-41d4-a716-446655440000"
}

Get Embed Key

GET /workspaces/{workspaceId}/embed/key

Headers:

Authorization: Bearer YOUR_JWT_TOKEN

Response:

{
  "embed_key": "existing-key"
}

Publishing Entries

Only published entries are visible in the widget. Publish an entry using:

POST /workspaces/{workspaceId}/entries/{entryId}/publish

Body:

{
  "published": true
}

Security

  • Embed keys are unique per workspace
  • Only published entries are exposed via the public API
  • CORS is configured to allow requests from any origin (entry display only)
  • No sensitive data is exposed through the widget

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions
  • iOS Safari: Latest 2 versions
  • Android Browser: Latest version

Examples

Svelte

<script>
  import { onMount } from 'svelte';

  onMount(() => {
    const script = document.createElement('script');
    script.src = 'https://api.changelog.example.com/embed/widget.umd.js';
    document.body.appendChild(script);
  });
</script>

<div id="changelog-container">
  <changelog-modal 
    workspace-id="workspace-id" 
    embed-key="embed-key"
  ></changelog-modal>
</div>

React

import { useEffect } from 'react';

export function ChangelogWidget() {
  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://api.changelog.example.com/embed/widget.umd.js';
    script.async = true;
    document.body.appendChild(script);
  }, []);

  return (
    <changelog-modal 
      workspace-id="workspace-id" 
      embed-key="embed-key"
    />
  );
}

HTML

<!DOCTYPE html>
<html>
<head>
  <title>My Site with Changelog</title>
</head>
<body>
  <h1>Welcome!</h1>
  
  <!-- Changelog Widget -->
  <script src="https://api.changelog.example.com/embed/widget.umd.js"></script>
  <changelog-card 
    workspace-id="workspace-id" 
    embed-key="embed-key"
  ></changelog-card>
</body>
</html>

Troubleshooting

Widget not loading?

  1. Check that workspace-id and embed-key are correct
  2. Verify the API URL is accessible
  3. Check browser console for errors
  4. Ensure CORS is properly configured

Entries not showing?

  1. Make sure entries are published in the dashboard
  2. Verify the embed key is valid
  3. Check that the workspace ID matches

Styling not applying?

  1. CSS variables must be set on the element before it's rendered
  2. Specificity of your CSS must be high enough
  3. Shadow DOM encapsulation prevents external styles

Building from Source

cd packages/widget

# Install dependencies
npm install

# Development
npm run dev

# Build
npm run build

# Preview
npm run preview

License

MIT