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

discord.js-html-transcript

v4.0.0

Published

Generate beautiful, pixel-perfect Discord HTML transcripts with full support for modern Discord UI - buttons, select menus, polls, voice messages, forwarded messages, server tags, and more.

Readme


✨ What's New in v4

This package is a completely modernized fork of discord-html-transcripts by ItzDerock, rebuilt from the ground up with a native Discord UI that is indistinguishable from the real thing.

🆕 New Features

| Feature | Description | |---------|-------------| | 🔀 Forwarded Messages | Full support for Discord's forwarded message format with origin info | | 🎙️ Voice Messages | Waveform visualization with play button, duration, and speed controls | | 📊 Polls / Voting | Native poll rendering with answer options, vote counts, and progress bars | | 🏷️ Server Tags | APP badges, role icons, and server tag badges on user profiles | | 🔘 Buttons & Select Menus | Primary, secondary, success, danger, and link button styles + dropdown menus | | 🔗 Invite Link Previews | Rich invite cards with server icon, member counts, and join button | | 🖼️ Image Preview Lightbox | Click any image to open a full-screen lightbox overlay | | 🔍 Message Search | Built-in search bar to find messages within transcripts | | 🧵 Thread Previews | Thread starter messages with preview boxes and participant info | | 📎 File Attachments | Native-styled file attachment cards with download buttons | | 🎨 ANSI Code Blocks | Full ANSI escape sequence rendering with colors and formatting | | 📱 Fully Responsive | Mobile-first responsive design that works perfectly on all screen sizes | | 📌 Sticky Header | Channel header stays visible while scrolling, just like Discord | | ⚙️ Configurable Features | Toggle search, image preview, spoiler reveal, and more on/off | | 💾 Granular Asset Saving | Fine-grained control over which remote assets (images, avatars, emojis, etc.) are preserved |

🎨 UI Improvements

  • Redesigned button and select menu components matching Discord's current design
  • Modern dark theme background (#070709) matching native Discord
  • Improved embed border styling with subtle transparency
  • Enhanced markdown rendering (headings, lists, block quotes, code blocks)
  • Responsive image galleries with multi-image grid layouts
  • Native vote/poll UI with interactive styling
  • Voice message capsule with amplitude-proportional waveform bars
  • Custom file attachment cards with file type icons

📦 Installation

# npm
npm install discord.js-html-transcript

# pnpm
pnpm add discord.js-html-transcript

# yarn
yarn add discord.js-html-transcript

Requirements: Node.js 16+ and discord.js v14 or v15


🛠️ Get Started

Using the built-in message fetcher

const discordTranscripts = require('discord.js-html-transcript');

const channel = message.channel;

const attachment = await discordTranscripts.createTranscript(channel);

channel.send({
  files: [attachment],
});

Using your own messages

const discordTranscripts = require('discord.js-html-transcript');

const messages = await channel.messages.fetch({ limit: 100 });

const attachment = await discordTranscripts.generateFromMessages(messages, channel);

channel.send({
  files: [attachment],
});

TypeScript

import * as discordTranscripts from 'discord.js-html-transcript';

const attachment = await discordTranscripts.createTranscript(channel, {
  returnType: discordTranscripts.ExportReturnType.Attachment,
  filename: `transcript-${channel.id}.html`,
});

⚙️ Configuration

Both createTranscript and generateFromMessages accept an options object. All options are optional - sensible defaults are used when omitted.

const attachment = await discordTranscripts.createTranscript(channel, {
  // ── Output ────────────────────────────────────────────────
  returnType: 'attachment',       // 'buffer' | 'string' | 'attachment'
  filename: 'transcript.html',   // output filename (when returnType is 'attachment')

  // ── Message Fetching (createTranscript only) ──────────────
  limit: -1,                     // max messages to fetch (-1 = all)
  filter: (message) => true,     // filter which messages to include

  // ── Asset Preservation ────────────────────────────────────
  saveImages: false,             // legacy: save image attachments as data URIs
  saveAssets: false,             // save ALL remote assets as data URIs
  assets: {
    attachments: false,          // images, videos, audio, and files
    embeds: false,               // embed media + author/footer icons
    components: false,           // media gallery items, thumbnails, component files
    avatars: false,              // user avatars
    emojis: false,               // custom emoji + twemoji assets
    guildIcons: false,           // header + favicon guild icon
    inviteIcons: false,          // invite preview server icons
    roleIcons: false,            // highest-role icon images
    serverTagBadges: false,      // server tag badge images
  },

  // ── Feature Toggles ───────────────────────────────────────
  features: {
    search: true,                // built-in message search UI
    imagePreview: true,          // click-to-open image lightbox
    spoilerReveal: true,         // click spoilers to reveal
    messageLinks: true,          // reply click-to-scroll behavior
    profileBadges: true,         // APP badges, server tags, role icons
    embedTweaks: true,           // client-side embed border/style fixes
  },

  // ── Appearance ────────────────────────────────────────────
  footerText: 'Exported {number} message{s}.',
  poweredBy: true,               // show "Powered by" footer credit
  favicon: 'guild',             // 'guild' or a custom URL string
  hydrate: false,                // server-side hydrate the HTML

  // ── Callbacks ─────────────────────────────────────────────
  callbacks: {
    resolveChannel: (channelId) => channel.client.channels.fetch(channelId),
    resolveUser:    (userId)    => channel.client.users.fetch(userId),
    resolveRole:    (roleId)    => channel.guild?.roles.fetch(roleId),
    resolveInvite:  (code)      => /* return { name, icon, online, members, url } */,
    resolveImageSrc: (attachment, message) => /* return data URI or URL */,
    resolveAssetSrc: (asset)    => /* return data URI or URL */,
  },
});

Image Compression

Install sharp as a dev dependency to enable image compression:

npm install sharp --save-dev
const { TranscriptImageDownloader } = require('discord.js-html-transcript');

const attachment = await discordTranscripts.createTranscript(channel, {
  callbacks: {
    resolveImageSrc: new TranscriptImageDownloader()
      .withMaxSize(5120)          // 5MB max per image (in KB)
      .withCompression(40, true)  // 40% quality, convert to webp
      .build(),
  },
});

Saving All Assets (Offline Transcripts)

For transcripts that survive Discord CDN expiration:

const { TranscriptAssetDownloader } = require('discord.js-html-transcript');

const attachment = await discordTranscripts.createTranscript(channel, {
  saveAssets: true,
  // Or for fine-grained control:
  assets: {
    attachments: true,
    embeds: true,
    avatars: true,
    emojis: true,
    guildIcons: true,
  },
  callbacks: {
    resolveAssetSrc: new TranscriptAssetDownloader()
      .withMaxSize(10240)  // 10MB per asset
      .build(),
  },
});

🖼️ Preview

Messages & Attachments

| Normal Image | Multi Images | File Attachment | |:---:|:---:|:---:| | Normal Image | Multi Images | File |

Forwarded Messages & Reactions

| Forwarded Image | Forwarded + Reactions | |:---:|:---:| | Forwarded | Forwarded Reactions |

Polls, Threads & Mentions

| Poll | Thread | Mentions | |:---:|:---:|:---:| | Poll | Thread | Mentions |

Buttons, Select Menus & Slash Commands

| Buttons & Select Menu | Slash Command & Voice | |:---:|:---:| | Buttons | Slash |

Embeds

| Embed 1 | Embed 2 | Embed 3 | |:---:|:---:|:---:| | Embed | Embed | Embed |

Links & Invites

| Links | Invite Preview | |:---:|:---:| | Links | Invite |

Markdown Formatting

| Basic Formatting | Code Blocks | Headings | |:---:|:---:|:---:| | Basic | Code | Headings |

| Block Quotes | Lists | ANSI Styling | |:---:|:---:|:---:| | Quotes | Lists | ANSI |


📚 API Reference

createTranscript(channel, options?)

Fetches messages from a channel and generates an HTML transcript.

| Parameter | Type | Description | |-----------|------|-------------| | channel | TextBasedChannel | The channel to export | | options | CreateTranscriptOptions | Configuration options (see above) |

Returns: Promise<AttachmentBuilder | Buffer | string>

const transcript = await discordTranscripts.createTranscript(channel, {
  limit: 500,
  filter: (msg) => !msg.author.bot,
  returnType: 'attachment',
});

generateFromMessages(messages, channel, options?)

Generates a transcript from a pre-fetched array of messages.

| Parameter | Type | Description | |-----------|------|-------------| | messages | Message[] \| Collection<string, Message> | Messages to include | | channel | Channel | Channel for header/guild info | | options | GenerateFromMessagesOptions | Configuration options (see above) |

Returns: Promise<AttachmentBuilder | Buffer | string>

const messages = await channel.messages.fetch({ limit: 100 });
const transcript = await discordTranscripts.generateFromMessages(messages, channel);

Return Types

Use the ExportReturnType enum for type-safe return values:

import { ExportReturnType } from 'discord.js-html-transcript';

// Returns a Buffer
const buffer = await discordTranscripts.createTranscript(channel, {
  returnType: ExportReturnType.Buffer,
});

// Returns a string
const html = await discordTranscripts.createTranscript(channel, {
  returnType: ExportReturnType.String,
});

// Returns an AttachmentBuilder (default)
const attachment = await discordTranscripts.createTranscript(channel, {
  returnType: ExportReturnType.Attachment,
});

Asset Classes

TranscriptImageDownloader

const downloader = new TranscriptImageDownloader()
  .withMaxSize(5120)          // max file size in KB
  .withCompression(40, true)  // quality %, convert to webp
  .build();                   // returns a resolveImageSrc callback

TranscriptAssetDownloader

const downloader = new TranscriptAssetDownloader()
  .withMaxSize(10240)         // max file size in KB
  .build();                   // returns a resolveAssetSrc callback

📖 Full Example

const discordTranscripts = require('discord.js-html-transcript');
const { TranscriptAssetDownloader } = require('discord.js-html-transcript');

client.on('messageCreate', async (message) => {
  if (message.content === '!transcript') {
    const transcript = await discordTranscripts.createTranscript(message.channel, {
      returnType: 'attachment',
      filename: `transcript-${message.channel.id}.html`,
      limit: -1,
      assets: {
        attachments: true,
        embeds: true,
        avatars: true,
        emojis: true,
        guildIcons: true,
        inviteIcons: true,
        roleIcons: true,
        serverTagBadges: true,
      },
      features: {
        search: true,
        imagePreview: true,
        spoilerReveal: true,
        messageLinks: true,
        profileBadges: true,
        embedTweaks: true,
      },
      callbacks: {
        resolveAssetSrc: new TranscriptAssetDownloader()
          .withMaxSize(10240)
          .build(),
      },
      footerText: 'Exported {number} message{s}.',
      poweredBy: true,
    });

    await message.reply({
      content: '📄 Here is your transcript!',
      files: [transcript],
    });
  }
});

🆚 Comparison with Original

| Feature | discord-html-transcripts | discord.js-html-transcript | |---------|:---:|:---:| | Basic Messages & Embeds | ✅ | ✅ | | Forwarded Messages | ❌ | ✅ | | Voice Messages | ❌ | ✅ | | Polls / Voting | ❌ | ✅ | | Server Tags & Role Icons | ❌ | ✅ | | Buttons & Select Menus (Modern) | ❌ | ✅ | | Discord Invite Previews | ❌ | ✅ | | Image Preview Lightbox | ❌ | ✅ | | Message Search | ❌ | ✅ | | ANSI Code Block Styling | ❌ | ✅ | | Thread Preview Cards | ❌ | ✅ | | Fully Responsive Mobile UI | ❌ | ✅ | | Sticky Channel Header | ❌ | ✅ | | Feature Toggle System | ❌ | ✅ | | Granular Asset Saving | ❌ | ✅ | | Native File Attachment Cards | ❌ | ✅ | | Image Compression (sharp) | ❌ | ✅ | | Multi-Image Gallery Grid | ❌ | ✅ |


🤝 Credits

This package is built upon the excellent foundation of discord-html-transcripts by ItzDerock. Original styles powered by @derockdev/discord-components.

All new features, UI modernization, mobile responsiveness, and component redesigns by Wick Studio.


💬 Support


📜 License

This project is licensed under the Apache License 2.0.