blurhash-url
v1.4.1
Published
Generate image URLs with embedded Blurhash placeholders.
Maintainers
Readme
Blurhash URL generates image URLs with embedded Blurhash placeholders.
Features
- URL-powered placeholders: Image URLs with embedded Blurhash placeholder data; enables rapid-render image placeholders and optimized web vitals (via
visionary-image,visionary-image-js). - Cache-friendly: Deterministic URLs with path-based encoding improve cache hits across browsers and CDNs.
- Universal: Works in browsers, Node.js, and worker environments.
- Module support: Compatible with ES Modules and CommonJS.
- Lightweight: Under 3 kB minzipped.
Installation
pnpm add blurhash-urlUsage
Generate a Blurhash URL
import { generateBlurhashUrl } from "blurhash-url";
const blurhashUrl = generateBlurhashUrl({
url: "image:42", // Image ID or Image URL
bcc: "#8696ac", // Background color code (base layer)
blurhash: "AUFZT.%L_N%1", // Blurhash code
sourceHeight: 720, // Dimensions of image this placeholder represents
sourceWidth: 960, // Used to determine aspect ratio and max-width of placeholder
});This generates the following Blurhash URL with placeholder data embedded. The bolded section below highlights the encoded placeholder data ("Visionary Code"):
https://blurhash.link/image/aW1nIzQyITk2MCE3MjAhODY5NmFjIUFVRlpULiVMX04lMQ/image.jpg
You can configure your own domain to serve Blurhash URLs. See Using Your Own Domain for more details.
Anatomy of a Blurhash URL
A Blurhash URL consists of 3 or 4 path segments:
| | Base path | | Visionary Code | | Options (optional) | | Filename |
| --- | --------- | --- | -------------------------------------- | --- | ------------------ | --- | ----------- |
| / | image | / | <base64url-encoded placeholder data> | / | <option tokens> | / | image.jpg |
Base path
Defaults to /image.
Visionary Code
The Visionary Code is a base64url-encoded string with the following fields (in order):
| Index | Attribute | Description |
| ----- | --------------------- | ----------------------------------------------------------------------------------- |
| 0 | Image URL / ID | The URL of the image or an internal image ID. required |
| 1 | Image width | Used to calculate aspect ratio and constrain placeholder width. required |
| 2 | Image height | Used to calculate aspect ratio and constrain placeholder height. required |
| 3 | Background color code | Base layer color (e.g. #BACCAE). |
| 4 | Blurhash code | Blurhash code for the image. |
| 5 | Alt text | Optional alt text. |
[!NOTE] The first three fields are required to render a properly sized placeholder. If the other fields are omitted, a placeholder with a semi-transparent black background (
rgba(0, 0, 0, 0.7)) will be rendered.
Image Options
Image options control how the image is served. To add them, include comma-separated tokens in the path segment between the Visionary Code and the filename.
/image/djQyITEyODAhODUzITg2OTZhYw/<options>/image.jpg
[!NOTE] Sort option tokens in lexicographic order (e.g.
download,jpg, notjpg,download) to produce a deterministic, canonical URL for a given set of image options. This improves cache hit rates across browsers and CDNs. URLs generated byblurhash-urlare properly sorted.
Example
Options tokens instructing the server to return an xl sized image as a downloadable file (content-type: attachment).
download,xl
These options in the Blurhash URL: https://blurhash.link/image/djQyITEyODAhODUzITg2OTZhYw/download,xl/image.jpg
Format tokens
Specify the image format using one of the following tokens:
auto (default), avif, jpeg, webp
autoselects the most ideal format based on the browser'sAcceptheader (default)avif,jpeg,webpforce the image to be served in the specified format.
Format tokens are defined in the ImageFormatToken enum in enum.ts.
Size tokens
Specify the image size using one of the following tokens (in increasing order):
xs, sm, md, lg, xl, xxl, 4k, 5k
Size tokens are defined in the ImageSizeToken enum in enum.ts. The size-to-pixel mapping is defined in the IMAGE_SIZES variable in constants.ts.
Control tokens
| token | description |
| ---------- | ----------------------------------------------------------------------------------------------------------- |
| debug | Instructs the server to display debug information for this URL. |
| download | Instructs the server to set Content-Disposition: attachment in response headers. |
| follow | Instructs the server to issue a redirect and follow the URL field for external URLs on whitelisted domains. |
Filename
Defaults to image.jpg.
[!TIP] Use descriptive filenames (e.g.
tokyo-shibuya-crossing-rainy-night.jpg) to improve image discoverability in search engines.
The filename can be modified to force a cache refresh. If an outdated image is still being served due to caching, append a version number or date (e.g. starship-stacked-v2.jpg or starship-stacked-20250609.jpg) to ensure the latest version is loaded.
Using Your Own Domain
To serve Blurhash URLs from your own domain, configure two route handlers:
app.get("/image/:visionaryCode/:filename", handler);
app.get("/image/:visionaryCode/:options/:filename", handler);handler extracts the Blurhash placeholder data from the URL and serves the corresponding image.
import { parseVisionaryString } from "blurhash-url";
export const handler = (request: Request) => {
const data = parseVisionaryString(request.url);
const imageUrl = data.fields.url;
// Load, serve, or redirect your image as needed
};Frequently Asked Questions
What are the benefits of using Blurhash URL?
Blurhash URLs embed image placeholder data directly in the URL, letting components like visionary-image and visionary-image-js render placeholders instantly. This improves page load performance by reserving layout space early to prevent cumulative layout shift (CLS) and improve perceived load time.
Because the data is self-contained in the URL, no API or database schema changes are needed.
How does progressive image loading work?
Blurhash URL-compatible components render images in three layers. The first background-color layer is server-rendered, so the browser reserves its space during layout and paints it in the Critical Rendering Path at First Contentful Paint (FCP), before DOMContentLoaded and eliminating Cumulative Layout Shift (CLS). Client JS then paints a BlurHash layer on top, and the full-resolution image replaces it on load.
Rendering meaningful pixels this early improves both perceived load time and measured metrics like FCP, LCP, and CLS in PageSpeed Insights.
How is the Visionary Code structured?
Visionary Code fields are separated by an exclamation mark (!) before being base64url-encoded. This separator was chosen to avoid conflicts with characters used by Blurhash's base83 encoding. For more details, see this section of the Blurhash Algorithm docs.
