Self-hosted service
subzeroid/aiograpi-rest avatar
subzeroid/aiograpi-rest

aiograpi-rest puts Instagram's private API behind an HTTP boundary

🌐 RESTful API Wrapper for Instagram Private API

645 stars153 forksPythonMIT

At a glance

What is it?
aiograpi-rest is a FastAPI service that wraps aiograpi, the async fork of instagrapi, so an application in Node, Go, PHP or any other language can drive Instagram's private mobile API over HTTP. The trade is that it moves the protocol problem but not the operational one: accounts, proxies and session rotation are still yours.
Who is it for?
aiograpi-rest suits a team whose business logic is written outside Python and whose Instagram integration has been stuck on an archived client, and who is prepared to run a sidecar and own the account risk. It does not suit a Python team, because the README says you import aiograpi directly in that case, and it does not suit anyone who wants the operational burden handled for them, since the project lists accounts, proxies, session storage and retry logic as things you bring.
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 155 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

The problem is a language gap, not a missing feature

The README frames the project as an exit rather than a library. Instagram's private mobile API has been wrapped for many languages, and the wrappers that were once the standard have largely stopped moving. The specific examples given are the canonical Node and TypeScript client, which has not shipped a meaningful release since August 2024, and the canonical Go client, archived in 2021, and the Swift options are described as dead. The stated reason is that Instagram's surface keeps moving and the per-language wrapper authors largely stopped chasing it. The fix is to keep one maintained wrapper and put an HTTP boundary in front of it. The README is explicit about the audience: if your application is in Python you import the async library directly, and if it is in a different language you run the maintained Python library behind an HTTP boundary and call it from whatever language you actually write your business logic in.

The route verbs are strict, and the undo paths were removed

The API design is intentionally opinionated, and the README explains the reasoning because it is a departure from the old service. The version is declared once in pyproject.toml and exposed through the build and openapi.json endpoints. The rule is that GET is for reads and downloads, POST is for login and for creates and uploads, PATCH is for state changes, and DELETE is for removals or state reversal. The part worth knowing before you write a client is that the undo-style paths were removed before the public API became widely used, so there is no /media/unlike, no /user/unfollow and no /media/archive. You use DELETE /media/like, DELETE /user/follow and DELETE /media/archive instead. This is a deliberate cleanup rather than an oversight, and it means a client written against the older instagrapi-rest service needs its paths reviewed, not just its base URL.

Sessions, and the three ways to set one up

Authentication is a session id, and there are two ways to obtain one. You log in with a username and password, and the response body is the session id, or you import an existing Instagram sessionid cookie through the sessionid login route,

bash
SESSIONID=$(curl -fsS -X POST http://localhost:8000/auth/login \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=<USERNAME>&password=<PASSWORD>")

which accepts the same proxy, locale and timezone client options as the username and password route. Once you have one, you pass it as a header on protected routes. There is also a settings route that patches a session after the fact with the same three options, so a proxy can be changed without re-authenticating. The security surface here is the obvious one: a session id is a credential for an Instagram account, and the project is careful to state that the service collects nothing for you and that sessions are yours to store and rotate. The example in the README shows the settings call with a proxy URL containing a username and password, which is a reminder that the proxy credential travels in the request body.

Running it is one Docker command

The quick start is short because the container carries its own environment. The published image is tagged with the release version, and the README distinguishes the pinned tag from the latest tag for people who want the newest release on purpose:

bash
docker run --rm -p 8000:8000 subzeroid/aiograpi-rest
bash
docker run --rm -p 8000:8000 subzeroid/aiograpi-rest

The service listens on port 8000. The Dockerfile behind it is a multi-stage build on a slim Python base, installing the package with pip and then switching to a dedicated unprivileged user with its own uid and gid, creating a data directory owned by that user, and starting uvicorn against the application module on all interfaces. The runtime stage adds a health check that hits a health endpoint every 30 seconds with a 3 second timeout, a 10 second start period and 3 retries, so an orchestrator can tell a healthy container from a hung one. The compose file builds the same image, publishes the same port, and keeps the database in a named volume with the working tree mounted at the app path, and it defines a separate test service behind a profile so the test suite can run in the same environment.

The session store is a JSON file, and the API shape is paginated

Two implementation details tell you what this service is and is not. The first is the store. The database path is a single JSON file under the data volume, and the dependency list includes TinyDB, which is a document store that keeps its whole database in memory and writes the file on change. That is entirely adequate for a sidecar whose state is a handful of sessions, and it is not what you would use for an application with a large amount of state. The second is the response shape for list endpoints. Large read lists are paginated with a consistent shape, an items array and a next_cursor field, and you keep the cursor and pass it as the cursor parameter on the next request. That is the part a client library should be generated against, and the repository carries an openapitools.json alongside a docs/ directory, a Go client in golang/, a Swift client in swift/ and an examples/ directory with curl, Python and TypeScript samples, which is what an OpenAPI-driven client setup looks like in practice.

Upload endpoints take form fields, and JSON where a structure is expected

The write side has its own conventions, and they differ between routes. Story upload decoration fields are form fields, and for mentions you pass JSON as a form value. If the x, y, width, height or rotation values are omitted for a mention, a location or a hashtag, the service applies a centered default position before calling the underlying library. Feed upload and edit metadata works the same way: on the photo, video, clip, igtv and album upload routes and on the media PATCH route, usertags is passed as JSON-encoded objects and location as one JSON-encoded object. The example in the README for a story upload by URL shows the pattern, with the media address as a plain form field and the mentions array passed with the url-encoded flag so the JSON survives the form encoding intact.

What you still own, stated plainly

The section on what you still own is the most useful paragraph in the README, because it names the costs that the HTTP boundary does not remove. This is OSS infrastructure rather than a managed service, and self-hosting means you bring Instagram accounts and the operational headache of keeping them un-banned, residential or mobile proxies because Instagram's anti-abuse system flags datacenter IPs hard, session storage and rotation, and retry logic for when a challenge fires mid-script. The same team runs a hosted equivalent, called HikerAPI, which handles sessions and proxies on their side and is called over HTTPS with an API key, and the README says both paths are first-class. The honest framing is that this service solves the maintenance problem of the client library and leaves the operational problem of the account entirely with you, and that is a reasonable trade if you already have accounts and a proxy, and a poor one if you were hoping the service would make Instagram automation safe.

A rename that changed the package identity

The project was renamed from instagrapi-rest to aiograpi-rest in v1.0.0, and the reasoning is worth recording because it affects anything you have written against the old name. The old name made sense while the service wrapped the synchronous library, but the service is now powered by the async fork, and the README says the new name is more precise for package managers, Docker images, OpenAPI clients and repository discovery. The version line was restarted rather than continued: the new project starts its own semver line at 1.0.0 and is the renamed successor of instagrapi-rest 3.1.1, and the first release did not continue the old package version number. The current stable release is v6.0.0, wrapping a pinned version of the underlying library, and the metadata records Python 3.13 as the floor with FastAPI and uvicorn as the serving stack, and the licence as MIT.

Editorial conclusion

aiograpi-rest suits a team whose business logic is written outside Python and whose Instagram integration has been stuck on an archived client, and who is prepared to run a sidecar and own the account risk. It does not suit a Python team, because the README says you import aiograpi directly in that case, and it does not suit anyone who wants the operational burden handled for them, since the project lists accounts, proxies, session storage and retry logic as things you bring. Before adopting, read the route semantics section, because the undo-style paths were removed and the HTTP verbs are strict, and note that the last push to the repository was on 2026-05-21 with v6.0.0 tagged the same day under an MIT licence.

Frequently asked questions

How do I run aiograpi-rest?

With `docker run --rm -p 8000:8000 subzeroid/aiograpi-rest`. Use the version-pinned tag subzeroid/aiograpi-rest:6.0.0 for a reproducible runtime, or the latest tag when you deliberately want the newest release. The service listens on port 8000 and exposes live OpenAPI and Swagger UI at /docs.

How do I authenticate against aiograpi-rest?

Log in by posting a username and password to /auth/login, which returns a session id, or import an existing Instagram sessionid cookie through /auth/login/by/sessionid. Pass the session id on protected routes in the X-Session-ID header, and you can authorize once in the Swagger UI instead. Proxy, locale and timezone can be set at login, at session import, or patched later through /auth/settings.

Why did the undo-style API routes disappear?

The README says the undo-style paths such as /media/unlike, /user/unfollow and /media/unarchive were removed before the public API became widely used. The route semantics are now strict, with GET for reads and downloads, POST for login and creates, PATCH for state changes and DELETE for removals, so you use DELETE /media/like, DELETE /user/follow and DELETE /media/archive instead.

How does pagination work in the aiograpi-rest API?

Large read lists return the same shape, an items array with a next_cursor field. You keep the next_cursor value and pass it as the cursor parameter on the next request. User post collection routes such as /user/posts, /user/reels, /user/videos and /user/tagged/posts accept either user_id or username.

What does running aiograpi-rest still leave me responsible for?

The README lists the accounts and the operational work of keeping them un-banned, residential or mobile proxies since Instagram flags datacenter IPs hard, session storage and rotation, and retry logic when a challenge fires mid-script. The same team offers a hosted equivalent, HikerAPI, which handles sessions and proxies on their side and is called over HTTPS with an API key.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. subzeroid/aiograpi-rest on GitHub
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/subzeroid-aiograpi-rest.svg)](https://hysenlabs.com/projects/subzeroid-aiograpi-rest)

Was this useful?