ShortPixel is an image optimization service built to make websites faster with minimal effort. Official website: https://shortpixel.com/.
In practice, ShortPixel helps you shrink heavy images, serve modern formats like WebP/AVIF, and keep visual quality high. Real-world results can go up to 86% image compression, which means faster pages, better UX, and stronger SEO outcomes.
This repository is the Node.js SDK for that product. It gives you both:
- a simple, abstract DX (
optimize,upscale,rescale,backgroundChange, etc.) - and low-level, explicit control (
fromFile,fromUrl,Source, per-itemMeta, polling/retry tuning)
This README is the complete documentation for the current API surface in this repository.
- What this SDK solves
- Installation
- Quick Start
- Mental model: Client + Source + Meta
- Abstraction layers
- Full client API reference
- Supported API parameters
- Practical examples (cookbook)
- Power User Guide
- Errors, retry, debugging
- Running tests
- Important notes
ShortPixel itself focuses on one core goal: keep images looking great while making them much smaller and easier to deliver at scale.
Inside the API, there are two main endpoints:
- Reducer API: optimizes images from remote URLs.
- Post-Reducer API: optimizes local files or buffers uploaded as multipart.
This SDK hides transport details, polling, retry strategy, and response normalization, while still giving you full access to API options.
In short:
- Want explicit control: use
fromFile,fromUrl, etc. - Want fast and simple DX: use
optimize(...)and feature-first helpers (upscale,rescale,backgroundChange, etc). - Want advanced control: use
Source, inspectlastMetas, tune polling/retries/timeouts.
npm i @shortpixel-com/shortpixelAfter installation, import from shortpixel:
import SHORTPIXEL from "@shortpixel-com/shortpixel";- Current state: version 1 (v1.x), ESM-only package
- In your app
package.json, you must set:
{
"type": "module"
}- ESM (
"type": "module") - Modern Node.js (ideally Node 20+)
It may work by not setting type at all, but it's not stable.
import SHORTPIXEL from "@shortpixel-com/shortpixel";
const { ShortPixelClient } = SHORTPIXEL;
const cli = new ShortPixelClient({
apiKey: process.env.SHORTPIXEL_API_KEY,
});
const src = await cli.upscale("assets/panda.png", 2, {
lossy: 2,
convertto: "+webp",
});
const files = await src.downloadTo("./output");
console.log(files);Desired feature-first style:
const src = await cli.upscale("/path/input.png", 2);
await src.downloadTo("/path/output");This is the entry point. It can:
- configure API key and defaults,
- accept multiple input forms,
- route to the correct ShortPixel endpoint,
- expose higher-level abstractions.
Each operation returns a Source.
Source contains:
lastMetas: metadata returned by the API for the latest operation,lastResults: input-to-meta mapping,downloadTo(outputDir): downloads optimized outputs locally.
For regular usage, it's recommended to not directly use the Source.
Each optimized item has metadata with status (Status.Code) and output URLs (LossyURL, LosslessURL, WebP*, AVIF*, etc). Useful for debugging
The SDK is intentionally designed with multiple abstraction layers. Use the one that matches your team and use case.
Classic and very explicit:
fromUrl(url, options)fromUrls(urls, options)fromURLs(urls, options)(alias)fromFile(path, options)fromFiles(pathsOrObjects, options)fromBuffer(buffer, filename, options)fromBuffers(buffersOrObjects, defaultName, options)
Advantages:
- clear endpoint intent (Reducer vs Post-Reducer)
- easy to reason about in large codebases
Same operations, naming focused on user intent:
optimizeUrl,optimizeUrlsoptimizeFile,optimizeFilesoptimizeBuffer,optimizeBuffers
Advantages:
- more natural naming for most developers
Pass input, and the SDK routes automatically.
- URL string ->
fromUrl - local path string ->
fromFile Buffer->fromBuffer- array of URLs ->
fromUrls - array of file paths/entries ->
fromFiles - array of buffers/entries ->
fromBuffers - object shapes:
{ url },{ urls }{ file },{ path },{ filename }{ buffer, filename? },{ buffers, defaultName? },{ files }
Do not mix remote URLs and local paths in the same string array (optimize(["https://...", "./a.png"]) throws).
Methods that set feature defaults, then allow full override via options:
- quality:
lossless,lossy,glossy - resize/upscale:
upscale,rescale,resizeOuter,resizeInner,smartCrop - background:
backgroundChange,backgroundRemove - format:
convert - metadata/color:
keepExif,cmykToRgb - workflow:
wait,refresh
These methods are intelligent aliases built on top of optimize(...).
new ShortPixelClient({ apiKey, pluginVersion = "NP001", proxy = null })apiKeyis required.pluginVersionmust be a string with max 5 characters. Although it's optionalproxyis optional and can usehttp://orhttps://proxy URLs.- All final outbound image/API requests are forced to
https://;http://targets are rejected with error.
HTTPS is mandatory in this SDK for security reasons:
- protects image/API traffic against interception (confidentiality),
- prevents payload tampering in transit (integrity),
- validates the remote host identity via TLS certificates (authenticity).
Behavior details:
- direct input URLs over
http://are rejected before network calls, - output/polling metadata that may come back as
http://from upstream APIs is upgraded tohttps://automatically, - the SDK never performs final outbound requests over plain HTTP.
cli.set(name, value)Useful keys:
timeout(ms)retriesretryDelay(ms)waitconverttoproxypoll->{ enabled, interval, maxAttempts }
Please consider increasing the poll interval and maxAttempts if the polling process fails due to timeout. This is required on complex operations like background-removal or smart resizing.
fromUrl(url, options)fromUrls(urls, options)fromURLs(urls, options)fromFile(path, options)fromFiles(pathsOrEntries, options)fromBuffer(buffer, filename, options)fromBuffers(buffersOrEntries, defaultName, options)
optimize(input, options)optimizeUrl(url, options)optimizeUrls(urls, options)optimizeFile(path, options)optimizeFiles(paths, options)optimizeBuffer(buffer, filename, options)optimizeBuffers(buffers, defaultName, options)
lossless(input, options)->lossy: 0lossy(input, options)->lossy: 1glossy(input, options)->lossy: 2wait(input, seconds, options)->wait: secondsupscale(input, factor = 2, options)->upscale: factorrescale(input, width, height, options)->resize: 1resizeOuter(input, width, height, options)-> alias ofrescaleresizeInner(input, width, height, options)->resize: 3smartCrop(input, width, height, options)->resize: 4convert(input, convertto, options)->converttocmykToRgb(input, enabled = true, options)->cmyk2rgbkeepExif(input, enabled = true, options)->keep_exifbackgroundChange(input, background = 1, options)->bg_removebackgroundRemove(input, options)->bg_remove: 1refresh(input, enabled = true, options)->refresh
See the Official API documentation for more information : https://shortpixel.com/api-docs
const Source = cli.Source(); // Source is a classAny ShortPixel-supported parameter can be passed via options.
| Parameter | Purpose | SDK usage |
|---|---|---|
key |
API key | constructor new ShortPixelClient({ apiKey }) |
plugin_version |
client identifier (max 5 chars) | constructor pluginVersion |
lossy |
0=lossless, 1=lossy, 2=glossy | options.lossy or lossless/lossy/glossy |
wait |
wait seconds in API call | options.wait or wait(...) |
upscale |
0,2,3,4 | options.upscale or upscale(...) |
resize |
0 none, 1 outer, 3 inner, 4 smart crop | options.resize or rescale/resizeInner/smartCrop |
resize_width |
resize width | options.resize_width |
resize_height |
resize height | options.resize_height |
cmyk2rgb |
CMYK -> RGB conversion | options.cmyk2rgb or cmykToRgb(...) |
keep_exif |
preserve EXIF | options.keep_exif or keepExif(...) |
convertto |
output conversion (webp/avif/etc) | options.convertto or convert(...) |
bg_remove |
remove/change background | options.bg_remove or backgroundChange(...) |
refresh |
refetch/re-optimize source | options.refresh or refresh(...) |
urllist |
URL list payload | handled internally by fromUrl(s)/optimize |
paramlist |
per-URL settings for reducer batch | options.paramlist |
returndatalist |
custom payload echoed by API | options.returndatalist |
Before requests are sent, the SDK validates at minimum:
pluginVersionmax 5 charswaitin[0..30]upscalein{0,2,3,4}- if
resize > 0, valid dimensions are required
const src = await cli.fromFile("assets/panda.png", { lossy: 1 });
await src.downloadTo("./output");const src = await cli.optimizeFile("assets/otherImage.png", { lossy: 2 });
await src.downloadTo("./output");const srcA = await cli.optimize("test/assets/panda-small.png", { lossy: 0 });
const srcB = await cli.optimize("https://images.unsplash.com/photo-1506744038136-46273834b3fb", { lossy: 1 });
const srcC = await cli.optimize(Buffer.from("..."), { filename: "upload.png", lossy: 2 });const src = await cli.upscale("test/assets/panda-small.png", 4, {
lossy: 0,
keep_exif: 1,
});
await src.downloadTo("test/output-real");const src = await cli.rescale("test/assets/panda-small.png", 1024, 768, {
convertto: "+avif",
});
await src.downloadTo("test/output-real");const src = await cli.resizeInner("test/assets/panda-small.png", 400, 400, {
keep_exif: 1,
});
await src.downloadTo("test/output-real");const src = await cli.smartCrop("test/assets/panda-small.png", 300, 200, {
convertto: "+webp",
});
await src.downloadTo("test/output-real");Transparent output:
const src = await cli.backgroundRemove("test/assets/panda-small.png", {
convertto: "+webp",
});
await src.downloadTo("test/output-real");Solid color + alpha (#rrggbbxx):
// Warning, this might take a while to process
const src = await cli.backgroundChange("test/assets/panda-small.png", "#00ff0080", {
lossy: 2,
convertto: "+webp",
});
await src.downloadTo("test/output-real");Custom background image URL:
const src = await cli.backgroundChange(
"test/assets/panda-small.png",
"https://example.com/background.jpg",
{ convertto: "+webp" }
);
await src.downloadTo("test/output-real");Original + WebP:
await cli.convert("test/assets/panda-small.png", "+webp");WebP + AVIF only (no original optimization):
await cli.convert("test/assets/panda-small.png", "webp|avif");Original + WebP + AVIF:
await cli.convert("test/assets/panda-small.png", "+webp|+avif");const src = await cli.fromFiles([
"test/assets/panda-small.png",
"test/assets/panda-small.png",
], {
lossy: 1,
convertto: "+webp",
});
await src.downloadTo("test/output-real");const src = await cli.fromUrls([
"https://images.unsplash.com/photo-1506744038136-46273834b3fb",
"https://images.unsplash.com/photo-1506744038136-46273834b3fb"
], {
lossy: 2,
convertto: "+avif",
});
await src.downloadTo("test/output-real");const b1 = Buffer.from("...");
const b2 = Buffer.from("...");
const src = await cli.fromBuffers([
{ buffer: b1, filename: "one.png" },
{ buffer: b2, filename: "two.png" },
], "fallback.bin", {
lossy: 1,
});
await src.downloadTo("test/output-real");Use this when you want deep control over runtime behavior, observability, and tuning.
cli.set("timeout", 45000);
cli.set("retries", 4);
cli.set("retryDelay", 1000);cli.set("poll", {
enabled: true,
interval: 2000,
maxAttempts: 20,
});When API responses come back with pending status (Status.Code = 1), the SDK polls until ready (2) or until attempt budget is exhausted.
cli.set("convertto", "+webp");Any call without an explicit options.convertto inherits +webp.
const src = await cli.fromFile("test/assets/panda-small.png", {
lossy: 2,
convertto: "+webp|+avif",
});
for (const m of src.lastMetas || []) {
console.log("Code:", Number(m?.Status?.Code));
console.log("Message:", m?.Status?.Message);
console.log("LossyURL:", m?.LossyURL);
console.log("WebP:", m?.WebPLossyURL || m?.WebPLosslessURL);
console.log("AVIF:", m?.AVIFLossyURL || m?.AVIFLosslessURL);
}If you need maximum internals control:
const SourceCtor = cli.Source();
const src = new SourceCtor({ filename: "test/assets/panda-small.png" });
src.setOptions({
lossy: 2,
upscale: 2,
convertto: "+webp",
});
await src.postReducer();
console.log(src.lastMetas);
await src.downloadTo("test/output-real");For URL-based flows, call src.reducer() instead of postReducer().
downloadTo is convenient, but you can use metadata URLs directly for custom naming/storage (S3, object stores, CDN pipelines, etc).
CODE IN PROGRESSFeature helpers set defaults, but options has priority:
await cli.lossless("test/assets/panda-small.png", {
lossy: 2,
});The call above effectively runs with lossy: 2.
The SDK uses typed errors:
ShortPixelErrorShortPixelAuthErrorShortPixelQuotaErrorShortPixelTemporaryErrorShortPixelInvalidRequestErrorShortPixelBatchError
Error objects may include:
httpStatusspCodespMessagepayload
Recommended handling pattern:
try {
const src = await cli.fromFile("test/assets/panda-small.png", { upscale: 9 });
await src.downloadTo("test/output-real");
} catch (err) {
console.error("name:", err?.name);
console.error("spCode:", err?.spCode);
console.error("spMessage:", err?.spMessage);
console.error("httpStatus:", err?.httpStatus);
console.error("payload:", err?.payload);
}In batch mode, one or more failed items can raise ShortPixelBatchError, which includes items (index, input, meta/error per item).
Retry is used for temporary failures (for example 429, 5xx, temporary SP codes). Configure via:
retriesretryDelaytimeout
Please install the development dependency jest js before running tests.
Unit tests:
npm testReal API integration tests (consume ShortPixel credits):
RUN_SHORTPIXEL_REAL=1 SHORTPIXEL_API_KEY="your-key" npm testRun specific integration groups:
RUN_SHORTPIXEL_REAL=2 SHORTPIXEL_API_KEY="your-key" npm test
RUN_SHORTPIXEL_REAL=3 SHORTPIXEL_API_KEY="your-key" npm test
RUN_SHORTPIXEL_REAL=4 SHORTPIXEL_API_KEY="your-key" npm test
RUN_SHORTPIXEL_REAL=5 SHORTPIXEL_API_KEY="your-key" npm test
RUN_SHORTPIXEL_REAL=6 SHORTPIXEL_API_KEY="your-key" npm test
RUN_SHORTPIXEL_ALL_REAL=1 SHORTPIXEL_API_KEY="your-key" npm testapiKeyis required.pluginVersionmust be max 5 characters. (optional)downloadTo()only works after an optimization call (from*,optimize*,optimize, feature helpers).- In
optimize([...]), do not mix URL strings and local path strings. - All feature helpers (
upscale,rescale,backgroundChange, etc.) support additional options, so you can combine capabilities in a single call. - Increase poll time if anything breaks and retry.
Official ShortPixel API docs: https://shortpixel.com/api-docs