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.
Maintainers
Keywords
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-transcriptRequirements: 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-devconst { 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 |
|:---:|:---:|:---:|
|
|
|
|
Forwarded Messages & Reactions
| Forwarded Image | Forwarded + Reactions |
|:---:|:---:|
|
|
|
Polls, Threads & Mentions
| Poll | Thread | Mentions |
|:---:|:---:|:---:|
|
|
|
|
Buttons, Select Menus & Slash Commands
| Buttons & Select Menu | Slash Command & Voice |
|:---:|:---:|
|
|
|
Embeds
| Embed 1 | Embed 2 | Embed 3 |
|:---:|:---:|:---:|
|
|
|
|
Links & Invites
| Links | Invite Preview |
|:---:|:---:|
|
|
|
Markdown Formatting
| Basic Formatting | Code Blocks | Headings |
|:---:|:---:|:---:|
|
|
|
|
| Block Quotes | Lists | ANSI Styling |
|:---:|:---:|:---:|
|
|
|
|
📚 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 callbackTranscriptAssetDownloader
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
- 🌐 Discord Server: discord.gg/wicks
- 🐛 Bug Reports: GitHub Issues
- 📦 NPM: discord.js-html-transcript
📜 License
This project is licensed under the Apache License 2.0.
