Minecraft Heads API
The Minecraft Heads API is an open-source Node.js service that renders Minecraft player heads, full bodies, isometric views, and raw skin textures as PNG images. It supports both Java Edition (via the Mojang API) and Bedrock Edition (via the GeyserMC API), with automatic edition detection based on the input you provide.
The public instance is hosted at api.mcheads.org. You can also self-host the API on your own infrastructure.
What It Does
Given a player's username, UUID, or Bedrock identifier, the API fetches their skin from the appropriate upstream service and renders one of several image types:
| Render Type | Endpoint | Description |
|---|---|---|
| Head | /head/:input/:size |
Front-facing head, base skin layer |
| Head with Hat | /head/:input/:size/hat |
Front-facing head with the hat overlay layer composited on top |
| Full Body | /player/:input/:size |
Full body render showing head, torso, arms, and legs |
| Isometric Body | /avatar/:input/:direction/:size |
3D isometric full body, viewed from the left or right |
| Isometric Head | /ioshead/:input/:direction |
3D isometric head only |
| Isometric Body (iOS) | /iosbody/:input/:direction |
3D isometric full body (alternative endpoint) |
| Raw Skin | /skin/:input |
The original skin texture file as a PNG |
| Download | /download/:input |
Same as raw skin, but served as a file attachment |
All image endpoints return image/png responses. No API key is required.
Supported Editions
Java Edition
Java players are identified by their Mojang username or UUID. The API resolves usernames to UUIDs using the Mojang API (api.mojang.com), then fetches the player's skin texture from the Mojang session server.
GET /head/Notch/128
GET /head/069a79f444e94726a5befca90e38aaf5/128
Both formats work identically. The API accepts UUIDs with or without dashes.
Bedrock Edition
Bedrock players are identified by their Xbox Live XUID or gamertag. The API resolves these through the GeyserMC API (api.geysermc.org), which provides skin data for Bedrock players.
GET /head/0000123456789/128 # XUID (starts with 0000)
GET /head/.ExampleGamertag/128 # Gamertag (prefixed with a dot)
If a Bedrock player has no skin data available, the API falls back to the default Steve skin.
How It Works
At a high level, every request follows the same path: parse the input, check the cache, fetch the skin if needed, render the image, cache the result, and respond. The sections below explain each stage in detail.
Render Pipeline
The rendering process follows these steps:
Input parsing -- The API cleans the input (stripping
.pngsuffixes, sanitizing parameters) and determines whether the player is Java or Bedrock edition. ThecleanParamsutility normalizes the URL parameters, and theparseSizeutility converts the size string to an integer (defaulting to 128 if missing or invalid).Cache lookup -- The API checks the database for a cached render matching the endpoint, input, size, and options. If a valid cache entry exists (less than 1 hour old), it is returned immediately. Cache hits skip all network requests and image processing, making them very fast.
Profile resolution -- For cache misses, the API fetches the player's profile and skin URL from the appropriate upstream service. For Java players, this is a two-step process: resolve the username to a UUID via
api.mojang.com, then fetch the session profile (which contains the skin URL) fromsessionserver.mojang.com. For Bedrock players, the GeyserMC API atapi.geysermc.orghandles both gamertag-to-XUID resolution and skin data retrieval.Image rendering -- The raw skin texture is downloaded from the resolved URL and processed into the requested render type. The skin texture is a standard Minecraft skin format -- either 64x64 pixels (new format, used since Minecraft 1.8) or 64x32 pixels (legacy format). Each body part occupies a specific region of this texture, and the rendering code crops, scales, and composites these regions according to the requested output.
Caching -- The rendered PNG buffer is stored in the database with a 1-hour TTL, keyed by a combination of endpoint, input, size, and options. Subsequent requests for the same render will hit the cache until it expires.
Response -- The PNG buffer is sent to the client with
Content-Type: image/pngand appropriate security and compression headers.
Image Processing Libraries
The API uses three image libraries, each suited to different render types:
Sharp -- Used for head renders. Extracts the 8x8 pixel head region from the skin texture, scales it to the requested size using nearest-neighbor interpolation (preserving pixel art), and optionally composites the hat overlay layer.
Jimp -- Used for full body renders. Assembles the body from individual parts (head, torso, left arm, right arm, left leg, right leg), each cropped from the skin texture at their standard coordinates. Supports both old-format (64x32) and new-format (64x64) skins.
node-canvas -- Used for isometric 3D renders. Applies affine transforms to project each face of the body onto an isometric plane, producing a 3D appearance. The final canvas is scaled down with Lanczos resampling (via Sharp) for smooth output.
Caching
All renders are cached for 1 hour in the configured database. The cache key is a combination of the endpoint name, player input, size, and any options (like hat or direction). This means:
GET /head/Notch/128andGET /head/Notch/256are cached separately.GET /head/Notch/128andGET /head/Notch/128/hatare cached separately.GET /avatar/Notch/left/128andGET /avatar/Notch/right/128are cached separately.- Repeated requests for the same render within 1 hour are served from cache without hitting the Mojang or GeyserMC APIs.
Cache entries older than 1 hour are not proactively deleted. They remain in the database but are ignored by the cache lookup query, which filters by created_at > (now - 1 hour). When the same key is requested again after expiry, the new render overwrites the stale entry using an upsert (INSERT OR REPLACE in SQLite, ON CONFLICT DO UPDATE in PostgreSQL).
The database backend is configurable. By default, the API uses a local SQLite file (new_minecraft_heads.db). For production deployments, you can set the DATABASE_URL environment variable to use PostgreSQL instead. See the Self-Hosting guide for database configuration details.
MHF Preset Heads
The API includes a set of preset MHF (Minecraft Head Format) heads. These are well-known UUIDs that Mojang provides for common mob and item textures:
GET /head/MHF_Creeper/128
GET /head/MHF_Skeleton/64
A full list of available MHF heads is available at:
GET /minecraft/mhf
Usage Statistics
The API tracks how many renders have been served for each edition:
| Endpoint | Description |
|---|---|
GET /allstats |
Total Java Edition render count |
GET /allstatsbedrock |
Total Bedrock Edition render count |
GET /allstatsSorted |
All stats sorted by count (descending) |
These return JSON responses, not images.
Health Monitoring
The /health endpoint returns a JSON status report including:
- Overall system status (
green,yellow, orred) - External API reachability (Mojang API ping with 5-second timeout)
- Response time for the health check itself
- Server uptime in seconds
- Memory usage (heap used and heap total in MB)
- Recent health check summary from the last 5 minutes
curl https://api.mcheads.org/health
The status is determined by analyzing recent health check logs stored in the database. If more than 50% of recent checks are errors, the status is red. If any errors exist or more than 30% are warnings, the status is yellow. Otherwise, it is green. The API stores up to 10,000 health log entries, pruning older ones on startup.
Project Architecture
The codebase is organized into route handlers and utility modules:
server.js Entry point, Express setup, middleware
routes/
head.js GET /head/:input/:size/:option
player.js GET /player/:input/:size/:option
avatar.js GET /avatar/:input/:direction/:size
skin.js GET /skin/:input
download.js GET /download/:input
ios.js GET /ioshead and /iosbody endpoints
mhf.js GET /minecraft/mhf
stats.js GET /allstats, /allstatsbedrock, /allstatsSorted
health.js GET /health
utils/
minecraft.js Edition detection, Mojang + GeyserMC API calls
imageProcessor.js All image rendering functions
database.js SQLite/PostgreSQL abstraction, caching, stats
mhfHeads.js MHF UUID-to-name mappings
urlHelpers.js Parameter cleaning and size parsing
Each route handler follows the same pattern: clean parameters, build a cache key, check the cache, call getProfile to resolve the player, call the appropriate render function, cache the result, and return the PNG.
Technology Stack
| Component | Technology |
|---|---|
| Runtime | Node.js |
| Framework | Express |
| Image rendering | Sharp, Jimp, node-canvas |
| Database | SQLite (better-sqlite3) or PostgreSQL (pg) |
| HTTP client | Axios |
| Security | Helmet (HTTP headers), CORS |
| Compression | compression (gzip) |
Security
The API applies several security measures through Express middleware:
- Helmet -- Sets secure HTTP headers (X-Content-Type-Options, X-Frame-Options, Content-Security-Policy, etc.). The
crossOriginResourcePolicyis set tocross-originso that images can be loaded from any domain. - CORS -- All origins are allowed, since the API is designed to serve images to any website.
- Compression -- Gzip compression is applied to all responses.
- No authentication -- The API is intentionally open. There are no API keys, rate limits, or access controls at the application level. If you need rate limiting, configure it at the reverse proxy level (see Self-Hosting).
License
The Minecraft Heads API is released under the MIT License. Copyright (c) Jace Sleeman.