Changelog to JSON - Release Notes, GitHub Releases, npm & PyPI
Pricing
from $2.80 / 1,000 version returneds
Changelog to JSON - Release Notes, GitHub Releases, npm & PyPI
For AI agents and developers upgrading a dependency: give a changelog page, GitHub repo or npm/PyPI package, get one JSON row per version with date and added / fixed / removed / breaking items, only versions newer than yours if you ask. On 41 real changelogs, 371 of 375 versions returned were real.
Pricing
from $2.80 / 1,000 version returneds
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
17 days ago
Last modified
Categories
Share
For AI agents and developers who need to know what changed in a library or API since the version they use. Give a changelog page, a GitHub repository or an npm / PyPI package; get back one JSON row per version: version number, date, the notes sorted into added / changed / deprecated / removed / fixed / security / breaking lists, whether a breaking-change marker is written, and the full notes text. Ask for sinceVersion to get only the versions newer than yours, or turn on monitor mode to get only versions that appeared since the last run.
Quick example
Input:
{"repos": ["expressjs/express"],"maxVersions": 2}
First output row (real run, shortened):
{"status": "ok","input": "expressjs/express","repository": "expressjs/express","source": "changelog-file","sourceUrl": "https://github.com/expressjs/express/blob/HEAD/History.md","version": "5.2.1","tag": "v5.2.1","title": "5.2.1 / 2025-12-01","date": "2025-12-01","dateSource": "heading","releasePublishedAt": "2025-12-01T20:54:44Z","isPrerelease": false,"hasBreakingMarker": false,"breakingMarkers": [],"fixed": [],"otherChanges": ["Revert security fix for [CVE-2024-51999](https://www.cve.org…"],"itemCount": 1,"entryUrl": "https://github.com/expressjs/express/releases/tag/v5.2.1","alsoFoundIn": "github-releases","versionsFound": 304,"note": "Of 304 version(s) found: 11 pre-release(s) left out (includePrereleases); 291 older one(s) beyond maxVersions 2."}
The version was found both in the repository's History.md and in GitHub Releases; the row uses the History.md text (source) and adds the release page and publish time from GitHub. The notes of 5.2.1 mention "an erroneous breaking change" of the previous release, which is not a breaking-change marker for this version (only a label such as BREAKING: or a "Breaking changes" heading is).
To get only what changed since your version, add "sinceVersion": "5.1.0". For an npm or PyPI package use npmPackages / pypiPackages; for any changelog page use urls.
With no input at all, the Actor reads the example https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md and returns its newest 3 versions.
What it reads
| Input | How it is read |
|---|---|
Changelog page URL (urls) | CHANGELOG.md, HISTORY.md, CHANGES.rst, Releases.md and similar files (a github.com/.../blob/... link is read as the raw file), /changelog and /release-notes web pages, and single release-notes pages. The page is split at the headings that carry a version number or a date; pages that list dated posts (a <time> element or a date line next to each title) are split at those dates. |
GitHub repository (repos, owner/name) | Both the GitHub Releases list (official REST API) and the changelog file in the repository are read and matched by version. The source column says which one each row came from (changelog-file or github-releases) and alsoFoundIn says when the other one had the same version. For a package in a monorepo write owner/name/path/to/package. |
npm package (npmPackages) | The repository is taken from the npm registry, then read like a GitHub repository (the changelog in the package's own folder first). registryLatestVersion is the latest published version. |
PyPI package (pypiPackages) | PyPI's public release feed: the newest 40 version numbers with upload times. No release notes — PyPI's project pages answer automated readers with a check page and its JSON API is disallowed by its robots.txt, so this Actor does not use them. Give the repository or the changelog URL to get the notes. |
Formats handled (measured on real changelogs, see below): Keep a Changelog (## [1.2.0] - 2024-01-02, ## [Unreleased]), release-please / standard-version (## [1.2.0](compare-link) (2024-01-02) with ### Features / ### Bug Fixes / ### ⚠ BREAKING CHANGES), Changesets (### Major Changes / ### Minor Changes / ### Patch Changes), setext and reStructuredText headings (Version 3.0.0 underlined, Released 2023-09-30 on the next line), plain lines such as v10.11.0 - September 18, 2026, calendar versions (2026.9.1, not read as a date), date-style API versions (2026-08-26.dahlia), go1.27.0 (released 2026-08-19), dates in English (September 5, 2026, 5 Sep 2026), ISO and Japanese (2026年9月24日), and headings such as Sep 22 under a September, 2026 heading (the year is taken from the heading above and dateSource says so).
Honest limits
- A page that cannot be split is not guessed at. If no heading carries a version or a date, the row says
no-versions-foundand why (free). SetreturnWholeTextIfUnsplitto get the whole text as one row instead (charged as one row). - Breaking changes are marked only when the text says so: a heading such as
### ⚠ BREAKING CHANGESorBackwards incompatible changes in 5.2, a label at the start of an item (BREAKING:,**Breaking:**,Breaking change:,破壊的変更:), an upper-caseBREAKING, or afeat!:style commit. A mid-sentence mention ("the previous release included an erroneous breaking change"), a negated form (Non-breaking changes), a⚠️ Notable Changesheading and a major version bump alone are not marked.hasBreakingMarker: falsemeans "no marker is written", not "certainly compatible". - Pages drawn by JavaScript (the text is not in the HTML) are reported as
js-required(free). When an HTML page cannot be split, the Actor asks the site once more for its Markdown version (Accept: text/markdown), which some documentation sites serve to AI agents;notesays when that version was used. - GitHub API allowance: without a token GitHub allows about 60 API calls per hour per IP address. The Actor checks the remaining allowance first (that check is free), uses one call per 100 releases, and when the allowance is used up it reads only the changelog file and writes that in
note(or returns a freerate-limitedrow if there is no changelog file). AddgithubToken(no scopes needed) for 5,000 per hour; it is sent only toapi.github.com. - Pre-releases written after the version with a space (
Python 3.14.0 beta 4,3.14.0 release candidate 2) are returned as3.14.0-beta.4/3.14.0-rc.2withisPrerelease: true, never as the final release. - The same changelog given twice through different fields (for example its URL in
urlsand the package innpmPackages) is read and charged twice; the same field written differently is read once. - Pages over 10 MB are read up to 10 MB (
notesays so). dateis the date written in the changelog; for GitHub Releases it is the release's publish time. Registry upload times can differ from the written date by a day or two.
Respecting sites
Every address is checked against the site's robots.txt before it is requested (RFC 9309, longest match, * and $ patterns; this Actor's own name NeverEmptyChangelog is honoured if a site names it). A disallowed address is not requested and comes back as a free robots-disallowed row. The Actor does not sign in, does not solve or bypass check pages or CAPTCHAs, does not use proxies to get around a refusal, and does not read private or internal network addresses. It identifies itself with the user agent NeverEmptyChangelog/1.0.
Measured accuracy
On 41 real changelogs (2026-09-25; 25 files and repositories checked against an independent source — the npm registry's publish times, PyPI's release feed or GitHub Releases — and 16 web pages checked by reading the page):
| Check | Result |
|---|---|
| Returned versions that really exist (newest 15 per changelog) | 371 / 375 (98.9%); the 4 others are written in the changelog but were never published to npm (for example openai 7.12.0) or are a changelog entry for a pre-release |
| Published versions in the covered range that were returned | 347 / 352 (98.6%); the 5 missing ones (React 19.2.8 and 19.1.9, axios 1.14.1 and 1.18.1, Prettier 3.9.2) have no heading in those changelogs (checked by searching the files) |
| Dates within 3 days of the registry / GitHub date | 292 / 299 (97.7%) |
| Web pages whose newest version or post (title and date) was read correctly | 16 / 16 (Stripe API, Cloudflare, Claude API, OpenAI API, Resend, Linear, Vercel, Supabase, Notion, Go, Python, Kubernetes, Django 5.2, VS Code, kintone (Japanese), GitHub REST API) |
Covered: React, Vite, axios, Express, Anthropic SDK (TypeScript and Python), OpenAI SDK (Node and Python), Stripe Node, Tailwind CSS, Svelte, SvelteKit, Crawlee, Prettier, ESLint, Jest, Vue, Flask, Requests, Pydantic, FastAPI, HTTPX, Deno, Rust, Misskey (calendar versions) and the 16 pages above.
Monitor mode (only new versions)
Set onlyNewVersions: true and a watchName. The first run returns the newest versions (up to maxVersions) with changeType: "first-check" and remembers them and the older versions below them. Later runs return only versions that were not returned or remembered before (changeType: "new"), newest first, up to maxVersions per run (the rest come in the next run). A run with no new version returns one free no-new-versions row and is charged only the run start fee.
- A version that was left out as Unreleased or as a pre-release is not remembered, so it comes back as new once it is released (for example Flask's
Version 3.2.0 / UnreleasedbecomingReleased 2026-10-01). - A maintenance release of an older line (a new 4.22.3 below 5.2.1) is returned as new too.
- Entries without a version number (dated posts) are told apart by date, title and the start of their text, so two posts on the same day are two entries.
- If a source could not be read at earlier checks (for example GitHub Releases while the hourly allowance was used up), its versions are taken as the starting point the first time it is read and are not sold as new;
notesays how many. - Versions not returned because the run hit its maximum charge are not remembered, so the next run returns them.
- If the platform restarts a run, rows already returned are not returned or charged again.
Pricing
Pay per event:
- Version returned — each row with a version (or, when you ask for it, one unsplit changelog text).
- Run start — once per run that returned at least one version, or, in monitor mode, once per run that read a changelog and compared it (even when nothing is new).
Free: every row that says why nothing was returned (not found, robots.txt disallows, cannot be split, no newer version, rate limited, blocked, needs JavaScript, bad input). A run whose maximum total charge cannot cover the start fee plus one version requests nothing and is charged nothing.
Input fields
| Field | Type | Default | Description |
|---|---|---|---|
urls | list | – | Changelog files and pages. GitHub repository, npmjs.com and pypi.org package links are read as repositories / packages. |
repos | list | – | GitHub repositories as owner/name (or owner/name/path/to/package). |
npmPackages | list | – | npm package names. |
pypiPackages | list | – | PyPI project names (versions and dates only). |
sinceVersion | text | – | Only versions greater than this (semantic-version order; pre-releases sort before their release). |
sinceDate | text | – | Only versions dated after this day (YYYY-MM-DD). |
maxVersions | integer | 20 | Newest N versions per input (1–1,000). |
includePrereleases | boolean | false | Also return alpha / beta / rc / canary / next / dev versions and GitHub pre-releases. |
includeUnreleased | boolean | false | Also return an "Unreleased" section. |
includeBody | boolean | true | Include the full notes text as Markdown (body, up to 20,000 characters). |
returnWholeTextIfUnsplit | boolean | false | Return a page that cannot be split as one row of text. |
onlyNewVersions | boolean | false | Monitor mode: only versions not seen in earlier runs of the same watch. |
watchName | text | – | Name of the remembered state for monitor mode. |
resetMonitoringState | boolean | false | Forget what this watch remembered. |
githubToken | secret | – | Optional GitHub token for a higher API allowance; sent only to api.github.com. |
maxConcurrency | integer | 4 | Inputs read at the same time (1–8). |
requestTimeoutSecs | integer | 25 | Time limit per request (5–60 s). 429 and 5xx answers are asked again up to two more times. |
Output columns
status (ok, unsplit, or the reason: no-versions-found, no-versions-after, no-new-versions, no-changelog-found, rate-limited, js-required, robots-disallowed, robots-unreachable, login-required, blocked, not-found, http-error, unreachable, unreadable, bad-input, budget-reached), position, input, inputType, repository, package, source, sourceUrl, httpStatus, version, tag, title, date, dateSource, releasePublishedAt, isPrerelease, isUnreleased, hasBreakingMarker, breakingMarkers, added, changed, deprecated, removed, fixed, security, breaking, otherChanges, sections, itemCount, body, bodyTruncated, entryUrl, alsoFoundIn, registryLatestVersion, versionsFound, sortedBy, changeType, watchName, note, checkedAt.
Rows are sorted newest first: by version number when at least 80% of the versions are numbers (so a maintenance release of an older line does not jump above the current line), otherwise by date, otherwise in page order (sortedBy).
Support
Found a changelog that is split wrongly? Open an issue in the Issues tab with the URL and what you expected; it helps the next person.