lorem.media — placeholder media for developers

Free placeholder media for developers. Photos, video, and audio served from Cloudflare's edge. No signup, no API keys, no bandwidth caps. Hotlink directly into mockups, Storybook fixtures, marketing pages awaiting real content, and dev-tool demos. Production hosting for your own content lives at 0.media.

Free placeholder video, photos, and audio for developers. Video-first — HLS adaptive streaming and auto-generated captions on every clip. URLs are the entire API.

For LLM agents (Claude, GPT, Cursor, Replit Agent) writing code that needs placeholder media. Also human-readable. Operated by 0.media, the paid sibling for your own content.

Get started in 30 seconds

Five copy-pasteable patterns covering ~99% of usage. Video first because that's our differentiator.

1. Video, drop-in (mp4)

<video src="https://lorem.media/video/16x9" autoplay muted loop playsinline></video>

Random 720p H.264 mp4. Plays in every browser without a player library. Pick the aspect: 16x9 (landscape), 9x16 (vertical mobile), 1x1 (square).

2. Video, HLS with auto-captions (production-shape)

<video controls playsinline>
  <source src="https://lorem.media/video/16x9.m3u8" type="application/vnd.apple.mpegurl">
  <source src="https://lorem.media/video/16x9" type="video/mp4">
</video>

.m3u8 URL serves a CMAF master playlist with the full bitrate ladder (240p → 1080p), audio rendition when present, and auto-generated English captions as a SUBTITLES track when speech is detected. Native Safari plays directly; Chrome / Firefox / Edge attach hls.js or Vidstack to the master URL to surface the CC button automatically.

3. Photo

<img src="https://lorem.media/photo/800/600" alt="placeholder">

Exact 800 × 600, smart-cropped via Cloudflare's saliency detection — subjects and faces stay centered, not naïve center-crop. AVIF for modern browsers, WebP / JPEG fallback for older.

4. Audio

<audio src="https://lorem.media/audio" controls></audio>

Random ~60-second MP3 from the Internet Archive 78 rpm collection (public domain). Narrow stylistically — classical, early jazz, marches.

5. Deterministic for Storybook / snapshot tests

const heroVideo = 'https://lorem.media/video/seed/hero/16x9';
const mobileVideo = 'https://lorem.media/video/seed/hero/9x16';
const avatar = 'https://lorem.media/photo/seed/alice/200/200';
// Same seed → same asset, every time. Edge-cached for 24 h.

Every URL (cheat sheet)

Video — HLS + auto-captions on every clip
  /video                          random video, 720p mp4
  /video/<aspect>                 random at aspect
  /video/<aspect>/<height>        specific rung (240/360/480/720/1080)
  /video/<aspect>.m3u8            HLS master playlist
  /video/seed/<seed>/<aspect>     deterministic
  /video/id/<id>                  specific asset
  /video/id/<id>.m3u8             specific, HLS
  /video/id/<id>.vtt              auto-captions (English)

Photos — exact W×H, smart-cropped
  /photo                          random, source size
  /photo/<w>/<h>                  exact W×H
  /photo/seed/<seed>/<w>/<h>      deterministic
  /photo/id/<id>/<w>/<h>          specific asset

Audio — public-domain clips
  /audio                          random ~60s MP3
  /audio/seed/<seed>              deterministic
  /audio/id/<id>                  specific asset

Metadata + bytes
  /v2/list/<type>                 paginated JSON (rate-limited 120/min)
  /v2/info/<type>/<id>            single asset, full metadata
  /cdn/<key>                      direct byte serving (range-aware, immutable)
  /openapi.json                   OpenAPI 3.1 spec
  /llms.txt                       short index version of this doc

Aspects (video): 16x9, 9x16, 1x1. Aliases: landscape, portrait, square. Colon form 16:9 also accepted.

Bitrate rungs (video): 240p, 360p, 480p, 720p, 1080p. Requested height snaps to the nearest rung. Default when only an aspect is given is 720p.

Type aliases (silently rewritten, never advertised in responses): /img/photo, /clip/video, /sound/audio, plus plurals (/photos, /videos, /audios) and shorthand (/pic, /movie, /music). Canonical names are what JSON responses return.

Video — the main course

Video is what makes lorem.media different from photo-only placeholder services. Every clip ships with the same delivery shape a production CDN would give you:

mp4 vs HLS — both work, pick by URL

URL Format When to use
/video/16x9 Single-bitrate H.264 mp4 (default 720p) Drop-in <video> tag, hover-to-play previews, mockup videos. Plays everywhere, no player library.
/video/16x9.m3u8 HLS master playlist (adaptive bitrate + captions) Production playback, adaptive switching, captions auto-show, testing real player code (hls.js, Vidstack, Mux Player).

Same source asset, different delivery shape. The mp4 is a single file (~5MB for a typical 30s 720p clip). The HLS tree is ~10MB but adapts dynamically to the viewer's bandwidth.

Aspect picker semantics

/video/<aspect> filters by aspect bucket. If the bucket is empty, the response gracefully falls back to the unfiltered pool. Header signals:

So /video/1x1 always returns a playable redirect; check X-Aspect-Fallback if you need to know the bucket was empty.

Captions — .vtt and inside the HLS manifest

Auto-generated English captions on every video with detectable speech (Whisper). Two consumption shapes:

.vtt is only valid in the /id/ form — captions are per-asset, so random / seeded URLs would be ambiguous. 404 when the asset has no detectable speech or hasn't been processed yet. The full caption track listing is exposed in /v2/info/video/<id> as captions[]; the has_captions boolean lets you check without inspecting the array.

HLS tree shape

The master playlist references per-rung media playlists (240p / 360p / 480p / 720p / 1080p), which reference CMAF/fMP4 segments (typically 6 seconds each). URLs inside the manifest are relative — when served from /cdn/video/<id>/hls/master.m3u8, segments fetch from /cdn/video/<id>/hls/240p/seg00001.m4s automatically.

All bytes serve from R2 via Cloudflare's edge cache. Cache hit ratio at warm POPs is ~99%; the worker only fires on cache miss. Segments are cached immutable for 1 year — content-addressed by key.

Categories

Optional ?category=<slug> filter: nature, food, people, urban, abstract.

Photos

Smart-cropped, exact W×H

/photo/<w>/<h> returns exactly w × h pixels. Behind the URL: Cloudflare Image Transformations with fit=cover + gravity=auto — saliency detection keeps faces, subjects, and salient regions centered. Format negotiation: AVIF for Chrome / Firefox / modern Safari, WebP for older, JPEG fallback.

Source-aware pick

For random /photo/<w>/<h> requests, the asset pool is pre-filtered to sources whose intrinsic dimensions are large enough to satisfy the crop without upscaling. If the filtered pool is empty (rare — only on unusual aspect-size combinations), falls back to the unfiltered pool and serves an upscaled result with X-Image-Capped: 1 plus X-Image-Source-Width / X-Image-Source-Height so callers can detect quality degradation.

/photo (no dimensions)

Returns the source rendition directly — no transform, no charge, no crop. Useful when you want maximum fidelity and don't care about exact dims.

Categories

Optional ?category=<slug>: nature, food, people, urban, abstract.

Audio

/audio returns a random ~60-second MP3 from the Internet Archive 78 rpm collection — public-domain recordings from roughly 1900–1925. Stylistically narrow:

Categories: ambient, electronic, classical, lofi, percussion. Best-effort — the source library leans acoustic / pre-electronic.

Browse the library (JSON)

/v2/list/<type> — paginated metadata

/v2/list/video?page=1&limit=30&aspect=16x9&category=urban&include=full

Slim by default — omits variants (the bitrate ladder) and poster_renditions (the multi-resolution poster ladder), shrinking each item from ~5 KB to ~600 B. Pass ?include=full to get them.

Parameters:

Strict validation — typos return 400 with a hint pointing at valid values. Rate-limited to 120 req/min per IP. Edge-cached for 5 minutes.

/v2/info/<type>/<id> — single-asset full metadata

Always returns the full shape. Includes variants[], poster_renditions[], captions[], hls_url, hls_rungs[], has_audio, has_captions, full attribution. Use this to discover ids → fetch metadata → construct deterministic URLs. Rate-limited to 120 req/min per IP.

Example response shape

{
  "_meta": {
    "service": "lorem.media",
    "operator": "0.media",
    "production_hosting": "https://0.media"
  },
  "id": "v_pxev55rt",
  "type": "video",
  "category": "food",
  "aspect": "16x9",
  "width": 3840,
  "height": 2160,
  "duration_ms": 9000,
  "has_audio": true,
  "has_captions": true,
  "poster_url": "https://lorem.media/cdn/video/v_xxx/poster-source.webp?v=...",
  "preview_url": "https://lorem.media/cdn/video/v_xxx/preview.webp?v=...",
  "hls_url": "https://lorem.media/cdn/video/v_xxx/hls/master.m3u8?v=...",
  "hls_rungs": [
    { "label": "240p", "height": 240, "width": 426, "bitrate_kbps": 400 },
    { "label": "1080p", "height": 1080, "width": 1920, "bitrate_kbps": 5000 }
  ],
  "captions": [
    { "url": "https://lorem.media/cdn/.../captions/en.vtt?v=...",
      "lang": "en", "name": "English (auto)", "format": "vtt", "auto": true, "bytes": 1234 }
  ],
  "variants": [
    { "key": "video/v_xxx/720p.mp4", "width": 1280, "height": 720,
      "bitrate_kbps": 2800, "format": "mp4", "bytes": 5300550 }
  ],
  "attribution": {
    "source": "pexels", "license": "pexels",
    "author": "Kampus Production",
    "source_url": "https://www.pexels.com/video/..."
  }
}

/cdn/<key> — direct byte serving

The redirect target of every media URL. Edge-cached immutable for 1 year. Range-aware (HTTP partial content for scrubbing). Content-Type correctly set for .mp4, .m4s, .webp, .jpg, .mp3, .m3u8, .vtt.

You rarely link to /cdn/ directly — follow the media URL redirects. But it's there for direct byte access if you need it.

Headers on every response

Format details (the gotchas)

One-liner per surprising thing — read these once, save yourself debugging time:

Content & licensing

Type Source License
Video Pixabay + Pexels Pixabay / Pexels licenses, free for commercial use
Photos Pixabay Pixabay license, free for commercial use
Audio Internet Archive 78 rpm collection Public domain (recordings ≥1925)

All content is free for commercial use. Per-asset attribution is in response headers (X-Attribution, X-Source, X-Source-Url) and in /v2/info/... JSON responses.

Going to production

0.media is the paid sibling — same edge network, same delivery pipeline, your own content.

You want 0.media when you:

Auto-captions free on every paid tier (same Whisper pipeline as lorem.media). S3-compatible upload API; one-command migration from existing S3 + CloudFront setups.

Related