notion-site-fetch
Fetch any public Notion page and print it as Markdown to stdout. No API token. No login. No headless browser. Just plain HTTPS calls to the endpoints Notion's own web client uses.
If the page opens for anyone in an anonymous browser tab, this tool can read it.
Install / run
The package is published on PyPI. The fastest way to run it is with
uvx, which fetches and
executes the tool on demand:
uvx notion-site-fetch https://example.notion.site/ > page.md
You can also install it permanently:
uv tool install notion-site-fetch
notion-site-fetch https://example.notion.site/ > page.md
# or with pipx:
pipx install notion-site-fetch
Requires Python 3.13+.
Usage
notion-site-fetch <url>
Markdown is written to stdout. Use shell redirection to save it:
notion-site-fetch https://example.notion.site/ > page.md
notion-site-fetch https://example.notion.site/Some-Subpage >> notes.md
Errors go to stderr; the exit code is non-zero on failure.
Accepted URL forms
| URL | What it fetches |
|---|---|
https://<sub>.notion.site/ |
Site's public home page |
https://<sub>.notion.site/<slug-or-id> |
A specific page on the public site |
https://www.notion.so/<...>-<32-char-page-id> |
A notion.so page URL |
Any URL whose path ends in a 32-character Notion page id is accepted
even without a .notion.site host.
Behavior
- Sub-pages stay as links. Only the page you ask for is fetched. To expand a linked sub-page, run the tool again with its URL.
- Toggles/dropdowns are expanded inline. Nothing is hidden behind a fold; nested toggles are followed recursively.
- Private pages fail clearly. If the page isn't publicly readable, the tool exits with an error rather than silently returning nothing.
- Pagination is handled for long pages.
What gets rendered
Headings (H1–H4), paragraphs, bold/italic/strikethrough/code inline formatting, links, bulleted/numbered/to-do/toggle lists with nesting, quotes, callouts (as blockquotes), dividers, code blocks (with language), images, bookmarks, video/file/PDF/audio embeds (as links), and inline equations.
Things that are deliberately skipped or simplified: table-of-contents and breadcrumb blocks (Markdown renderers generate their own), column-layout wrappers (children are flattened into normal flow), and collection-view databases (only the title is emitted — Notion does not expose row-level data to anonymous viewers).
How it works
Notion's public sites are served as an empty React shell and hydrated by client-side calls to three internal endpoints:
POST /api/v3/getPublicPageDatawith{"spaceDomain": "<sub>"}resolves a*.notion.sitesubdomain to aspaceId.POST /api/v3/getPublicSpaceDatawith thatspaceIdreturns thepublicHomePageblock id — the root page of the site.POST /api/v3/loadCachedPageChunkV2walks the page block by block, paginated with a cursor. Toggle children that the chunk loader skips are pulled in afterwards viasyncRecordValues.
All endpoints are unauthenticated and return JSON. The tool issues
these requests against the site's own subdomain (*.notion.site) where
possible to avoid Notion's cross-cell routing errors on www.notion.so.
License
MIT — see LICENSE.
Metadata
Release files for notion-site-fetch 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| notion_site_fetch-0.1.0.tar.gz | 7.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| notion_site_fetch-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.1 kB
Release files / notion_site_fetch-0.1.0.tar.gz
| Download URL | notion_site_fetch-0.1.0.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4702a4907d096495086cbf86e03c88a7e8c798db657871bf616fe1c51472b0de
|
|
BLAKE2b-256 checksum How to use checksums |
b4d734123a86035e9d27e6fd1847c46404b25b296b318e69dcc1a823e833a756
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / notion_site_fetch-0.1.0-py3-none-any.whl
| Download URL | notion_site_fetch-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c5c3fefaa600a9cc100ef895b640471652e61029891d24449f137da352ff7d8
|
|
BLAKE2b-256 checksum How to use checksums |
913850974ca6c697530e1f404dcb7dba78bc709058bf4d6866da237fa1ef810c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for notion-site-fetch 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.