Changelog to JSON - Release Notes, GitHub Releases, npm & PyPI avatar

Changelog to JSON - Release Notes, GitHub Releases, npm & PyPI

Pricing

from $2.80 / 1,000 version returneds

Go to Apify Store
Changelog to JSON - Release Notes, GitHub Releases, npm & PyPI

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

NeverEmpty

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

17 days ago

Last modified

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

InputHow 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-found and why (free). Set returnWholeTextIfUnsplit to 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 CHANGES or Backwards incompatible changes in 5.2, a label at the start of an item (BREAKING:, **Breaking:**, Breaking change:, 破壊的変更:), an upper-case BREAKING, or a feat!: style commit. A mid-sentence mention ("the previous release included an erroneous breaking change"), a negated form (Non-breaking changes), a ⚠️ Notable Changes heading and a major version bump alone are not marked. hasBreakingMarker: false means "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; note says 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 free rate-limited row if there is no changelog file). Add githubToken (no scopes needed) for 5,000 per hour; it is sent only to api.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 as 3.14.0-beta.4 / 3.14.0-rc.2 with isPrerelease: true, never as the final release.
  • The same changelog given twice through different fields (for example its URL in urls and the package in npmPackages) is read and charged twice; the same field written differently is read once.
  • Pages over 10 MB are read up to 10 MB (note says so).
  • date is 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):

CheckResult
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 returned347 / 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 date292 / 299 (97.7%)
Web pages whose newest version or post (title and date) was read correctly16 / 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 / Unreleased becoming Released 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; note says 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

FieldTypeDefaultDescription
urlslist–Changelog files and pages. GitHub repository, npmjs.com and pypi.org package links are read as repositories / packages.
reposlist–GitHub repositories as owner/name (or owner/name/path/to/package).
npmPackageslist–npm package names.
pypiPackageslist–PyPI project names (versions and dates only).
sinceVersiontext–Only versions greater than this (semantic-version order; pre-releases sort before their release).
sinceDatetext–Only versions dated after this day (YYYY-MM-DD).
maxVersionsinteger20Newest N versions per input (1–1,000).
includePrereleasesbooleanfalseAlso return alpha / beta / rc / canary / next / dev versions and GitHub pre-releases.
includeUnreleasedbooleanfalseAlso return an "Unreleased" section.
includeBodybooleantrueInclude the full notes text as Markdown (body, up to 20,000 characters).
returnWholeTextIfUnsplitbooleanfalseReturn a page that cannot be split as one row of text.
onlyNewVersionsbooleanfalseMonitor mode: only versions not seen in earlier runs of the same watch.
watchNametext–Name of the remembered state for monitor mode.
resetMonitoringStatebooleanfalseForget what this watch remembered.
githubTokensecret–Optional GitHub token for a higher API allowance; sent only to api.github.com.
maxConcurrencyinteger4Inputs read at the same time (1–8).
requestTimeoutSecsinteger25Time 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.