← All articles 8 min read

Placeholder Image Services: The Complete Developer Guide

A placeholder image is a temporary stand-in — a sized rectangle that holds layout space while real assets are still in production. Every frontend developer reaches for one sooner or later, and the service you pick determines whether your mockup looks like a wireframe or something you can actually show a stakeholder.

This guide covers the four major placeholder image services, how to use each one in HTML, CSS, and JavaScript, and how to swap real images in at production dimensions using Pixotter's resize tool.


Why Placeholder Images Matter

Placeholder images solve a real problem: you are building a layout before the real photography, illustration, or product images exist. Without placeholders, you have two bad options — leave blank space that makes the design look broken, or use your own test images that may have wrong dimensions.

Good placeholder services give you:

The wrong service gives you HTTP-only URLs that break staging environments, limited size options, or placeholder text baked into images that confuses clients.


The Four Services Worth Knowing

1. picsum.photos (Lorenzo Nicora, MIT License)

The best-looking option. Picsum serves real photographs from Unsplash, sized to any dimension you request. Your mockup looks like finished work instead of a grey box.

https://picsum.photos/800/600

Request a specific image by ID (stable across requests — useful for consistent mockups):

https://picsum.photos/id/237/800/600

Grayscale for wireframe-style mockups:

https://picsum.photos/800/600?grayscale

Blur (1–10):

https://picsum.photos/800/600?blur=2

Random vs. stable: Without an ID, picsum returns a random image on every request. This looks great in a gallery mockup but breaks screenshot-based visual regression tests. Use /id/{n}/ for stable, reproducible images.

Caveats: picsum does not support custom text overlays. If your design needs dimension labels or placeholder labels visible in the image, pick placehold.co instead.


2. placehold.co (Free, no affiliation required)

The most flexible option. placehold.co generates text-annotated placeholders with custom colors, fonts, and dimensions. Good when you need to label sections or annotate dimensions for handoff.

https://placehold.co/800x600

Custom colors (hex, without the #):

https://placehold.co/800x600/1a1a2e/ffffff

Custom text:

https://placehold.co/800x600?text=Product+Image

Retina (2x) — append @2x:

https://placehold.co/400x300@2x/png

Format support: PNG (default), JPEG, WebP, SVG, GIF. The SVG format is vector — it scales without pixelation at any screen density. Useful for prototyping.


3. placeholder.com (placeholder.com)

The classic. Simple URL scheme, instant gray boxes with dimension labels, no setup. It has been around since 2012 and loads fast on a CDN.

https://via.placeholder.com/800x600

Custom background and text color:

https://via.placeholder.com/800x600/3d5a80/ffffff

Custom text:

https://via.placeholder.com/800x600?text=Hero+Banner

Format support: PNG, GIF, JPEG, WebP. Request with extension:

https://via.placeholder.com/800x600.webp

Note on HTTPS: HTTPS is supported. Always use https:// — some older documentation shows HTTP URLs.


4. dummyimage.com

Functionally similar to placeholder.com but with a slightly different URL scheme. Useful as a fallback if placeholder.com is rate-limiting during CI builds.

https://dummyimage.com/800x600/cccccc/000000

Format in URL:

https://dummyimage.com/800x600/cccccc/000000.png

Service Comparison

Service URL Pattern Photo Content Custom Text HTTPS SVG Max Size License
picsum.photos /800/600 Yes (real photos) No Yes No 5000×5000 MIT
placehold.co /800x600 No Yes Yes Yes 4000×4000 Free to use
placeholder.com /800x600 No Yes Yes No 4000×4000 Free to use
dummyimage.com /800x600/hex/hex No Yes Yes No 4000×4000 Free to use

Which to pick:


Using Placeholder Images in Code

HTML <img> tag

<!-- Real photo, fixed dimensions -->
<img src="https://picsum.photos/800/600" alt="Product image placeholder" width="800" height="600">

<!-- Stable image (won't change on reload) -->
<img src="https://picsum.photos/id/237/400/300" alt="Dog placeholder" width="400" height="300">

<!-- Annotated placeholder for wireframe -->
<img src="https://placehold.co/800x400?text=Hero+Banner" alt="Hero banner placeholder" width="800" height="400">

Always include width and height attributes. This prevents layout shift (CLS) while the placeholder loads — important even for development builds where you want accurate measurements to carry over to production.

Responsive images with srcset

<img
  src="https://picsum.photos/800/600"
  srcset="
    https://picsum.photos/400/300  400w,
    https://picsum.photos/800/600  800w,
    https://picsum.photos/1200/900 1200w
  "
  sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
  alt="Product image placeholder"
  width="800"
  height="600"
>

Using stable IDs keeps this consistent across page reloads:

<img
  src="https://picsum.photos/id/10/800/600"
  srcset="
    https://picsum.photos/id/10/400/300  400w,
    https://picsum.photos/id/10/800/600  800w,
    https://picsum.photos/id/10/1200/900 1200w
  "
  sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
  alt="Forest placeholder"
  width="800"
  height="600"
>

CSS background-image

/* Hero section placeholder */
.hero {
  background-image: url('https://picsum.photos/1920/1080');
  background-size: cover;
  background-position: center;
  width: 100%;
  height: 600px;
}

/* Card thumbnail placeholder */
.card-thumbnail {
  background-image: url('https://placehold.co/400x300/e2e8f0/94a3b8?text=Card+Image');
  background-size: cover;
  background-position: center;
  width: 400px;
  height: 300px;
}

Using CSS custom properties for easy swapping:

:root {
  /* Swap this one variable to switch from placeholder to real image */
  --hero-image: url('https://picsum.photos/id/1015/1920/1080');
}

.hero {
  background-image: var(--hero-image);
  background-size: cover;
  background-position: center;
}

When the real image is ready, update the custom property. One change, reflected everywhere.

JavaScript / Fetch

Loading a placeholder image and inserting it dynamically:

// Vanilla JS — no external dependencies required
async function insertPlaceholder(container, width, height) {
  const url = `https://picsum.photos/${width}/${height}`;
  const img = document.createElement('img');
  img.src = url;
  img.width = width;
  img.height = height;
  img.alt = 'Placeholder image';
  img.loading = 'lazy'; // defer off-screen placeholders
  container.appendChild(img);
}

// Usage
const gallery = document.getElementById('photo-gallery');
for (let i = 0; i < 9; i++) {
  insertPlaceholder(gallery, 400, 300);
}

For a grid of stable, unique images using picsum's list API:

async function loadPlaceholderGrid(container, count = 9) {
  // picsum.photos/v2/list returns an array of photo objects
  const response = await fetch(`https://picsum.photos/v2/list?page=1&limit=${count}`);
  const photos = await response.json();

  photos.forEach(photo => {
    const img = document.createElement('img');
    img.src = `https://picsum.photos/id/${photo.id}/400/300`;
    img.width = 400;
    img.height = 300;
    img.alt = `Photo by ${photo.author}`;
    img.loading = 'lazy';
    container.appendChild(img);
  });
}

loadPlaceholderGrid(document.getElementById('gallery'));

React component

// PlaceholderImage.jsx
// React 18.x — no external image library required for basic usage

function PlaceholderImage({ width, height, id, text, className }) {
  const src = id
    ? `https://picsum.photos/id/${id}/${width}/${height}`
    : text
    ? `https://placehold.co/${width}x${height}?text=${encodeURIComponent(text)}`
    : `https://picsum.photos/${width}/${height}`;

  return (
    <img
      src={src}
      width={width}
      height={height}
      alt={text || 'Placeholder image'}
      className={className}
      loading="lazy"
    />
  );
}

// Usage
<PlaceholderImage width={800} height={600} id={237} />
<PlaceholderImage width={400} height={300} text="Product Photo" />


Swapping Placeholders for Real Images

The whole point of placeholder images is that they go away. Here is how to make that swap smooth.

Step 1: Know your target dimensions before you start

Placeholders lock in your layout dimensions. Before you write picsum.photos/800/600, confirm those are the actual production dimensions — not rough estimates. If your real product image will be 1200×900, use picsum.photos/1200/900 as the placeholder. Mismatched dimensions cause layout shift when you swap.

Check your design system. Common standard sizes:

Context Common Dimensions
Hero banner (desktop) 1920×1080, 1440×810
Product card thumbnail 400×400, 600×400
Blog post header 1200×630
Open Graph / social share 1200×630
Avatar / profile photo 200×200, 400×400
Sidebar widget 300×250

If you are unsure what size the real image should be, read image size for website for a complete breakdown by context.

Step 2: Resize real images to exact dimensions

When the real images arrive from your designer or photographer, they almost never match exactly. A raw photo is 3000×2000. Your layout needs 1200×630. Cropping and resizing those to exact spec before deploying prevents the most common CLS-related performance regressions.

Pixotter's resize tool handles this client-side — no upload, no account. Drop the image, set 1200×630, choose fit mode (cover crop vs. contain with letterbox), download. Processed in your browser using WASM.

If you are converting formats at the same time — raw JPEG to WebP, for example — use Pixotter's convert tool after resizing, or do both in one step. For high-traffic images where file size matters, run through the compress tool after.

Step 3: Replace the URL, keep the attributes

When swapping:

<!-- Before: placeholder -->
<img src="https://picsum.photos/id/237/800/600" alt="Dog placeholder" width="800" height="600">

<!-- After: real image, same dimensions, update alt text -->
<img src="/images/product-hero.webp" alt="Pixotter interface showing image compression" width="800" height="600">

The width and height attributes stay the same — that is the whole point of using placeholder images at correct dimensions. The only things that change are src and alt.


Using Placeholder Images in Figma and Design Tools

Most design tools can pull placeholder images directly into frames:

Figma: Use the Unsplash plugin (built by Figma, free). It pulls real photos at exact frame dimensions. Same photographic realism as picsum, direct in the canvas.

Framer: Built-in placeholder system auto-fills frames with stock photography at the correct aspect ratio.

Storybook: Use the @storybook/addon-backgrounds package (Storybook 8.x) and pass placeholder URLs as story args for visual regression testing.


Performance Considerations

Placeholder images are temporary, but they still affect development and staging performance:

Avoid using placeholder images in production even for a day. External service dependencies are a single point of failure — if picsum.photos has a brief outage, your production site shows broken images. Always swap to locally-hosted or CDN-hosted real images before deploying to production.

Lazy loading: Add loading="lazy" to placeholder images below the fold. This applies during development too — it prevents browser DevTools from showing 40 image requests on first load, which makes performance profiling harder.

Image format for placeholders: picsum returns JPEG by default. placehold.co returns PNG. The format difference rarely matters in development, but if you want to test how your layout handles WebP specifically, placehold.co supports .webp extension in the URL.

For a deeper look at which formats matter and when, see what is image resolution and best image format for web.


FAQ

What is a placeholder image? A placeholder image is a temporary image used in web development or design mockups to fill layout space before real images are ready. It has specific dimensions that match the final design, so the layout is accurate during development.

Which placeholder image service is the best? picsum.photos for realistic-looking mockups (uses real photos). placehold.co if you need custom text, colors, or SVG format. placeholder.com for the simplest URL scheme with no setup. All three are free and HTTPS-only.

Can I use placeholder images in production? No. Placeholder services are for development and staging only. They are external dependencies — an outage at the service breaks your site. Always swap to self-hosted or CDN-hosted images before going live.

How do I prevent layout shift when swapping placeholder images? Always specify width and height attributes on your <img> tags, and use placeholder images at the exact dimensions of the final image. When you swap src, the browser already knows the dimensions and does not need to recalculate layout.

What size should my placeholder images be? The same size as your final production images. Check your design specs first. Common sizes: 1200×630 for blog headers and OG images, 400×400 for product thumbnails, 1920×1080 for hero banners. See image size for website for a full reference.

Does picsum.photos cost money? No. picsum.photos is free and open source (MIT license). It is hosted and maintained by Lorenzo Nicora and contributors. For high-traffic applications where you need SLA guarantees, self-host it — the source code is on GitHub.

How do I get a stable (non-random) placeholder image from picsum? Use the ID-based URL: https://picsum.photos/id/237/800/600. The ID stays consistent across requests. Browse available IDs and their images at picsum.photos/images.

Can I use placeholder images in CSS background-image? Yes. Use the full URL in your CSS: background-image: url('https://picsum.photos/1920/1080'). For predictable results in staging environments, use an ID-based URL so the image does not change between builds.


Quick Reference

# Real photos (random)
https://picsum.photos/{width}/{height}

# Real photos (stable)
https://picsum.photos/id/{id}/{width}/{height}

# Real photos (grayscale)
https://picsum.photos/{width}/{height}?grayscale

# Color blocks with text
https://placehold.co/{width}x{height}
https://placehold.co/{width}x{height}/{bg-hex}/{text-hex}
https://placehold.co/{width}x{height}?text=Your+Label

# Classic gray boxes
https://via.placeholder.com/{width}x{height}
https://via.placeholder.com/{width}x{height}/{bg-hex}/{text-hex}

# Dummyimage fallback
https://dummyimage.com/{width}x{height}/{bg-hex}/{text-hex}

When the real images are ready: resize them to exact spec with Pixotter's resize tool, convert to WebP with the convert tool, compress for production with the compress tool, and swap the src. Three tools, one tab, no upload.