# TestingURL.dev > A free sandbox of pages with known, predictable structures for practicing web scraping, browser automation, and HTTP client development. Every page returns the same content on every request unless its own description says otherwise, so it is safe to build automated tests, scrapers, and agent tooling against. All endpoints are open to any crawler or agent: robots.txt allows every path, and none require authentication except where a page is specifically testing authentication itself. A full OpenAPI 3.0 spec for every JSON endpoint (Mock Data, HTTP & Networking, Generators) is at https://testingurl.dev/openapi.json. ## Web Scraping A web scraping test site with known, predictable markup. Practice pages for crawlers, scrapers, and browser automation, from a full ecommerce catalog to pagination, forms, and login walls. ### Ecommerce catalog - [Store home](https://testingurl.dev/scraping/ecommerce): Browse every product category in the fake store. (easy) - [Category listing](https://testingurl.dev/scraping/ecommerce/category/laptops): Products within one category, each linking to its own detail page. (easy) - [Product detail page](https://testingurl.dev/scraping/ecommerce/product/1): A realistic ecommerce scraping target, with price, rating, stock, and related items. (easy) ### Structured data & metadata - [Format overview](https://testingurl.dev/scraping/structured-data): The same demo product in every format below, for comparing extraction results. (easy) - [Product — JSON-LD](https://testingurl.dev/scraping/structured-data/product-json-ld): Product data exposed only via a schema.org/Product JSON-LD script. (easy) - [Product — Microdata](https://testingurl.dev/scraping/structured-data/product-microdata): Same product, marked up with schema.org Microdata (itemscope/itemprop) instead of JSON-LD. (easy) - [Product — Open Graph](https://testingurl.dev/scraping/structured-data/product-open-graph): Same product, exposed only via Open Graph / product: meta tags in . (easy) - [Product — dataLayer](https://testingurl.dev/scraping/structured-data/product-datalayer): Same product pushed into window.dataLayer as a GA4/GTM ecommerce event. No markup, so JS execution is required. (medium) - [Product — combined](https://testingurl.dev/scraping/structured-data/product-combined): JSON-LD, Microdata, Open Graph, and dataLayer all present at once (a realistic messy page). (medium) - [Collection (ItemList)](https://testingurl.dev/scraping/structured-data/collection): A category page exposed as a schema.org CollectionPage/ItemList. (easy) - [Product reviews](https://testingurl.dev/scraping/structured-data/reviews): A product with visible reviews plus Review/AggregateRating JSON-LD. (easy) - [FAQ page](https://testingurl.dev/scraping/structured-data/faq): Common questions marked up as a schema.org FAQPage. (easy) - [Contact page](https://testingurl.dev/contact): Email, phone, and address as plain text, mailto:/tel: links, Microdata, and Organization JSON-LD. (easy) ### Pagination - [Numbered pagination](https://testingurl.dev/scraping/pagination/page/1): Classic ?page=N style listing, 10 items per page, with rel="next"/"prev" link tags in . (easy) - [Offset/limit pagination](https://testingurl.dev/scraping/pagination/offset?start=0&limit=10): Query-param offset/limit pagination. (easy) - [Load more button](https://testingurl.dev/scraping/load-more): Fetches additional items via a JSON API on button click. (medium) - [Infinite scroll](https://testingurl.dev/scraping/infinite-scroll): Loads more items automatically as you scroll. (medium) ### Rendering modes - [JS-rendered content](https://testingurl.dev/scraping/js-rendered): Empty shell on load; content is injected via a client-side fetch. Requires a JS-capable scraper. (hard) - [Frames & iFrames](https://testingurl.dev/scraping/frames): Content nested inside an iframe pointing at a separate URL, two levels deep. Find the real page and fetch it directly. (hard) ### Tables - [Simple table](https://testingurl.dev/scraping/tables/simple): A single flat product table. (easy) - [Sortable table](https://testingurl.dev/scraping/tables/sortable): Client-navigable sortable columns via ?sort=&dir= query params. (medium) - [Nested/merged cells](https://testingurl.dev/scraping/tables/nested): Table grouped by category using rowspan. (hard) ### Forms - [Basic GET form](https://testingurl.dev/scraping/forms/basic): Simple search form, submits via GET. (easy) - [POST form](https://testingurl.dev/scraping/forms/post): Form submission via POST with a confirmation page. (easy) - [Multi-step form](https://testingurl.dev/scraping/forms/multi-step): Three-step wizard using a session cookie to persist state. (hard) - [File upload](https://testingurl.dev/scraping/forms/file-upload): Upload form with a file input. (medium) - [Hidden & honeypot fields](https://testingurl.dev/scraping/forms/hidden-fields): Form with a CSRF token and a bot-trap honeypot field that must stay empty. (hard) ### Authentication - [Login page](https://testingurl.dev/scraping/auth/login): Sets a session cookie on successful login (user: demo / pass: demo). (medium) - [Protected dashboard](https://testingurl.dev/scraping/auth/dashboard): Redirects to /login unless a valid session cookie is present. (medium) - [Logout](https://testingurl.dev/scraping/auth/logout): Clears the session cookie. (easy) ### Dynamic elements - [Dynamic elements](https://testingurl.dev/scraping/dynamic-elements): A randomized id on every request, plus buttons that only become enabled or change color after a delay. (medium) ### Accessibility - [Inaccessible version](https://testingurl.dev/scraping/accessibility/inaccessible): Four documented, scanner-detectable issues: missing alt text, an unlabeled input, low contrast, and a skipped heading level. (medium) - [Accessible version](https://testingurl.dev/scraping/accessibility/accessible): The same content with every issue above fixed, for comparison. (easy) ### Link graphs - [Redirect chain](https://testingurl.dev/scraping/links/redirect-chain/5): Follows N sequential redirects before landing. Try /redirect-chain/{n}. (medium) - [Circular links](https://testingurl.dev/scraping/links/circular): Three pages that link back to each other in a loop. (medium) - [Broken links](https://testingurl.dev/scraping/links/broken): A page mixing valid links with intentional 404s. (easy) ### Markup difficulty levels - [Clean semantic HTML](https://testingurl.dev/scraping/markup/clean): Well-structured HTML with meaningful classes. (easy) - [Div soup](https://testingurl.dev/scraping/markup/div-soup): Same content, all divs/spans, no semantic tags or classes. (medium) - [Obfuscated classes](https://testingurl.dev/scraping/markup/obfuscated): Same content, hashed/randomized-looking class names. (hard) - [Data-attribute hooks](https://testingurl.dev/scraping/markup/data-attrs): Same content, data extracted via data-* attributes rather than classes. (medium) ### URL structure & normalization - [Overview](https://testingurl.dev/scraping/url-structure): Links to every URL-structure scenario below. (easy) - [Trailing slash](https://testingurl.dev/scraping/url-structure/trailing-slash): The same content at two URLs, one with a trailing slash, one canonical to the other. (easy) - [Case sensitivity](https://testingurl.dev/scraping/url-structure/CaseSensitive): Paths are case-sensitive here; the lowercase variant of this URL is a genuine 404. (medium) - [Query parameter order & tracking params](https://testingurl.dev/scraping/url-structure/query-params?b=2&a=1): A canonical tag computed from the request, sorting params and stripping known tracking params. (medium) - [Encoded characters](https://testingurl.dev/scraping/url-structure/encoded-chars?value=hello%20world): Shows the raw vs. decoded query string: %20, +, and a literal space. (medium) - [The tag](https://testingurl.dev/scraping/url-structure/base-tag): A one directory above the page's own URL, so a relative link resolves somewhere unexpected. (hard) ### Canonical tags & meta robots directives - [Overview](https://testingurl.dev/scraping/crawler-directives): Links to every canonical and meta robots scenario below. (easy) - [Canonical: self-referencing](https://testingurl.dev/scraping/crawler-directives/canonical-self): The recommended default: a page canonical to itself. (easy) - [Canonical: duplicate content, page A](https://testingurl.dev/scraping/crawler-directives/canonical-duplicate-a): The preferred URL in a duplicate-content pair. (medium) - [Canonical: duplicate content, page B](https://testingurl.dev/scraping/crawler-directives/canonical-duplicate-b): A different URL with the same content, canonical to page A. (medium) - [Canonical: tag vs. header conflict](https://testingurl.dev/scraping/crawler-directives/canonical-conflict): The tag names one URL, the HTTP Link header names another. (hard) - [Canonical: cross-domain](https://testingurl.dev/scraping/crawler-directives/canonical-cross-domain): Canonical points at a URL on a different domain, the syndicated-content pattern. (medium) - [Meta robots: noindex, follow](https://testingurl.dev/scraping/crawler-directives/meta-noindex): Keep this page out of the index, but still crawl its links. (easy) - [Meta robots: index, nofollow](https://testingurl.dev/scraping/crawler-directives/meta-nofollow): Index this page, but don't follow its outbound links. (easy) - [X-Robots-Tag header](https://testingurl.dev/scraping/crawler-directives/x-robots-header): The same noindex directive as an HTTP header instead of a meta tag, the only option for non-HTML resources. (medium) - [Meta robots: noarchive, nosnippet](https://testingurl.dev/scraping/crawler-directives/meta-noarchive-nosnippet): Index this page, but don't cache a visible copy or show a snippet. (easy) ### hreflang - [Overview](https://testingurl.dev/scraping/hreflang): Links to all three language variants. (easy) - [English variant](https://testingurl.dev/scraping/hreflang/en): hreflang="en", linking to the Spanish and French variants plus x-default. (medium) ### Redirect mechanisms - [Overview](https://testingurl.dev/scraping/redirect-mechanisms): Links to every redirect-mechanism scenario below. (easy) - [Meta refresh](https://testingurl.dev/scraping/redirect-mechanisms/meta-refresh): A tag; the server response itself is a plain 200. (medium) - [JavaScript redirect](https://testingurl.dev/scraping/redirect-mechanisms/js-redirect): window.location set from a script, invisible to a scraper that skips JS execution. (hard) - [Infinite redirect loop](https://testingurl.dev/scraping/redirect-mechanisms/loop/a): Two real HTTP 302s that point at each other forever, on purpose. (hard) ## HTTP & Networking Endpoints for testing HTTP clients, status codes, and headers directly. ### Status & redirects - [Status code echo](https://testingurl.dev/http/status/404): Returns the requested HTTP status code. Try /http/status/{code}. (easy) - [Redirect chain](https://testingurl.dev/http/redirect/3): Issues N sequential 302 redirects. Try /http/redirect/{n}. (easy) - [Redirect to URL](https://testingurl.dev/http/redirect-to?url=https://example.com): Redirects to any http(s) URL you supply via ?url=, with an optional ?status_code=. (easy) - [Delayed response](https://testingurl.dev/http/delay/2): Delays the response by N seconds (max 10). Try /http/delay/{seconds}. (easy) ### Headers & cookies - [Header echo](https://testingurl.dev/http/headers): Returns the request headers as JSON. (easy) - [Request echo](https://testingurl.dev/http/anything): Accepts any method and echoes back the method, headers, query, and body. Try POSTing JSON to it. (easy) - [Set response headers](https://testingurl.dev/http/response-headers?X-Test=hello): Every query param becomes a real response header, and is echoed in the JSON body. (easy) - [User-Agent check](https://testingurl.dev/http/user-agent): Tests header-spoofing logic: returns 403 unless your User-Agent looks like a real browser. (medium) - [Your IP](https://testingurl.dev/http/ip): Returns the connecting client IP as seen by the edge. (easy) - [Set cookie](https://testingurl.dev/http/cookies/set?name=foo&value=bar): Sets a cookie from query params, then redirects to /cookies/get. (easy) - [Get cookies](https://testingurl.dev/http/cookies/get): Returns current cookies as JSON. (easy) ### Authentication - [Basic auth](https://testingurl.dev/http/auth/basic): Protected by HTTP Basic Auth (user: demo / pass: demo). (easy) - [Bearer token auth](https://testingurl.dev/http/auth/bearer): Requires an Authorization: Bearer demo-token header. (easy) ### Compression & rate limits - [Gzip response](https://testingurl.dev/http/gzip): A padded JSON body, transparently gzip-compressed by the edge when the client sends Accept-Encoding. (medium) - [Rate limiting](https://testingurl.dev/http/rate-limit): Returns 429 after 5 requests within 60 seconds from the same client. (medium) ### Caching & conditional requests - [Conditional GET](https://testingurl.dev/http/cache): Returns Last-Modified/ETag headers; send either back to get a 304 with no body. (medium) - [ETag round-trip](https://testingurl.dev/http/etag/testing-abc123): Send the same value back via If-None-Match to get a 304. Try /http/etag/{value}. (medium) ### Streaming & content negotiation - [Streamed NDJSON](https://testingurl.dev/http/stream/5): Streams N newline-delimited JSON lines via a real ReadableStream. Try /http/stream/{n} (max 100). (medium) - [Byte-range requests](https://testingurl.dev/http/range/1000): Supports Range: bytes=start-end with real 206/416 responses, for resumable-download testing. (medium) - [Image content negotiation](https://testingurl.dev/http/image): Returns a real SVG or PNG depending on the Accept header. (medium) ## Mock Data A small fake REST API for mocking data in your own apps. Responses are deterministic, JSONPlaceholder-style, and nothing is persisted. ### Users API - [Users API reference](https://testingurl.dev/mock-data/users/docs): Every endpoint documented: list, get, create, update, delete, plus a generated avatar per user. (easy) ### Posts & Comments API - [Posts & Comments API reference](https://testingurl.dev/mock-data/posts/docs): Endpoint reference covering nested /posts/:id/comments and ?userId=/?postId= filtering. (easy) ### Albums & Photos API - [Albums & Photos API reference](https://testingurl.dev/mock-data/albums/docs): Covers nested /albums/:id/photos, plus generated per-photo images. (easy) ### Todos API - [Todos API reference](https://testingurl.dev/mock-data/todos/docs): Documents every endpoint, including ?userId= and ?completed= filtering. (easy) ## Generators Instant, no-signup generators for bulk test data. Output is fresh every time, unlike the deterministic Mock Data fixtures above. ### User Generator - [Generate users](https://testingurl.dev/generator/users): Interactive generator with instant JSON/CSV download. No signup or email required. (easy) ### Card Generator - [Generate test cards](https://testingurl.dev/generator/cards): Visa, Mastercard, Amex, and Discover-shaped numbers. Not real, not linked to any account, and cannot be charged. (easy) ### File Generator - [Generate a dummy file](https://testingurl.dev/generator/files): txt, csv, json, or random bytes, at any size up to 5MB. (easy) ### Image Generator - [Placeholder image](https://testingurl.dev/generator/images/400/300): Deterministic per dimension, unlike the other generators here. Try /generator/images/{width}/{height}. (easy) ## AI & LLM Testing Test fixtures for people building AI agents, LLM-feeding scrapers, and RAG pipelines. Includes prompt-injection isolation testing, a RAG testing dataset with a documented answer key, and RAG testing PDFs and documents built to stress-test extraction. ### Prompt injection - [Prompt injection test page](https://testingurl.dev/ai/prompt-injection): Seven hidden-text vectors (HTML comments, display:none, off-screen, color-matched, zero-font, alt text, meta description), each with a unique canary. (medium) ### RAG & retrieval corpus - [Corpus & answer key](https://testingurl.dev/ai/corpus): Every article in the dataset, plus sample queries mapped to the correct expected result. (easy) - [Example article](https://testingurl.dev/ai/corpus/articles/1): Available as HTML, plain Markdown, or PDF, and in bulk as JSON at /ai/corpus/articles.json. (easy) - [Full dataset bundle](https://testingurl.dev/ai/corpus/dataset.json): The whole RAG testing dataset in one download: every article, every format URL, and the answer key in a single JSON file. (easy) ### PDF documents - [PDF documents](https://testingurl.dev/ai/pdf-documents): Every RAG testing PDF on the site in one place, including a plain PDF version of each corpus article. (easy) - [Table extraction test](https://testingurl.dev/ai/pdf-documents/table): A drawn table (an order log) that tests whether extraction keeps each row's cells together instead of reading columns out of order. (medium) - [Two-column layout test](https://testingurl.dev/ai/pdf-documents/two-column): Two unrelated essays placed side by side to test whether extraction respects column boundaries instead of reading straight across the page. (hard) - [Running header/footer test](https://testingurl.dev/ai/pdf-documents/running-header-footer): A multi-page document with repeated header and footer boilerplate on every page, testing whether extraction strips it out. (hard)