The Tech Behind Twitch Emotes: From Upload to CDN
Twitch emotes are the universal language of live streaming. From Kappa to PogChamp, these tiny images carry enormous cultural weight. But have you ever wondered what happens technically when an emote is uploaded, processed, and served to millions of users in real-time?
The Emote Ecosystem
Twitch supports several types of emotes:
- Global emotes — available to everyone (Kappa, LUL, etc.)
- Subscriber emotes — channel-specific, unlocked via sub
- Bits emotes — unlocked through cheering
- Follower emotes — newer tier, free for followers
- Third-party emotes — via BetterTTV (BTTV) and FrankerFaceZ (FFZ)
For a deep dive into specific emotes, their origins, and meanings, optistream.fr has detailed emote pages covering the most popular ones across the platform.
Upload and Processing
When a streamer or artist uploads a new emote, here is what happens behind the scenes:
1. Validation
The image must meet strict requirements:
- Dimensions: 28x28, 56x56, and 112x112 pixels
- Format: PNG with transparency support
- File size: under 1MB per size
- Content: reviewed by Twitch moderation (automated + manual)
Upload → Size validation → Format check → Content moderation → Approval
2. Processing Pipeline
Once approved, the emote enters a processing pipeline:
# Simplified emote processing
def process_emote(original_image):
sizes = [28, 56, 112]
variants = {}
for size in sizes:
resized = resize_with_quality(original_image, size, size)
webp = convert_to_webp(resized)
variants[f"{size}x{size}_png"] = resized
variants[f"{size}x{size}_webp"] = webp
return variants
Twitch generates multiple variants: PNG, WebP, multiple sizes, and animated variants for GIF-based emotes.
3. CDN Distribution
Processed emotes are pushed to Twitch's CDN:
https://static-cdn.jtvnw.net/emoticons/v2/{emote_id}/default/dark/{size}
Rendering in Chat
When a viewer types an emote code in chat:
- Text parsing — the chat message is scanned for known emote codes
-
Token replacement — matched codes are replaced with
<img>tags - Lazy loading — emotes are loaded on-demand
- Caching — the browser caches emote images aggressively
function renderEmotes(message, emoteMap) {
let rendered = message;
for (const [code, id] of Object.entries(emoteMap)) {
const img = `<img src="https://static-cdn.jtvnw.net/emoticons/v2/${id}/default/dark/1.0"
alt="${code}" class="chat-emote" loading="lazy">`;
rendered = rendered.replaceAll(code, img);
}
return rendered;
}
Third-Party Emote Extensions
BTTV and FFZ extend Twitch's native emote system with their own CDN infrastructure, client-side parsing, and support for animated emotes (GIF/APNG/WebP).
Performance at Scale
A popular stream with 100K concurrent viewers seeing 50 unique emotes per minute means 5 million emote image requests per minute. CDN caching and browser caching make this manageable, with WebP cutting bandwidth by 25-35% vs PNG.
The Cultural Impact
Emotes have become a language of their own. Resources like the emote directory on Optistream help newcomers decode the visual vocabulary of Twitch.
What is your favorite Twitch emote? Let me know in the comments! 💜
Top comments (0)