
PyPI froze the HTML simple index API
Quick answer: PEP 833 went Final on 20 May 2026 and PyPI adopted it on 11 August 2026. The HTML simple index is not deprecated, not going away, and still gets every new package and release — but it is closed to new features, permanently. If you parse HTML you already cannot see versions, file size or upload-time, because PEP 700 added those to JSON only. Nothing breaks today. Everything added from here lands in application/vnd.pypi.simple.v1+json and nowhere else.
"Frozen" is a better word than "deprecated" and the distinction is the whole story. A deprecated API gets a removal date. A frozen one gets maintained forever and never improves. If you are consuming PyPI's HTML index, you are not on a deadline — you are on a branch that stopped growing.
PyPI's own announcement is careful to say so: new packages and releases "will continue to appear in the HTML representation, meaning this has no breaking implications for downstream index consumers", and "no immediate action is required". The same post then says downstreams that consume only HTML are "strongly encouraged" to move to JSON "to ensure access to the latest and greatest index features". Both halves are true, and only the second one matters in a year.
What PEP 833 actually says
PEP 833, "Freezing the HTML simple repository API", was created on 21 April 2026 and resolved on 20 May 2026. Its operative sentence is that the HTML representation "is considered complete from the perspective of the standards process, and SHOULD NOT be updated by future PEPs".
Note the modal. SHOULD NOT, not MUST NOT — the PEP leaves room for an exception with a compelling reason. In practice that means you should plan as if HTML is closed while accepting that a future PEP could, in principle, reopen it. The packaging specification now states the same thing in plainer language: "the HTML representation is considered 'frozen' and is not expected to be updated", and "producers and consumers of the simple API should prefer the JSON representation".
The rationale names three problems, and the second is the one worth sitting with. First, structural rigidity: HTML cannot carry new metadata without shoehorning it into attributes and meta tags. Second, parsing brittleness — third-party consumers "often rely on fragile HTML parsing techniques rather than robust parsing libraries", so a non-semantic change to the markup breaks them. Third, limited adoption: corporate indices frequently implement only the minimal PEP 503 baseline, which caps the practical value of improving the format at all.
That middle point is a polite way of saying a lot of people regex an HTML page. If you are one of them, the freeze is good news: the thing you are regexing will not change under you.
What you already cannot see in HTML
This is the part people get wrong. The freeze is not the moment HTML fell behind. HTML fell behind in 2022.
| Repo version | PEP | Adds | In HTML? |
|---|---|---|---|
| 1.0 | 629 | API versioning itself | Yes |
| 1.1 | 700 | versions, size, upload-time | No |
| 1.2 | 708 | Repository "tracks" metadata | Yes, via pypi:tracks |
| 1.3 | 740 | Provenance metadata | Yes, via data-provenance |
| 1.4 | 792 | Project status markers | Yes, via meta tags |
Check that column carefully, because the intuition most people carry is wrong. Of the four PEPs that have raised the repository version, exactly one withheld its additions from HTML. PEP 708 specifies meta.tracks in JSON and a pypi:tracks meta element in HTML. PEP 740 specifies a provenance key in JSON and a data-provenance attribute on file links in HTML. PEP 792 specifies both. Only PEP 700 did not.
PEP 700 is the clean break. It says, verbatim, "For the HTML version of the API, there is no change from version 1.0", and that "clients wishing to access the new data introduced by this PEP will need to use the JSON API to get it." Created October 2022, resolved December 2022. So if your tooling needs a project's full version list, a file's byte size, or when a file was uploaded, HTML has never had it and now never will.
Status markers are the counterexample, and worth getting right because it is easy to assume everything new is JSON-only. PEP 792's four values — active, archived, quarantined, deprecated — appear in both representations. HTML exposes them as pypi:project-status and optional pypi:project-status-reason meta tags; JSON exposes a structured project-status object with state and reason. Both define repository version 1.4. If you parse HTML, you can still tell that a project was quarantined for malware.
How to ask for JSON
Content negotiation, with versioned media types of the form application/vnd.pypi.simple.$version+format. The three you need:
application/vnd.pypi.simple.v1+json for JSON. application/vnd.pypi.simple.v1+html for explicit HTML. And plain text/html, which is aliased to v1+html for backward compatibility — which is also why a naive client that sends no Accept header gets the frozen format by default. There is a latest meta-version too, so you can request the newest iteration without knowing its number, and only the major version appears in the content type, signalling that minor additions will not break you.
The migration for most code is one header and a parser swap, and the JSON shape is flat enough that a JSON formatter is enough to read it by eye before you write anything. If you are porting a curl-based script, our curl-to-fetch converter will carry the Accept header across for you, and a JSON-to-TypeScript converter gets you types from a real response rather than from the spec prose.
If you install packages with mainstream tooling you are already on JSON and have been for years: pip has preferred the JSON representation since 22.2, and uv prefers it too. This is a problem for the code around the edges — mirrors, vendoring scripts, dependency dashboards, licence scanners, internal "what version is X" endpoints.
If you run a private index
The PEP's third rationale is aimed squarely at you. Corporate indices that implement only the minimal PEP 503 baseline are the reason improving HTML had limited value — and they are also the reason a client that works against PyPI can fail against your mirror. If your index serves HTML only, your users silently lose versions, size and upload-time, and any tool that filters by upload time stops being able to do its job against your repository even though it works against PyPI.
Two practical consequences. Serve application/vnd.pypi.simple.v1+json and advertise your repository version honestly; a client that sees 1.0 will not ask for fields you do have. And test your mirror with the same tooling your developers use rather than with a browser, because a browser sends text/html and will always get the frozen path. The multi-ecosystem resolvers now in play — pnpm resolving PyPI alongside npm and crates.io, for one — make this more likely to surface, because they exercise the JSON path from a client nobody tested your index against.
Worth noting that PyPI's own file hosting had a rough August: a misconfigured cache node in Fastly's network plus bugs in PyPI's origin-fallback and range-request configuration produced two weeks of intermittent 502s and 503s on downloads, resolved by 28 August. If you run a pull-through cache, that is an argument for it, not against it. The cloud and DevOps category lists the artifact proxies that do this layer, and our open-source listings cover the self-hostable ones.
Your download numbers also changed
Unrelated to the freeze but landing in the same month, and more likely to be noticed: on 31 August 2026 PyPI stopped counting metadata requests in download statistics. Only actual distribution files — those ending in .whl, .tar.gz or .zip — now count.
The numbers are more precise and, for packages whose metadata gets hit a lot by resolvers, lower. If you report PyPI downloads to anyone — a sponsor, a board, a README badge — expect a discontinuity at the end of August and do not read it as a drop in usage. Downstream consumers like pypistats.org are affected going forward. This is the same class of change as registries retiring endpoints and shifting what their numbers mean, which we looked at when npm retired its legacy audit endpoints: the API still answers, but what it answers has moved.
FAQ
Is the HTML simple index being removed?
No. It is frozen, not deprecated. New packages and releases keep appearing in it and PyPI says the change has no breaking implications for downstream consumers. There is no removal date and none is proposed.
Do I need to change anything right now?
PyPI's answer is no immediate action required. If you only install packages with pip or uv, you were already on the JSON representation. The work is in custom code that parses the index directly.
What exactly is JSON-only?
The fields PEP 700 introduced: the versions array, the size field in bytes, and upload-time in ISO 8601. PEP 700 states there is no change from version 1.0 for HTML and that clients needing that data must use the JSON API.
Are project status markers JSON-only?
No — this is the common misreading. PEP 792 specifies both: pypi:project-status meta tags in HTML, and a structured project-status object in JSON. Both define repository version 1.4.
Which header do I send for JSON?
Accept: application/vnd.pypi.simple.v1+json. Sending nothing, or text/html, gets you the frozen HTML representation, because text/html is aliased to v1+html for backward compatibility.
Could HTML ever be extended again?
Technically yes. PEP 833 uses SHOULD NOT rather than MUST NOT, leaving room for a compelling exception. Plan as though it will not happen; nothing in the packaging specification suggests it will.
The quietest kind of API decision: nothing broke, nothing was removed, and one of the two formats stopped being worth building on.

