Package Exports
- better-discord-transcripts
Readme
better-discord-transcripts
A nicely formatted HTML transcript generator for discord.js v14/v15. Drop-in replacement for discord-html-transcripts, with Components V2, thread modals, voice playback, and a built-in search UI. Inspired by community forks such as discord.js-html-transcript.
Images and voice messages are inlined by default so transcripts stay readable offline. Images are compressed to WebP via sharp - smaller HTML files without extra setup.
Requirements
- Node.js 18+
- discord.js
^14.26.4or^15(peer dependency - install it yourself) - sharp - bundled as a regular dependency; installed automatically with this package
You do not need to run npm install sharp separately. It ships with better-discord-transcripts and is used whenever saveImages is enabled (default).
Install
npm install better-discord-transcripts discord.jsMigration from discord-html-transcripts
One line change. Same options, same return types:
- const { createTranscript } = require('discord-html-transcripts');
+ const { createTranscript } = require('better-discord-transcripts');Your existing ticket code still works.
Quick start
const { createTranscript } = require('better-discord-transcripts');
const attachment = await createTranscript(channel, { limit: -1 });
await logChannel.send({ files: [attachment] });If you omit limit (or set -1), the full channel history is fetched, including thread messages on posts with hasThread.
Image compression (sharp)
With default options, attachments and embed images are downloaded and embedded as WebP base64 instead of raw PNG/JPEG. That keeps transcript file size down while everything still opens from a single .html file with no external CDN links.
| Setting | Value |
|---|---|
| Library | sharp (required dependency) |
| Format | WebP |
| Max dimension | 720px (longest side) |
| Quality | ~70% |
| Toggle | saveImages: false skips download and inlining entirely |
If sharp fails to load on an unsupported platform, the library falls back to the original image format and logs a one-time warning - the transcript still generates, but files may be larger.
// Default - images compressed with sharp
await createTranscript(channel);
// Skip images - smallest output, but Discord CDN links may expire later
await createTranscript(channel, { saveImages: false });Options
Same options as discord-html-transcripts, plus saveVoiceMessages:
| Option | Type | Default | Description |
|---|---|---|---|
limit |
number |
all messages | Max messages to fetch. -1 or omit = everything |
filter |
(m) => boolean |
none | Filter messages before render |
returnType |
'attachment', 'buffer', 'string' |
'attachment' |
Or use the ExportReturnType enum |
filename |
string |
transcript-{channelName}.html |
Attachment filename |
saveImages |
boolean |
true |
Download images and inline as WebP base64 via sharp (max 720px, ~70% quality) |
saveVoiceMessages |
boolean |
true |
Download voice messages and inline as base64 so they stay playable after Discord URLs expire |
footerText |
string |
Exported {number} message{s}. |
Footer line before the powered-by credit |
poweredBy |
boolean |
true |
Show "Powered by better-discord-transcripts" |
favicon |
'guild' or string |
'guild' |
Guild icon or a custom URL |
hydrate |
boolean |
false |
Server-side hydration of web components (slower, works offline) |
callbacks |
object | auto | resolveUser, resolveRole, resolveChannel, resolveImageSrc, resolveVoiceSrc |
Disable image or voice inlining
// No images (voice messages still inlined by default)
await createTranscript(channel, { saveImages: false });
// Voice only (images stay as Discord CDN links, but links may break later - remember that!)
await createTranscript(channel, { saveImages: false, saveVoiceMessages: true });
// Neither - smallest file, but CDN links may break later - remember that!
await createTranscript(channel, { saveImages: false, saveVoiceMessages: false });TypeScript
import { createTranscript, ExportReturnType } from 'better-discord-transcripts';
const transcript = await createTranscript(channel, {
returnType: ExportReturnType.String,
});generateFromMessages - when you already have messages
createTranscript fetches messages from Discord for you.
generateFromMessages skips that step. You pass a Message[] or Collection you already loaded (custom fetch, cached ticket log, filtered list, etc.) and get the same HTML output.
Use it when:
- you fetched messages yourself (custom pagination, database, bot cache)
- you want to render only a subset without calling the API again
- you deleted the channel but still have message objects in memory
const { generateFromMessages } = require('better-discord-transcripts');
// messages = Message[] or Collection from channel.messages.fetch(), your DB, etc.
const attachment = await generateFromMessages(messages, channel, {
poweredBy: false,
filename: 'ticket-log.html',
});Same options as createTranscript, except there is no limit or filter (you control the array yourself). saveImages and saveVoiceMessages default to true here as well.
Interactive HTML viewer
Built into every transcript:
- Search - find messages by text or ID, keyboard navigation
- Pinned messages - header panel with jump-to-message
- Member list - participants and message counts
- Thread modal - click a thread bar to read the full thread inline
- Image lightbox - click images to zoom
- Voice playback - play button and waveform (works offline when
saveVoiceMessagesis on) - Spoiler reveal - click to reveal spoilers
Content rendered
- Plain text, markdown, mentions, emojis, timestamps
- Embeds, attachments, stickers, reactions
- Replies, forwards, slash command headers
- Components V2 - Container, Section, TextDisplay, Media Gallery, Thumbnail, File, Separator, buttons
- Polls with vote bars
- Voice messages - waveform from
attachment.waveform, duration, inline<audio> - System messages - pins, thread created, joins, and more
- Server tags, role icons, verified bot badges
- Cross-server reply indicators
Included by default
- Full channel fetch when
limitis omitted - Full thread fetch on messages with
hasThread - sharp installed and used for image inlining (
saveImages: true) - Images inlined as WebP base64 (720px max, ~70% quality)
- Voice messages inlined as base64 (
saveVoiceMessages: true) for offline playback
API
| Export | Description |
|---|---|
createTranscript(channel, options?) |
Fetch messages from a channel and render HTML |
generateFromMessages(messages, channel, options?) |
Render HTML from messages you already have |
ExportReturnType |
Attachment, Buffer, or String |
default |
{ createTranscript, generateFromMessages } |
License
Fork and successor of discord-html-transcripts by ItzDerock.