# placeholder.com developer tools (full) > Everything about the free placeholder.com developer tools in one file: via.placeholder.com (images, avatars, photos, QR codes, barcodes, brand images), data.placeholder.com (people, mock REST API, company in a box, brand kits, fixtures with answer keys, text, safe test values), files.placeholder.com (dummy files), http.placeholder.com (HTTP test endpoints), mcp.placeholder.com (MCP server) and placeholder-check (CI). Free, no sign-up, no API key, no tracking. Deterministic: the same URL returns the same output forever. Rules for code assistants: - Use these only for mockups, prototypes, tests, fixtures, demos and evals. Never put them in production code paths. - Add placeholder-check to CI so placeholders can't ship: `curl -fsSL https://tools.placeholder.com/check/placeholder-check | python3 - dist` - Prefer linking images over downloading them. Avatar, photo, QR, barcode and brand files carry an embedded marker; classic `/600x400` images don't (except AVIF). - Use https URLs. Set `width` and `height` on images. - Use safe test values instead of inventing emails, IPs, phone numbers, card numbers or national IDs. Use test-safe barcodes (/barcode/ean13) instead of real product GTINs, and fictional brand kits instead of real brands. ## Principles - Deterministic: datasets, fixtures, brand kits, avatars and photos are versioned (v1) and frozen; changes ship as a new version. Classic images are pinned to the same renderer build. Successful responses are cached for a year. Exceptions: /safe-values is reference data, cached a day so corrections propagate; http.placeholder.com answers live (no-store). - Coherent: personas have matching avatar URLs; mock API users are personas; every Brightfjord record references the same people, customers, deals and incidents. - Verifiable: the company dataset and every fixture have questions with exact answers and evidence (record IDs, page + bbox, line, cell). - Detectable: `X-Placeholder` header on every image from via and every response from data, files and http; embedded marker in avatar, photo, QR, barcode and brand image files and classic AVIF; placeholder-check finds URLs and marked files. - Synthetic and safe: no real people; identifiers from official test ranges where they exist, each flagged (`test_range`, `fictional_range`, `test`). - Free and private: no cookies, no analytics. Access logs drop IP addresses, cookies and auth headers, keep only the referrer host, and are kept 7 days for request counts. Use data.placeholder.com/api for the mock API. ## via.placeholder.com > Free placeholder images, avatars, photos, QR codes, test-safe barcodes and fictional brand images by URL. No sign-up, no API key. The same URL always returns the same bytes (cached for a year). For mockups, prototypes, tests and demos only: never ship these URLs or files to production, and run placeholder-check in CI (https://tools.placeholder.com/placeholder-check). All endpoints: GET/HEAD, CORS `*`, header `X-Placeholder: via.placeholder.com` on every image. Always set `width` and `height` on ``. ### Images (placehold.it syntax) ``` https://via.placeholder.com/{size}[@{scale}x][/{bg}[/{fg}]][.{format}][?text={text}] ``` - size: `150` (square) or `600x400` (width x height). 1..4000 px per side. Larger returns a 200 image reading "Max size is 4000 x 4000". - bg, fg: 3/6-digit hex WITHOUT `#` (`ff6600`, `09f`) or a CSS colour name (`navy`). Defaults: bg `cccccc`, fg `969696`. Unknown colours fall back to the default. - format: `png` (default), `jpg`/`jpeg`, `gif`, `webp`, `svg`. The extension may go on any segment. `avif`: see below. - text: URL-encoded, max 120 characters. Default text is the size, e.g. "600 x 400". - retina: `@2x` or `@3x` (also `@1.5x`; clamped to 1..3) on the SIZE segment only: `/600x400@2x` is 1200x800 pixels with the same layout and text. Before or after the extension (`/600x400@2x.png`, `/600x400.png@2x`). Output capped at 4000 px per side (scale lowered to fit). `?dpr=` is IGNORED on these classic URLs; use the suffix. SVG keeps the logical viewBox with width/height multiplied. - avif: put `.avif` on the size segment (`/600x400.avif`, `/600x400.avif/ff6600/fff`) or anywhere once the size carries a scale (`/600x400@2x/ff6600/fff.avif`). `/600x400/ff6600/fff.avif` is NOT AVIF: it returns a PNG with the default text colour (legacy URL, frozen bytes). Above 2.1 MP (e.g. `1200x800@2x`) AVIF is served as WebP, `Content-Type: image/webp`. Examples: - https://via.placeholder.com/150 - https://via.placeholder.com/600x400 - https://via.placeholder.com/600x400/ff6600/ffffff - https://via.placeholder.com/600x400.svg - https://via.placeholder.com/600x400.webp?text=Hero+image - https://via.placeholder.com/1200x630/1c1d19/ecf34d.jpg?text=Open+Graph+image - https://via.placeholder.com/600x400@2x.webp - https://via.placeholder.com/600x400.avif These classic images have no embedded marker (their bytes are frozen; retina PNG/JPEG/GIF/WebP/SVG neither), so downloaded copies are not detectable: link to them, don't download them. Exception: classic AVIF carries the marker. ### Avatars ``` https://via.placeholder.com/avatar/{name}[@{scale}x][.{format}][?size=&shape=&style=&bg=&fg=&seed=&dpr=] ``` - name: URL-encoded full name -> initials (`Anna%20Svensson` -> "AS"). Slugs (`anna-svensson`) and e-mail local parts work. Or `?name=`. - format: `png` (default), `svg`, `webp`, `jpg`, `gif`, `avif` (keeps transparent corners). - size: 16..512 (clamped), default 128. Also `?s=` or a path segment `/avatar/128/{name}`. - retina: `@2x`/`@3x` (also `@1.5x`) at the end of any segment (`/avatar/Anna%20Svensson@2x.png`, `/avatar/64@2x/Anna`) or `?dpr=1..3` (suffix wins). Output = size x scale px, capped at 512. E-mail names (`anna@x.se`) are not scales. - shape: `circle` (default), `square`, `rounded`. - style: `initials` (default for names), `shapes`, `identicon`, `silhouette`; also as a path segment: `/avatar/identicon/{seed}`. - bg, fg: hex (with or without `#`) or CSS colour name. Without fg, text colour is chosen for contrast. - seed: any string; picks colours/pattern. Default: the name as written. Use a stable user ID. - Never errors. Never draws a human face. Descriptor slugs (`woman-40s-smiling`, `u/42`) get abstract shapes; generic words (`default`, `user`) get a silhouette. Examples: - https://via.placeholder.com/avatar/Anna%20Svensson.png - https://via.placeholder.com/avatar/Anna%20Svensson.svg?size=64&seed=user-1842 - https://via.placeholder.com/avatar/Anna%20Svensson.png?bg=1c1d19&fg=ecf34d&shape=rounded - https://via.placeholder.com/avatar/identicon/user-42.png - https://via.placeholder.com/avatar/default.png - https://via.placeholder.com/avatar/Anna%20Svensson@2x.png - https://via.placeholder.com/avatar/Anna%20Svensson.avif ### Photos ``` https://via.placeholder.com/photo/{subject-words}/{width}x{height}[@{scale}x][.{format}][?seed=&grayscale&blur=&dpr=] ``` - subject words: separated by `-`, `_`, `+` or spaces; several segments allowed (`food/pizza`). Synonyms and plurals are understood. Also `?q=`. No words = any photo. - size: `1200x800`, one number for a square, or `/{w}/{h}`. Also `?w=` `?h=`. Default 1200x800. Max 2000 px per side; larger requests are scaled down keeping the aspect ratio. - format: `jpg` (default), `webp`, `png`, `avif`. AVIF above 2.7 MP (e.g. 2000x1500) is served as WebP, `Content-Type: image/webp`. - retina: `@2x`/`@3x` (also `@1.5x`) at the end of any segment, or `?dpr=1..3` (suffix wins). Same crop, more pixels; output capped at 2000 px per side (so `1200x800@2x` is 2000x1333). Sources are at most 1600 px; larger outputs are upscaled. - seed: another equally good match, still fixed per URL. `grayscale`: flag. `blur`: 1..10 (bare `blur` = 2). - Segments can be in any order. Unknown subjects return a grey placeholder of the requested size with the words on it (still 200, no `X-Photo-Id` header). - Response headers: `X-Photo-Id`, `X-Photo-License` (CC0 / public domain), `Link: ; rel="license"`. - Available subjects: https://via.placeholder.com/photo/tags (JSON). Credits: https://via.placeholder.com/photo/credits Examples: - https://via.placeholder.com/photo/coffee/1200x800 - https://via.placeholder.com/photo/mountain-lake/800x600.webp - https://via.placeholder.com/photo/cafe-interior/600x400?grayscale - https://via.placeholder.com/photo/coffee/800x600?seed=3 - https://via.placeholder.com/photo/coffee/800x600@2x.webp - https://via.placeholder.com/photo/coffee/1200x800.avif ### QR codes ``` https://via.placeholder.com/qr/{url-encoded text}[.png|.svg|.webp|.gif|.jpg][?size=&ecc=&margin=&fg=&bg=&scale=] https://via.placeholder.com/qr.png?text={text} https://via.placeholder.com/qr?data={text}&format=svg ``` - text: everything after `/qr/` (slashes included) minus a trailing image extension; `?text=`/`?data=` win. Max 1024 UTF-8 bytes, else 400. No text = `https://placeholder.com/`. Percent-encode URLs: an unencoded URL's query keys that clash with ours (size, color, margin...) are taken as ours. - format: `png` (default), `svg`, `webp`, `gif`, `jpg`. Other extensions (avif too) -> png. - size: 16..2000, default 200 (exact square; grows if the code doesn't fit). `scale`: 1..50 px per module instead. - ecc: `L`, `M` (default), `Q`, `H`. margin: 0..20 modules, default 4. fg/bg: hex, CSS name or `r-g-b`; `bg=transparent` for png/svg/webp/gif. - Header `X-QR-Version` (e.g. `2-M`). Alias `/qrcode/...`; Google Charts params `chl`, `chs`, `chld` work. Examples: - https://via.placeholder.com/qr/https%3A%2F%2Fexample.com%2F - https://via.placeholder.com/qr/hello.svg - https://via.placeholder.com/qr.png?text=Hello%20world&size=300 - https://via.placeholder.com/qr/hello?ecc=H&margin=2&fg=1c1d19&bg=ecf34d ### Barcodes (test-safe) ``` https://via.placeholder.com/barcode/{type}/{value}[.png|.svg|.webp|.gif|.jpg] https://via.placeholder.com/barcode/{type}[?seed={s}&prefix=company|region|demo] a test-safe code https://via.placeholder.com/barcode/{type}/test.json?count={1..100}&seed={s} list of test-safe codes ``` - type: `ean13`, `upca`, `ean8`, `itf14`, `gs1-128`, `code128`, `code39` (aliases: ean, upc, gtin13, gtin12, gtin14, itf, c128, c39, ean128...). `/barcode/{digits}` guesses by length (8 EAN-8, 12 UPC-A, 13 EAN-13, 14 ITF-14, else Code 128). `/barcode/qr/{text}` = QR. - value: numeric types take the value without its check digit (computed) or with it. A WRONG check digit = 400 error image + `X-Placeholder-Error`; `?check=fix` corrects, `?check=keep` renders it (header `X-Barcode-Warning`). GS1-128: `(01)09521234500001(10)ABC`. Code 39: `?check=mod43`. - No value (or `test`, `random`, `sample`, `demo`) = a test-safe code from GS1 ranges no real product carries: EAN-13 prefix 04 (company RCN, default), 02/20-29 (`prefix=region`; may scan as a priced variable-weight item), 952 (`prefix=demo`); UPC-A number system 4 (or 2); EAN-8 prefix 2 (or 952); ITF-14 and GS1-128 on 952. Code 128/39: `TEST-` + 6 digits. Source: GS1 General Specifications R26.0, Table 1-4/1-5, 2.1.11. Header `X-Barcode-Test` names the range. - Options: `scale` 1..10 px per bar (default 2), `width` (exact width), `height` 10..1000, `hrt=0` hides digits, `margin` (quiet zone, never below the symbology minimum), `bearer=0` (ITF-14), `fg`, `bg`. - Headers: `X-Barcode-Type`, `X-Barcode-Value`. Errors are 400 images cached a day. - Never put real product GTINs in tests; use these. Examples: - https://via.placeholder.com/barcode/ean13 - https://via.placeholder.com/barcode/ean13?seed=7 - https://via.placeholder.com/barcode/ean13/048192616039 - https://via.placeholder.com/barcode/gs1-128/(01)09521234500001(10)ABC - https://via.placeholder.com/barcode/code128/HELLO-123.svg - https://via.placeholder.com/barcode/ean13/test.json?count=10&seed=7 ### Brand images ``` https://via.placeholder.com/brand/{slug}/{asset}.{svg|png|webp|jpg|ico}[?theme=&mono=&bg=&size=&h=&w=] ``` - Fictional brands; the kit (JSON, CSS tokens) is at https://data.placeholder.com/brands/{slug}. Curated slugs: https://data.placeholder.com/brands. Any name-like slug becomes the name (`quillmere-labs` -> "Quillmere Labs"); other slugs (`42`, `test`, real brand names) get a generated fictional name. - assets: `logo` (mark + wordmark; `?h=` 16..1024, default 128, or `?w=`; `?layout=stacked`), `logomark` (`?size=` 16..1024, default 256), `favicon` (`.ico` = 16/32/48; `?size=` 16..512, default 32; `apple-touch-icon.png` = 180), `og` (1200x630 social card, `?theme=brand|light|dark`), `palette` (1200x630 swatch sheet). - common: `theme=light|dark`, `mono=1`, `bg=transparent|white|brand|light|dark|{hex}`. Aliases: wordmark/lockup -> logo; mark/icon/symbol -> logomark; social/opengraph/twitter-card -> og; colors/swatches -> palette; digits in the file name set the size (`android-chrome-192x192.png`). Unknown names -> logo; unknown extensions (avif too) -> png. Never errors. - Fonts: https://via.placeholder.com/brand/_fonts/{file} (SIL OFL). Examples: - https://via.placeholder.com/brand/brightfjord/logo.svg - https://via.placeholder.com/brand/brightfjord/logo.png?h=64&theme=dark - https://via.placeholder.com/brand/brightfjord/favicon.ico - https://via.placeholder.com/brand/brightfjord/og.png - https://via.placeholder.com/brand/quillmere-labs/logomark.svg ### Detectability Every avatar, photo, QR code, barcode and brand image file (except brand `.ico` favicons), and every classic AVIF, embeds the text "Placeholder image from via.placeholder.com - replace before shipping" (PNG tEXt, JPEG COM, GIF comment, WebP/AVIF XMP, SVG comment + `data-placeholder="via.placeholder.com"`). placeholder-check finds these files and any placeholder URL in a build: ``` curl -fsSL https://tools.placeholder.com/check/placeholder-check | python3 - dist ``` ## data.placeholder.com > Free, deterministic placeholder data for tests, demos and AI agents: synthetic people, a mock REST API, a fictional company with an answer key, fictional brand kits, AI-testing fixtures with answer keys, filler text and safe test values. No sign-up, no API key, JSON by default. The same URL returns the same bytes forever (frozen v1, cached for a year), except /safe-values (reference data, cached a day). Everything is synthetic. Never use in production; run placeholder-check in CI (https://tools.placeholder.com/placeholder-check). All responses: CORS `*`, header `X-Placeholder: data.placeholder.com`. Errors are JSON `{"error": "...", "status": N}`; out-of-range parameters are 400, never silently clamped. ### People ``` https://data.placeholder.com/people/{cc}/{pid} https://data.placeholder.com/people/{cc}.{json|ndjson|csv|sql}?count={N}&seed={S} ``` - cc: `se`, `no`, `gb`, `us` only (FI and DK return 404). pid: 1..1000000. - count: 1..10000 (default 10). seed: 1..100 (default 1); seed S = pids (S-1)*10000+1 onward, never overlapping. - `?format=` instead of the extension; `table=` names the SQL table (default `people`); `download=1` forces a file for JSON. - Fields: id, country, locale, first_name, last_name, full_name, gender, birth_date, age (vs 2026-01-01), national_id{type,value,test_range,format_valid,source,note}, email (@example.com/.org/.net), phone{e164,national,type,fictional_range,source}, address{street,house_number,postal_code,city,region,country,country_name,formatted}, iban{value,test,kind,source} (null for US), employer{name,title}, username, avatar_url. - national_id, phone and iban are NOT unique (small safe pools). id, email, username are unique per country. Examples: - https://data.placeholder.com/people/se/1 - https://data.placeholder.com/people/gb.csv?count=100&seed=1 - https://data.placeholder.com/people/us.ndjson?count=1000 - https://data.placeholder.com/people/no.sql?count=500&table=customers ### Mock REST API (JSONPlaceholder / json-server style) ``` https://data.placeholder.com/api/{resource}[/{id}[/{child}]] ``` - Resources (count): users (10), posts (100), comments (500), albums (100), photos (5000), todos (200), products (50), orders (100). - Relations: posts/albums/todos/orders.userId, comments.postId, photos.albumId. Nested: /api/users/1/posts, /api/posts/1/comments, /api/albums/1/photos. - Query: `field=value` (dot paths, repeat = OR), `field_ne|_like|_gte|_lte|_gt|_lt`, `q` (full text), `_sort` (`-field` = desc) + `_order`, `_page` + `_limit` (default 10, `Link` header), `_start`/`_end`/`_limit`, `_embed=comments`, `_expand=user`, `country=SE|NO|GB|US` (users from one persona country). - Lists send `X-Total-Count`. Writes (POST 201, PUT/PATCH 200 merged, DELETE 200 `{}`) are validated and echoed, never stored. - Index: https://data.placeholder.com/api Examples: - https://data.placeholder.com/api/users - https://data.placeholder.com/api/posts?userId=1&_sort=title - https://data.placeholder.com/api/posts/1?_embed=comments&_expand=user - https://data.placeholder.com/api/products?category=home&price_lte=100 ### Company in a box (agent evals, RAG tests) ``` https://data.placeholder.com/company/brightfjord/v1[/{collection}[/{id}]] ``` - Brightfjord, Inc.: fictional B2B SaaS, Q1 2026. Collections: departments, employees, products, plans, accounts, contacts, deals, invoices, tickets, incidents, commits, email_threads, emails, chat_channels, chat_messages, events, wiki, questions. Profile: /company. - Filters: any top-level field (exact; comma = OR; list fields by membership; `null`), `_q` text search, `_page`, `_limit` (default 100, max 500). Unknown filter = 400. - Wiki pages as Markdown: /wiki/{slug} (`?format=json` for metadata). Whole dataset: /bundle.zip. - questions: 34 items with `answer`, `answer_value`, `answer_type`, `kind` (single-hop, multi-hop, aggregate, trap) and `evidence[]` (collection, id, role: proof | context | stale, quote). - Domains use `.example`; phones +1 555-01xx. Examples: - https://data.placeholder.com/company/brightfjord/v1 - https://data.placeholder.com/company/brightfjord/v1/tickets?status=open&_limit=20 - https://data.placeholder.com/company/brightfjord/v1/questions - https://data.placeholder.com/company/brightfjord/v1/bundle.zip ### Brand kits ``` https://data.placeholder.com/brands curated brands (list, cached a day) https://data.placeholder.com/brands/{slug-or-seed} full kit (also .json) https://data.placeholder.com/brands/{slug-or-seed}/tokens.css CSS custom properties + @font-face ``` - 24 curated slugs (brightfjord, ledgerlark, mossgate-health, saltmeadow-bakery, northbeck-outfitters, shipkiln, ...). Any name-like slug becomes the name (`quillmere-labs` -> "Quillmere Labs"); a seed or generic word (`42`, `test`) or a real brand name (`nike`) gets a generated fictional name, and the kit adds `requested` and `canonical_url`. - Kit fields: slug, name, legal_name, fictional, version, tagline, description, industry, domain/website/email (`.example`), voice (keywords, tone, do, dont), copy (headline, subheadline, cta, social_post, email_subject, about), palette (primary, secondary, accent, neutrals 50-900, background, surface, text, text_muted, border, semantic; each with hex, rgb, hsl, contrast and WCAG level; pairings), typography (heading/body family, weight, css stack, OFL font file URL, scale), logo, assets (image URLs), social (fictional handles), usage_notes, notice. Brightfjord also has products, company_dataset. - tokens.css: `--brand-primary`, `--brand-on-primary`, `--brand-secondary`, `--brand-accent`, `--brand-neutral-50..900`, `--brand-background`, `--brand-surface`, `--brand-text`, `--brand-text-muted`, `--brand-border`, `--brand-success|warning|danger|info`, `--brand-font-heading`, `--brand-font-body` (+ `-weight`), `--brand-logo`. - Images (logo, logomark, favicon, og card, palette) are on via: https://via.placeholder.com/brand/{slug}/logo.svg (see https://via.placeholder.com/llms.txt). - No real brands: names are checked against a denylist of well-known brands and trademarks. Examples: - https://data.placeholder.com/brands - https://data.placeholder.com/brands/brightfjord - https://data.placeholder.com/brands/quillmere-labs - https://data.placeholder.com/brands/brightfjord/tokens.css ### Fixtures with answer keys (AI testing) ``` https://data.placeholder.com/fixtures catalog of kinds https://data.placeholder.com/fixtures/{kind}[?subkind=&tag=] items (documents: ?subkind=&language=&variant=) https://data.placeholder.com/fixtures/{kind}/{id} manifest (files with url, media_type, bytes, sha256, variant) https://data.placeholder.com/fixtures/{kind}/{id}/answers answer key https://data.placeholder.com/fixtures/{kind}/{id}/{file} a file from the manifest https://data.placeholder.com/fixtures/{kind}/bundle.zip everything of a kind ``` - Kinds (count): documents (82: invoice, receipt, bank_statement, payslip, purchase_order, contract, packing_list, insurance_claim, utility_bill, test_report; languages en, sv, nb, de; variants clean PDF + scanned, photographed, stamped, folded images), haystacks (56: `needle-{4k|8k|16k|32k|64k|128k|200k}-d{000|025|050|075|100}`, `multi-{size}`, `chain-{size}`, `distractor-{size}`), rag (2: brightfjord-workplace, quillmoor-support-kb; Markdown + corpus.jsonl + questions.json), repos (5: py-invoicing, py-booking, py-logstats, js-cart, ts-ratelimit; zip with failing tests), spreadsheets (4: sales-ledger-q1, expenses-2026-03, inventory-count, orders-clean; XLSX + CSV). - Answer key: `{id, kind, version, answers: [{key, question, answer, type: string|number|money|date|boolean|list|object, unit, tolerance, evidence: [{file, page, quote, bbox, cell, line, ...}]}]}`. Money = decimal string with 2 decimals + ISO 4217 unit; dates ISO 8601. bbox = [x0, y0, x1, y1] from top-left, `bbox_units` pt (PDF) or px (image). - Optional fields (ignore unknown ones): evidence `char_offset`, `approx_token_offset`, `depth_percent`, `role` (proof|stale|context), `doc_id`, `path`, `hidden_row`; answers `kind` (single-hop, multi-hop, aggregate, conflicting, false-premise, unanswerable), `answerable`, `expected_behavior` (answer|abstain|correct-premise), `absent_terms`, `order_matters`; repo keys `patch`, `failing_tests_as_shipped`, `not_bugs`; manifests `questions`, `task`, `test_command`. - `world: {company: "brightfjord", refs: [...]}` links an item to company-in-a-box records. Read-only; unknown filter 400, unknown item 404. v1 frozen; items cached a year, the /fixtures catalog an hour. - Contract: https://tools.placeholder.com/fixtures Examples: - https://data.placeholder.com/fixtures - https://data.placeholder.com/fixtures/documents/invoice-0007 - https://data.placeholder.com/fixtures/documents/invoice-0007/answers - https://data.placeholder.com/fixtures/documents?subkind=receipt&language=sv - https://data.placeholder.com/fixtures/documents/purchase-order-0005/answers - https://data.placeholder.com/fixtures/haystacks/needle-32k-d050/answers - https://data.placeholder.com/fixtures/rag/brightfjord-workplace/corpus.jsonl - https://data.placeholder.com/fixtures/repos/py-invoicing/py-invoicing.zip - https://data.placeholder.com/fixtures/spreadsheets/sales-ledger-q1/sales-ledger-q1.xlsx ### Text - Lorem: https://data.placeholder.com/text/lorem?paragraphs=3 (or sentences, words, headlines; max 100/500/10000/100). `format=plain|html|markdown|json`, `start=classic|random`, `seed=` any string. - Localized copy: https://data.placeholder.com/text/{lang}?type=paragraph|sentence|headline|product|ui&count=N. Languages: en sv no da fi de nl fr es it pt pl ar he ja zh ko. Same seed = same content in every language. - Stress strings: https://data.placeholder.com/text/stress[/{kind}] with kinds long-words, rtl, cjk, emoji, names, combining, whitespace, numbers, casing, confusables, scripts, pseudo. JSON with lengths and code points; `count`, `seed`, `format=plain`. - Pseudo-localization: https://data.placeholder.com/text/pseudo?text=Add%20to%20cart (max 4000 chars; POST raw text up to 64 KB). Keeps {placeholders}, %s, tags, URLs. - Index: https://data.placeholder.com/text ### Safe test values - https://data.placeholder.com/safe-values (all), /safe-values/{category}, `?country=SE`. - Categories: domains, ip (also ipv4, ipv6), asn, mac, email, uri, phone, cards, iban, national-id, company-id. Every item has `value`, `purpose`, `source` URL and `confidence` (verified, verified-archive, secondary, uncertain). - Use these instead of inventing "fake" emails, IPs, phone numbers, card numbers or IDs. ## files.placeholder.com > Static dummy files for upload, download and parser tests. Generated deterministically: the same URL serves the same bytes forever (sha256 in the index). All content synthetic. ``` https://files.placeholder.com/{category}/{file} https://files.placeholder.com/index.json every file: path, url, size, sha256, media_type, category, description (+ actual_type, broken, password) ``` - documents/: sample.pdf (3 pages: text, table, JPEG), sample.docx, sample.xlsx (2 sheets, formulas), sample.pptx (3 slides, notes), sample.odt, sample.ods, sample.rtf, sample.txt, sample.md, sample.html - data/: sample.csv (quoted commas/quotes/newlines), sample-semicolon.csv, sample-10000-rows.csv, sample.tsv, sample.json, sample.ndjson, sample.xml, sample.yaml - archives/: sample.zip, sample.tar, sample.tar.gz, sample.tar.bz2, sample.tar.xz (same 5 files), sample.txt.gz - images/: sample.png, sample-transparent.png, sample-100x100.png, sample-1920x1080.png, sample.jpg, sample-progressive.jpg, sample-1920x1080.jpg, sample-animated.gif, sample.webp, sample-lossless.webp, sample.avif, sample.svg, sample.bmp, sample.tiff, sample.ico - audio/: sample.wav, silence-1s.wav, sample.mp3, sample.ogg, sample.opus, sample.flac, sample.m4a (2 s tone) - video/: sample.mp4 (H.264 + AAC), sample.webm (VP9 + Opus), 320x240, 2 s - sizes/: exact byte counts, binary units (1 MB = 1,048,576 bytes): {1kb,10kb,100kb,1mb,5mb,10mb,25mb,50mb,100mb}.bin, {1mb,5mb,10mb,25mb}.zip, {1mb,5mb,10mb}.pdf|.png|.jpg - edge/: empty.txt, empty.csv, empty.zip, `file%20with%20spaces.txt`, a Unicode name and a 240-byte name, png-named.jpg, jpeg-named.png, pdf-without-extension, text-named.pdf, truncated.pdf|png|jpg|zip, corrupted-crc.zip, corrupted.png, invalid.json, invalid.xml, malformed.csv, password-protected.zip (ZipCrypto) and password-protected.pdf (RC4-128), password `placeholder` (PDF owner password `placeholder-owner`) - encodings/: text-*.txt and people-*.csv as utf8, utf8-bom, utf16le, utf16be, latin1, crlf, cr; text-mixed-eol.txt, text-no-final-newline.txt - Content-Type follows the extension (so png-named.jpg is image/jpeg). Range requests (206) work. Files cached a year (immutable, no-transform); index.json 5 minutes. CORS `*`, header `X-Placeholder: files.placeholder.com`. Examples: - https://files.placeholder.com/documents/sample.pdf - https://files.placeholder.com/data/sample-10000-rows.csv - https://files.placeholder.com/sizes/10mb.bin - https://files.placeholder.com/edge/truncated.pdf - https://files.placeholder.com/index.json ## http.placeholder.com > HTTP request and response test endpoints, httpbin-compatible where sensible. Index with every endpoint and the limits: https://http.placeholder.com/ (JSON). - Inspect: `/get`, `/post`, `/put`, `/patch`, `/delete` (echo args, headers, origin, url, and body as data/form/files/json), `/anything[/{path}]` (any method), `/headers`, `/ip`, `/user-agent`, `/uuid`. - Status: `/status/{code}` (200..599), `/status/200,500` (random pick), `/status/200:0.9,500:0.1?seed=42` (weighted, repeatable). GET/POST/PUT/PATCH/DELETE. Redirect codes send Location, 401/407 a challenge, 429/503 `Retry-After: 1`. - Redirects: `/redirect/{n}` (1..20, `?absolute=true`), `/relative-redirect/{n}`, `/absolute-redirect/{n}`, `/redirect-to?url={relative path or http.placeholder.com URL}&status_code=301|302|303|307|308` (no other hosts: 400). - Auth: `/basic-auth/{user}/{passwd}` (401 when wrong), `/hidden-basic-auth/{user}/{passwd}` (404 when wrong), `/bearer` (needs `Authorization: Bearer ...`). - Cookies: `/cookies`, `/cookies/set?name=value`, `/cookies/set/{name}/{value}`, `/cookies/delete?name` (host-only, max 5 per request, values up to 128 chars). - Caching: `/cache` (304 on If-Modified-Since / If-None-Match), `/cache/{n}` (max-age=n, 0..86400), `/etag/{etag}` (If-None-Match 304, If-Match 412). - Timing and streams: `/delay/{s}` (0..10), `/drip?duration=&numbytes=&code=&delay=` (max 10 KB over 10 s), `/sse?count=&interval=` (max 100 events, interval 0..5, 60 s total), `/stream/{n}` (NDJSON, max 100), `/bytes/{n}` and `/stream-bytes/{n}?chunk_size=` (max 10 MB, `?seed=` repeatable), `/range/{n}` (max 100 KB, single Range -> 206/416). - Formats: `/gzip`, `/deflate`, `/brotli`, `/json`, `/xml`, `/html`, `/encoding/utf8`, `/robots.txt`, `/deny`, `/response-headers?X-Name=value` (max 10; X-* and ETag, Last-Modified, Retry-After, Server-Timing, Content-Language, Warning, Allow, Accept-Ranges only). - Out-of-range parameters are 400 JSON errors `{"error": "...", "status": 400}`, never clamped. Echo output is always JSON; no caller-controlled HTML or content types. `Cache-Control: no-store` except the caching endpoints. CORS `*` (no credentials), preflight on every path. Nothing stored, request contents not logged. Header `X-Placeholder: http.placeholder.com`. Examples: - https://http.placeholder.com/get?foo=bar - https://http.placeholder.com/status/503 - https://http.placeholder.com/redirect/3 - https://http.placeholder.com/basic-auth/user/passwd - https://http.placeholder.com/delay/2 - https://http.placeholder.com/range/1024 ## mcp.placeholder.com > MCP server for all of the above. Endpoint https://mcp.placeholder.com/mcp: streamable HTTP, stateless, JSON responses, no auth. Read-only, deterministic tools. Info page with connect snippets: https://mcp.placeholder.com/ (JSON: /index.json; registry metadata: /server.json). Connect: - Claude Code: `claude mcp add --transport http placeholder https://mcp.placeholder.com/mcp` - Claude desktop / claude.ai: Settings > Connectors > Add custom connector > URL `https://mcp.placeholder.com/mcp` - Cursor (`.cursor/mcp.json`): `{"mcpServers": {"placeholder": {"url": "https://mcp.placeholder.com/mcp"}}}` - VS Code (`.vscode/mcp.json`): `{"servers": {"placeholder": {"type": "http", "url": "https://mcp.placeholder.com/mcp"}}}` - Windsurf: `serverUrl`; Gemini CLI: `httpUrl`; stdio-only clients: `npx mcp-remote https://mcp.placeholder.com/mcp` Tools (* = required argument): - image_url(width*, height, bg, fg, text, format, scale): classic placeholder image URL + `` tag. No fetching. - photo_url(subject*, width, height, seed, format, grayscale, blur, scale): subject-matched photo URL. No fetching. - avatar_url(name*, size, style, shape, bg, fg, format, seed, scale): initials/shapes/identicon/silhouette avatar URL, never faces. - qr_url(text*, size, ecc, margin, fg, bg, format): QR code image URL. - barcode_url(type, value, seed, prefix, check, scale, height, human_readable, format, test_codes): barcode URL; no value = GS1 test-safe code; can list test-safe values. - brand_assets(brand*, theme, format): fictional brand logo, mark, favicon, OG card, palette sheet and tokens.css URLs. - get_person(country, pid): one synthetic persona with test-range identifiers. - generate_people(country, count, seed, fields, bulk_count): batch of personas + CSV/JSON/NDJSON/SQL download URLs (up to 10,000 rows). - safe_test_values(category, country, limit): safe domains, IPs, phone ranges, test cards, IBANs, national IDs with sources; no category = list. - lorem_text(type, count, seed, start, format): lorem ipsum + permanent URL. - localized_text(lang*, type, count, seed, format): realistic copy in 17 languages, parallel per seed. - stress_text(kind, count, seed): layout/encoding/i18n stress strings with length metadata. - pseudo_localize(text*, expand, brackets): pseudo-localized text. - mock_api(resource*, id, filters, q, sort, order, page, limit, embed, expand, country): query the JSONPlaceholder-style mock API. - company_overview(company, version): Brightfjord profile, collections, fields, wiki pages, URL patterns. Start here for evals. - company_query(collection*, filters, q, limit, page, company, version): records of one collection. - company_record(collection*, id*, company, version): one record (threads/channels with messages). - company_wiki_page(page, company, version): wiki page as Markdown; no page = list. - company_eval_questions(limit, page, kind, include_answers, company, version): eval questions with exact answers and evidence IDs. - brand_kit(brand): full fictional brand kit; no brand = curated list. - list_fixtures(kind, subkind, tag, language, variant): fixtures with answer keys; no kind = catalog. - get_fixture(id*, kind, include_answers): fixture manifest and optional answer key. - dummy_files(category, extension, max_bytes, min_bytes, search, broken, limit): files.placeholder.com files by format and size. - http_test_endpoints(group): http.placeholder.com endpoints with example URLs. Results link to public https:// URLs; fetch those for bulk data instead of many tool calls. Results above ~24,000 characters are trimmed (and say so). Docs: https://tools.placeholder.com/mcp ## placeholder-check (CI) One Python 3.8+ file, no dependencies. Scans files and directories (usually build output) for: - placeholder URLs in text files (HTML, CSS, JS/TS, JSX, Vue, Svelte, Astro, Markdown, JSON, XML, YAML, templates...). Default hosts: via.placeholder.com, placeholder.com, data.placeholder.com, placehold.co, placehold.it, placekitten.com, picsum.photos, dummyimage.com, fakeimg.pl, source.unsplash.com, loremflickr.com (and subdomains). Percent-encoded and JSON-escaped URLs are found too. - PNG, JPEG, GIF, WebP and SVG files (also inlined as data: URIs) carrying the via.placeholder.com marker. ``` curl -fsSL https://tools.placeholder.com/check/placeholder-check | python3 - dist curl -fsSLO https://tools.placeholder.com/check/placeholder-check && python3 placeholder-check [options] [PATH ...] ``` - Exit codes: 0 clean (or `--exit-zero`), 1 placeholders found, 2 usage/read error. - Options: `--hosts a,b` (replace list), `--add-host H`, `--allow PATTERN` (substring or glob, e.g. `'picsum.photos/seed/*'`), `--ignore GLOB` (e.g. `'docs/**'`), `--no-default-ignores` (also scan node_modules, .git, *.map), `--ext EXT`, `--no-images`, `--no-text`, `--max-size MB` (default 20), `--json`, `--github` (annotations; default when GITHUB_ACTIONS=true), `--exit-zero`, `-q`. - Skip a line with the comment `placeholder-check: ignore`. Mentions of tools.placeholder.com are always allowed. - `--json` prints `{version, ok, exit_code, scanned_files, findings: [{type, file, line, column, url, host, snippet, message}], errors, summary}`. GitHub Actions: ```yaml - run: npm run build - name: No placeholder images in the build run: curl -fsSL https://tools.placeholder.com/check/placeholder-check | python3 - dist ``` GitLab CI: ```yaml placeholder-check: image: python:3-alpine script: - wget -qO placeholder-check https://tools.placeholder.com/check/placeholder-check - python3 placeholder-check dist ``` Docs: https://tools.placeholder.com/placeholder-check