Instapaper API Python Library
The official Python client for the Instapaper API v2. Save articles, keep a user's library in sync, organize bookmarks into folders and tags, work with highlights, and read parsed article text.
It has no dependencies outside the Python standard library.
Installation
pip install instapaper-api
Requires Python 3.10 or later.
Quick start
If you're calling the API for your own Instapaper account, such as from a script or a personal tool, you don't need the OAuth flow. Register an application, then generate an access token on its page. See Accessing your own account.
from instapaper import Instapaper
client = Instapaper("your-access-token")
for bookmark in client.bookmarks.list():
print(bookmark.title, bookmark.url)
bookmark = client.bookmarks.save("https://example.com/article", title="An Article")
client.bookmarks.like(bookmark.id)
Authenticating other users with OAuth
To act on behalf of other Instapaper users, send them through the OAuth 2 authorization code flow. Add your redirect URI to your application's callback URIs first; it has to match exactly.
import secrets
from instapaper import Instapaper, OAuth
oauth = OAuth(
client_id="your-client-id",
client_secret="your-client-secret",
redirect_uri="https://yourapp.example.com/callback",
)
state = secrets.token_urlsafe(16)
url = oauth.authorization_url(state=state)
# Redirect the user to `url`. Instapaper sends them back to your redirect URI
# with ?code=...&state=... once they approve.
# In your callback, check that `state` matches, then:
token = oauth.exchange_code(code)
client = Instapaper(token.access_token)
Access tokens don't expire, so store the token rather than the code. Keep your client secret on your server.
Bookmarks
# One page of a section: home (default), archive, liked, folder, or tag
page = client.bookmarks.list(section="archive", limit=50)
print(f"{len(page)} of {page.total}")
for bookmark in page:
print(bookmark.title)
# Every bookmark in a folder, fetched page by page
for bookmark in client.bookmarks.iterate(folder_id=99):
...
# Save with tags, straight into a folder
client.bookmarks.save("https://example.com/recipe", tags=["Recipes"], folder_id=99)
# Save content that has no public URL
client.bookmarks.save(private_source="Acme Reader", content="<p>...</p>", title="A Private Article")
client.bookmarks.update(12345, progress=0.42)
client.bookmarks.archive(12345)
client.bookmarks.move_to_folder(12345, 99)
client.bookmarks.update_tags(12345, add=["Recipes"], remove=[7])
client.bookmarks.delete(12345) # permanent, not the same as archiving
Syncing
sync returns everything that changed since a Unix timestamp, across every section, including the IDs of bookmarks deleted since then.
import time
started = int(time.time())
changes = client.bookmarks.sync(since=last_sync)
for bookmark in changes.bookmarks:
... # insert or update your local copy
for bookmark_id in changes.deleted_ids:
... # remove it locally
last_sync = started
Use changes instead if you want to fetch one page at a time.
Article text
article = client.bookmarks.parse(12345)
print(article.metadata.title)
print(article.content.body) # HTML with scripts stripped
Parsing without a key is allowed for personal use, when the account you're reading belongs to the developer who registered the application. To read other users' articles, pass your own Instaparser key as instaparser_api_key. See Non-personal use, and read the API Terms of Use for what you may do with article text.
Folders, tags, and highlights
folder = client.folders.create("Recipes")
client.folders.reorder({folder.id: 1})
client.folders.delete(folder.id) # its bookmarks move back to the home list
tag = client.tags.create("Cooking")
client.tags.rename(tag.id, "Food")
highlight = client.highlights.create(12345, "The passage the reader marked.")
client.highlights.list(12345)
client.highlights.delete(highlight.id)
Accounts without Instapaper Premium can create five highlights a month. Past that, create raises PermissionDeniedError.
Errors
Every error this library raises is an InstapaperError. When the API answers with an error status you get an APIError subclass carrying status and message:
| Exception | Status | When |
|---|---|---|
BadRequestError |
400 | A missing or invalid argument |
AuthenticationError |
401 | The access token is missing, unknown, or revoked |
QuotaExceededError |
402 | Instaparser credits ran out |
PermissionDeniedError |
403 | The application isn't approved or is suspended, or a Premium limit |
NotFoundError |
404 | No such endpoint |
RateLimitError |
429 | Too many requests |
ServerError |
5xx | Something went wrong on Instapaper's side |
InstapaperConnectionError means the request never got a response, and OAuthError comes from OAuth.exchange_code.
from instapaper import AuthenticationError, RateLimitError
try:
client.bookmarks.save("https://example.com/article")
except AuthenticationError:
... # ask the user to reconnect
except RateLimitError:
... # back off and try again later
Branch on the exception type or status, not on message, which may be reworded over time.
Documentation
The full API reference lives at instapaper.com/developers.
License
MIT. See LICENSE.
Release files for instapaper-api 1.0.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 | |
|---|---|---|---|
| instapaper_api-1.0.0.tar.gz | 15.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| instapaper_api-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.3 kB
Release files / instapaper_api-1.0.0.tar.gz
| Download URL | instapaper_api-1.0.0.tar.gz |
|---|---|
| Size | 15.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
34103b4684f64594eecfae44600079cf72e27bde5605a46ada660013f8915297
|
|
BLAKE2b-256 checksum How to use checksums |
73000e3f52eb61d5541ee31ea23eaa420ee18479d1f936532391953ec4b813ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / instapaper_api-1.0.0-py3-none-any.whl
| Download URL | instapaper_api-1.0.0-py3-none-any.whl |
|---|---|
| Size | 18.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9a4a5d655e32773186581fe53dbff1dc29911f322ef2bd1843f3e02169174fa0
|
|
BLAKE2b-256 checksum How to use checksums |
75f28e35bcd7e7be59c04849f4b339e2d2dcdcbc13bdb17dc9a7d966b44b343c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log