Library / SDK
halcy/Mastodon.py avatar
halcy/Mastodon.py

Mastodon.py: driving a Mastodon server from Python

Python wrapper for the Mastodon ( https://github.com/mastodon/mastodon/ ) API.

958 stars172 forksPythonMIT

At a glance

What is it?
Mastodon.py is a MIT licensed Python client for the Mastodon REST API, complete for the public API as of Mastodon 4.7.3, with OAuth handled through persisted secret files. It suits scripts and services that post, read and stream from Fediverse servers, and it does not cover the admin API.
Who is it for?
Adopt Mastodon.py when your work needs a scripted client for a Mastodon instance, especially interactive login, posting, timelines and streaming, and look elsewhere when you need the admin API or a client outside Python.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A Python object over the Mastodon REST API

Mastodon.py is a wrapper around the Mastodon server's REST API, written and maintained in Python by Lorenz Diener under the halcy account. The project states that it is feature complete for the public API as of Mastodon version 4.7.3, and it is packaged on PyPI under the name Mastodon.py.

What the library actually is, from the code and metadata, is a thin object layer over HTTP calls. The package directory is a single mastodon/ package, the dependency list is short, and the three required libraries are requests for the transport, python-dateutil for timestamp handling and decorator for method wrapping. That is a small footprint, which matters for a client that ends up inside a cron job or a home lab container.

The scope boundary is stated rather than implied. The claim covers the public API, so features restricted to server administrators are not promised. The repository also carries a srcgen/ directory, which suggests the API surface is derived from the upstream schema rather than maintained only by hand, and a tests/ directory that runs against recorded HTTP interactions rather than a live server, since the test extras include vcrpy and pytest-recording.

The intended audience is a developer who wants to script against one or many Fediverse servers without assembling OAuth requests and multipart uploads by hand.

OAuth is handled through three persisted secret files

The most instructive part of the documentation is the authentication flow, because it shows how the library expects an application to be built and where credentials live. There are three distinct stages, two of which produce a file.

First, an application is registered once per server, or once per device and server when the app is distributed rather than hosted:

python
Mastodon.create_app(
    'pytooterapp',
    api_base_url = 'https://mastodon.social',
    to_file = 'pytooter_clientcred.secret'
)

That writes the client credentials to a file you name. Second, the user authorizes the application in a browser and hands back a code:

python
mastodon = Mastodon(client_id = 'pytooter_clientcred.secret',)
print(mastodon.auth_request_url())

The library hands back a URL to open, and the code that comes back is exchanged and written to a user credential file:

python
mastodon.log_in(
    code=input("Enter the OAuth authorization code: "),
    to_file="pytooter_usercred.secret"
)

Third, later runs reuse the stored token and act as the user:

python
mastodon = Mastodon(access_token = 'pytooter_usercred.secret')
mastodon.toot('Tooting from Python using #mastodonpy !')

The practical consequence is that the access token is a plain file on disk, and so is the client credential. Whether you keep those in a home directory, a container volume or a secret manager is your decision, and nothing in the documentation encrypts them for you.

Installation is one pip command, with extras for the harder features

The library installs from PyPI:

bash
pip install Mastodon.py

That gives you the core client with the three required dependencies. The features that need more than plain HTTP are split into optional dependency groups declared in pyproject.toml, and you install them by naming the group.

The webpush group brings in http_ece and cryptography, which are needed to encrypt and decrypt web push notification payloads. The websocket_streaming group adds websocket-client, which is what makes live timeline streaming possible. The blurhash group adds blurhash for decoding those placeholder images into pixels. The grapheme group adds graphemeu, which handles user perceived characters, the units people actually count when they say a post has thirty characters. There is also a magic group that pulls in python-magic on non-Windows systems and python-magic-bin on Windows, which is used to detect file types from content.

That split is worth understanding rather than just copying. A script that only posts text can install the base package and stay small. A service that streams timelines or serves push notifications needs two of the extras and their transitive dependencies.

One packaging detail that occasionally surprises people: the project ships both pyproject.toml and setup.py, and setup.py contains nothing but a call to setup(). All the real configuration lives in pyproject.toml, which lists the package name as Mastodon.py and the version as 2.3.3, with setuptools as the build backend.

Version coverage is stated as a snapshot, not a promise

The project describes itself as feature complete for the public API as of Mastodon version 4.7.3. That phrasing is precise and it carries an implication: the library tracks a specific upstream release, and its completeness claim is anchored to it.

In practice, a Mastodon server is often behind or ahead of any particular upstream release. Servers run their own versions and some fork the API, so the endpoints a given server exposes can differ from upstream. The library talks to Mastodon's API, so against a different implementation the question is which endpoints overlap and which do not.

The maintenance history supports the idea that coverage gets extended as upstream moves. The changelog is kept as CHANGELOG.rst at the top level, and the acknowledgements section points readers there for which contributor worked on which feature. Recent tags include v2.3.2 and v2.3.3, both dated 2026-10-18, and v2.2.2 dated 2026-08-03.

A reader deciding whether to adopt should treat the 4.7.3 figure as a floor to check against, not a ceiling. The README does not document a compatibility table per server version, and it does not say what happens when a client calls an endpoint the server has not implemented.

Python 3.7 is the floor, and a Python 2 classifier lingers

The documentation states that the project tries to support Python 3.7 and above and to at least not break Python versions below that, and that Python 2 support is no longer a goal. That is an honest statement of intent rather than a hard guarantee.

The packaging metadata is a little less tidy. The classifiers in pyproject.toml still list both Programming Language :: Python :: 2 and Programming Language :: Python :: 3, and the project is marked Development Status :: 5 - Production/Stable. A classifier claiming Python 2 support sits next to text saying Python 2 is no longer a goal, so anyone selecting the library from a package index filter rather than by reading the documentation can be misled about what is actually tested.

Practical effect for a new user: Python 3.7 is the lowest version worth targeting, and any environment older than that, which in practice means end of life distributions, is out of scope. The project also keeps a separate tox.ini file and both test and test_old dependency groups, where test_old is the same set minus pytest-retry. That split suggests the older interpreter is exercised less often than the current one, which is another reason to treat the 3.7 support claim as best effort.

The bigger picture is that the library is small, single purpose and installed from PyPI, so migrating away from it later is not a large undertaking.

Tests run against recorded HTTP interactions

The repository has a .circleci/ directory for continuous integration, a .githooks/ directory and a .github/ directory, plus tox.ini for running the suite across environments. The test dependency group lists pytest, pytest-cov, vcrpy, pytest-recording, pytest-mock, requests-mock, pytz and pytest-retry, and the pytest configuration in pyproject.toml adds coverage over the mastodon package by default.

The presence of vcrpy and pytest-recording is the most informative detail. Those tools replay recorded HTTP conversations, so the suite does not need to reach a live Mastodon server for most of its checks. Coverage is measured and uploaded to codecov, which the README links as a badge.

That design has two consequences. The test suite stays fast and hermetic, and it does not depend on any single server being reachable or unchanged. The trade-off is that recorded interactions only cover what was captured, so a behaviour change on the server side, or an endpoint that was never recorded, can slip past the suite until someone runs it against a real instance.

For an adopter this matters mostly for trust in upgrades. A recorded suite gives reasonable confidence that a new tag did not break the calls it covers, and no confidence at all about calls it does not.

Where Mastodon.py is the wrong tool

The clearest boundary is server administration. The completeness claim is scoped to the public API, so a project whose main work is moderating an instance, reviewing reports or managing domain blocks is outside the promised surface. A client aimed at the administrative endpoints would have to reach for something else, or for raw HTTP calls of its own.

There is a second boundary that is a matter of emphasis rather than capability. This library is a thin client, not a framework. It gives you methods for the API and takes care of tokens, URLs and multipart bodies, but it does not add scheduling, retry policy with backoff, a job queue or a content pipeline. The dependency list shows that intent clearly: requests for transport, dateutil for dates, decorator for method wrapping, and nothing that suggests a background worker.

The alternative approach for a Python codebase that needs more than API calls is to use requests directly against the Mastodon endpoints and own the token handling, or to put a service boundary around Mastodon.py so that your application talks to your own code rather than to the library directly. The difference in approach is ownership: this library saves you the OAuth dance and the request formatting, and in exchange your code becomes coupled to its method names.

A third case worth naming is non-Python. The wrapper exists for Python only, so a Go or Rust service that wants to post to a Mastodon server either makes HTTP calls itself or calls this library through a sidecar.

MIT licence and a fast release cadence

Mastodon.py is released under the MIT licence, declared both in pyproject.toml and in the LICENSE file at the top of the repository. MIT is permissive, with attribution and preservation of the licence text as the main obligations. That makes the library easy to embed in a commercial product or a closed service, and the practical caution is the ordinary one for MIT code: keep the copyright notice and licence text with any substantial redistribution.

The project also asks for citation in research contexts. The README points to a Journal of Open Source Software paper, Diener et al. (2026), Mastodon.py: A Python library for the Mastodon API, in volume 11, issue 120, article 8946, with a DOI, and the repository carries a CITATION.cff file at the top level for tooling that reads citation metadata.

On maintenance, the last push to the default branch was on 2026-10-18, and version 2.3.3 was tagged the same day, with v2.3.2 a short while earlier on the same date. Version 2.2.2 came on 2026-08-03. The upgrade path for a consumer is simply a new pip install, since the project publishes to PyPI and keeps its version in pyproject.toml, and the CHANGELOG.rst file at the top level is the place to check what changed before you pull a new tag.

Editorial conclusion

Adopt Mastodon.py when your work needs a scripted client for a Mastodon instance, especially interactive login, posting, timelines and streaming, and look elsewhere when you need the admin API or a client outside Python. Verify three things first: which Mastodon version your instance runs against the library's stated coverage of the public API as of Mastodon 4.7.3, which optional extra your use case needs, since streaming, web push and blurhash are separate installs, and where your client secret and access token end up on disk, because the credentials in this workflow are plain files you name yourself. The last push to master was on 2026-10-18 and version 2.3.3 shipped the same day, so an upgrade is a pip install rather than a migration.

Frequently asked questions

How do I install Mastodon.py?

Install it from PyPI with pip install Mastodon.py. The base package requires requests, python-dateutil and decorator, and features such as web push, websocket streaming, blurhash decoding and grapheme handling are separate optional dependency groups.

How does Mastodon.py handle OAuth login?

You register the app once with Mastodon.create_app and write the client credentials to a file, open the URL returned by auth_request_url in a browser, then pass the returned code to log_in with a to_file path. Later runs instantiate Mastodon with access_token pointing at the stored user credential file.

Does Mastodon.py support the Mastodon admin API?

The project states it is feature complete for the public API as of Mastodon version 4.7.3, and it does not claim coverage of administrative endpoints. Administration work is outside the stated scope.

Which Python versions does Mastodon.py support?

The project states it tries to support Python 3.7 and above and to at least not break older Python 3 versions, and that Python 2 support is no longer a goal. The package metadata still carries a Python 2 classifier, which does not match that statement.

Which Mastodon server version is Mastodon.py compatible with?

The project describes itself as feature complete for the public API as of Mastodon version 4.7.3. The library talks to the Mastodon API specifically, and the documentation does not provide a compatibility table for other server implementations.

Official sources

  1. halcy/Mastodon.py on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/halcy-mastodon-py.svg)](https://hysenlabs.com/projects/halcy-mastodon-py)

Was this useful?