md-to-medium-deltas
Convert standard Markdown into Medium's undocumented, internal JSON "Deltas" protocol for programmatic publishing.
The Problem
Before 2025, developers could programmatically publish to Medium using their official REST API by sending standard Markdown or HTML.
Medium has since deprecated its public API and stopped issuing integration tokens. The only way to programmatically post rich content to Medium now is to reverse-engineer their internal, React-based web editor protocol, which uses a proprietary JSON "Delta" structure (POST /p/{id}/deltas).
Existing libraries only convert Medium articles to Markdown. This library does the opposite: it parses Markdown and generates exact Delta operations (with correct inline markup text offsets) to reconstruct your article in Medium's editor.
Features
- Accurate Text Offsets: Automatically calculates character-exact boundaries for inline markup (bold, italic, code).
- Rich Elements Supported:
- Headings (H1, H2, H3)
- Inline formatting (Bold, Italic, Strikethrough, Code)
- Auto-linked Hyperlinks and Markdown Links
- Blockquotes
- Code blocks
- Ordered and Unordered Lists
- Intelligent Pre-processing: Fixes edge cases with list elements and correctly drops Markdown dividers that Medium handles natively.
Installation
pip install md-to-medium-deltas
(Note: Requires Python 3.12+)
Usage
from md_to_medium_deltas import markdown_to_deltas
markdown_text = """
# My Awesome Post
This is a paragraph with **bold** and *italic* text, plus a [link](https://github.com).
- Bullet point one
- Bullet point two
```python
print("Hello World")
"""
The start_index indicates the starting delta sequence position.
Pass 1 if your request already created a title delta at index 0.
By default, strip_h1=True drops the leading # Title from the body
so it doesn't duplicate your separate Title field.
deltas = markdown_to_deltas(markdown_text, start_index=1, strip_h1=True)
import json print(json.dumps(deltas, indent=2))
This output can then be directly sent as the payload to Medium's `POST /p/{id}/deltas` internal endpoint.
## How it works
This package uses a robust two-step pipeline:
1. `python-markdown` parses the raw Markdown into compliant HTML.
2. `selectolax` traverses the HTML AST and translates DOM nodes into Medium's Delta paradigm, tracking text accumulation to emit exact inline-markup offsets.
## License
MIT
Metadata
Release files for md-to-medium-deltas 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 | |
|---|---|---|---|---|
| md_to_medium_deltas-0.1.0.tar.gz | 6.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| md_to_medium_deltas-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.9 kB
Release files / md_to_medium_deltas-0.1.0.tar.gz
| Download URL | md_to_medium_deltas-0.1.0.tar.gz |
|---|---|
| Size | 6.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4841e334630e8496678eb68d3f73512ebde5e24c0b8bb8c229c1ab469fe7bc61
|
|
BLAKE2b-256 checksum How to use checksums |
ab150fd83f15c56a64a087adc541bc2041a4859a6d3a448de20a504c64750687
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / md_to_medium_deltas-0.1.0-py3-none-any.whl
| Download URL | md_to_medium_deltas-0.1.0-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f014d8c3c4c7e8fbb25eaf0359bd84ca8ce707cb3255bd04adfb2f37b6353209
|
|
BLAKE2b-256 checksum How to use checksums |
46a5480502961e332797c7ce1579d4f44b210bf6671cc55b228a9ee5e355d0d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for md-to-medium-deltas 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.