import type { Metadata } from "next"; import Link from "next/link"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { formatDateOnly } from "@/lib/format"; import { cn } from "@/lib/utils"; export const metadata: Metadata = { title: "Changelog", description: "Release notes for the Fetcha web access API, dashboard and SDKs. What shipped, what changed, and what is not available yet.", alternates: { canonical: "/changelog" }, }; type ChangeKind = "added" | "changed" | "fixed" | "not-yet"; type Entry = { date: string; // ISO date version: string; title: string; tag?: "preview" | "stable" | "beta"; summary: string; changes: Array<{ kind: ChangeKind; text: string }>; }; const ENTRIES: Entry[] = [ { date: "2026-09-08", version: "v0.2.1", title: "Turnstile captcha solving, real Chrome", tag: "stable", summary: "The managed browser now solves interactive Cloudflare Turnstile challenges through a human-verification service and runs on a real Google Chrome build.", changes: [ { kind: "added", text: "Captcha solver (2captcha) for Cloudflare Turnstile: widget parameters are intercepted in-page, a token is obtained and injected with the matching user agent. New request field solve_captcha (default true); attempts report captcha_solved in metadata.debug." }, { kind: "changed", text: "Managed browser runs Google Chrome (stable channel) as a real window on the node instead of the headless Chromium build, with the native user agent and client hints kept coherent." }, { kind: "changed", text: "Admin → System lists the anti-bot configuration (solver key presence, browser channel and mode); /internal/browser exposes solver statistics." }, ], }, { date: "2026-09-08", version: "v0.2.0", title: "Private access, managed browser, crawl & map", tag: "stable", summary: "Fetcha becomes a private, invitation-only platform with a single unlimited plan, and the browser layer goes live: rendered fetches with automatic escalation from plain HTTP, hardened HTTP fingerprints, much broader block detection, Markdown output with page metadata and links, and a new Crawl & Map API with its dashboard page.", changes: [ { kind: "changed", text: "Private access: signup is invitation-only (administrators manage the allowlist and send invitations). One plan, unlimited: no request quota, 200 concurrent requests, 120 s max timeout, 5 retries, all network classes, 90-day retention, browser rendering and crawl jobs. No billing, no checkout." }, { kind: "added", text: "Managed browser rendering: browser: true renders the page in a headless Chromium on the same network, country and session; wait_for, wait_ms, wait_until, javascript, block_resources and screenshot control the render. 8 concurrent renders per organization; BROWSER_TIMEOUT when a page does not settle." }, { kind: "added", text: "Automatic escalation: with browser_fallback (default on), an HTTP attempt blocked by a JavaScript challenge is retried in the browser. metadata.mode reports http or browser; debug attempts carry mode and block_reason." }, { kind: "changed", text: "Hardened HTTP fingerprints: ordered Chrome, Firefox and Safari header profiles rotated per attempt, HTTP/2, Chrome-like TLS cipher ordering, a cookie jar carried across redirects, jittered backoff between retries and Retry-After honoured within the timeout. referer: auto | none | url controls the Referer strategy." }, { kind: "changed", text: "Expanded block detection: Cloudflare challenge and Turnstile, DataDome, PerimeterX / HUMAN, Akamai, Kasada, Imperva, AWS WAF, Vercel attack mode and soft 200 blocks (challenge, interstitial or empty-shell pages returned with a 200)." }, { kind: "added", text: "format: \"markdown\" returns the page as Markdown (main content first, boilerplate removed) in markdown. Every HTML response now includes page { title, description, canonical, lang, og, links_count }; links: true adds links[] with absolute URLs, anchor text, internal and nofollow flags." }, { kind: "added", text: "Crawl API: POST /v1/crawl starts an asynchronous job (max_pages, max_depth, include/exclude patterns, robots, sitemap, concurrency, delay, format, browser); GET /v1/crawl, GET /v1/crawl/:id, GET /v1/crawl/:id/pages (cursor pagination, content per page) and DELETE /v1/crawl/:id. 2,000 pages per job, 5 concurrent jobs. Every page is a normal request in the log with source crawl." }, { kind: "added", text: "Map API: POST /v1/map lists a site's URLs from its sitemap and links, synchronously, with search filtering." }, { kind: "added", text: "Dashboard: Crawls page (jobs, status, stats, create dialog, job detail with pages and content preview, cancel, Map tool). Playground: markdown format, live Browser rendering section, Include links, Referer, mode badge, page metadata, Markdown / Links / Screenshot tabs." }, { kind: "added", text: "SDKs 0.2.0 (JavaScript and Python): markdown format, browser options, links and referer on fetch; crawl.create / get / pages / cancel / wait and map(). User-Agent fetcha-sdk-js/0.2.0 and fetcha-sdk-python/0.2.0." }, { kind: "changed", text: "BROWSER_UNAVAILABLE is now only returned when the browser pool is disabled or unavailable. New codes CRAWL_NOT_FOUND (404) and CRAWL_LIMIT_REACHED (429)." }, { kind: "not-yet", text: "Browser actions (POST /v1/browser), structured extraction (/v1/extract), webhook delivery (crawl webhook_url is stored, not called), datacenter, ISP and mobile network classes, teams, OAuth, 2FA, CLI." }, ], }, { date: "2026-09-07", version: "v0.1.0", title: "Public preview", tag: "preview", summary: "First public release of Fetcha. One endpoint, automatic routing over the residential network, sticky sessions, and a dashboard to try requests and read logs. Billing checkout was intentionally not part of this release; every account ran on the Free plan (superseded by the single unlimited plan in 0.2.0).", changes: [ { kind: "added", text: "Fetch API: POST /v1/fetch with country, region and city targeting, custom headers, cookies, body, timeout, format (html, text, json, raw), redirect controls and per-request retries." }, { kind: "added", text: "Automatic routing (network: \"auto\"): weighted per-domain scoring, circuit breakers and cheap-to-premium escalation with a fresh IP on every retry." }, { kind: "added", text: "Residential network class, live in 45 target countries. auto resolves to residential during the preview." }, { kind: "added", text: "Sticky sessions: POST /v1/sessions with TTL 60–1,800 s, labels, Idempotency-Key support; list, inspect and close sessions." }, { kind: "added", text: "Playground in the dashboard: run real requests, inspect attempts and timings, copy generated cURL, JavaScript and Python." }, { kind: "added", text: "Request logs with per-request id (X-Fetcha-Request-ID), status, network, attempts, latency and bytes. Sensitive headers redacted before storage." }, { kind: "added", text: "Usage metering: monthly requests and residential bandwidth per project, GET /v1/usage and GET /v1/me." }, { kind: "added", text: "SDK source for JavaScript/TypeScript (@fetcha/sdk) and Python (fetcha). Install from the repository until the packages are published to npm and PyPI." }, { kind: "added", text: "Documentation: quickstart, authentication, fetch reference, networks, geolocation, sessions, errors, retries, rate limits, SDKs and examples." }, { kind: "added", text: "Public status page with 24-hour success rate and 30-day history, and this changelog." }, { kind: "not-yet", text: "Browser execution (browser: true returns BROWSER_UNAVAILABLE), structured extraction (/v1/extract), datacenter, ISP and mobile network classes." }, { kind: "not-yet", text: "Billing checkout and self-serve upgrades (email sales@fetcha.co), teams and invitations, webhook delivery, OAuth login, 2FA and passkeys, CLI." }, ], }, ]; const KIND_META: Record = { added: { label: "Added", variant: "success" }, changed: { label: "Changed", variant: "info" }, fixed: { label: "Fixed", variant: "warning" }, "not-yet": { label: "Not yet", variant: "outline" }, }; export default function ChangelogPage() { return (

Changelog

What shipped, and what has not.

Release notes for the API, dashboard and SDKs. We list unavailable features explicitly so you never build against something that does not exist yet. Follow the status page for incidents. Fetcha is invitation-only: request access or log in.

    {ENTRIES.map((e) => (
  1. {e.version} {e.tag ? {e.tag === "preview" ? "Public preview" : e.tag === "beta" ? "Beta" : "Stable"} : null}

    {e.title}

    {e.summary}

      {e.changes.map((c, i) => (
    • {KIND_META[c.kind].label} {c.text}
    • ))}
  2. ))}

Missing something you need?

Roadmap priorities follow real usage. Tell us what would unblock you.

); }