# Chaquopy: running Python inside an Android app

> Chaquopy is the Python SDK for Android, a Gradle plugin plus a runtime that lets an Android app call Python and be called from Python, with a wide range of third-party packages such as SciPy, Pandas and Pillow available. The repository is a monorepo of four build components, and its version number is split into incompatible changes, features and bugfixes.

**chaquo/chaquopy** — Chaquopy: the Python SDK for Android

- Repository: https://github.com/chaquo/chaquopy
- Website: https://chaquo.com/chaquopy/
- Stars: 1,269 · Forks: 198
- Language: Python
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/chaquo-chaquopy

## A Python runtime for Android that hooks into the Gradle build

Chaquopy exists to solve one problem: you have Python code, or Python-shaped work to do, and the target is an Android app.

The project describes itself as providing everything needed to include Python components in an Android app, and it splits that into three promises. There is full integration with Android Studio's standard Gradle build system, so the Python side is not a side project that has to be orchestrated by hand. There are simple APIs for calling Python code from Java or Kotlin, and for calling back the other way, which is the part that decides whether Python is a guest in your app or a peer in it. And there is a wide range of third-party Python packages available, with SciPy, Pandas and Pillow named as examples.

The choice of Gradle as the integration point is the load-bearing decision. An Android app already has a build system with a dependency graph, and Chaquopy enters through it as a plugin, so the Python interpreter and the packages you select become declared dependencies rather than files you copy into `assets` by hand. The practical consequence is that a build that goes wrong goes wrong in a place you already know how to debug.

The getting-started pointer is the documentation site at `https://chaquo.com/chaquopy/doc/current/`, and the project homepage is `https://chaquo.com/chaquopy/`. Those are the places to look for the version compatibility table and the package list, because neither is in the repository.

## Four build components, one version number

The repository layout is documented explicitly, and it maps directly onto what the tool does.

`product/gradle-plugin` contains the Chaquopy Gradle plugin, the piece that enters your build. `product/runtime` contains the Chaquopy runtime libraries, the code that actually lives in the app. `target` contains build scripts for Python itself and its supporting libraries, so the interpreter is built by this project rather than assumed to exist. `server/pypi` contains build scripts for third-party Python packages, which is how a package such as Pandas gets compiled for the Android target.

That last directory is the one with real weight behind it. Building a Python package for Android means cross-compiling it, and the build scripts under `server/pypi` are where the per-package work lives. The top-level tree also contains `maven/`, which is where all build outputs are stored, a `VERSION.txt` holding the version, a `release/` directory, and `doc/` for the documentation sources.

The version number encodes what kind of change was made, and the scheme is spelled out in `pyproject.toml`. The version has three components, in order of importance: the first is incompatible changes, the second is features, the third is bugfixes. The changelog itself is generated with towncrier, configured to write into `product/runtime/docs/sphinx/changelog.rst` and to format each entry as a link to the issue on the project's issue tracker, with directories named `removal`, `feature` and `bugfix` mapping to the three version components.

So when a release is tagged 17.1.0, the leading number moves when something breaks compatibility, and the trailing number moves for a fix. That is a direct answer to the question a team integrating a Python runtime into a shipped app needs to ask: which kind of upgrade can you take without touching your code.

## Calls in both directions, and why that direction matters

The project lists simple APIs for calling Python code from Java or Kotlin, and vice versa. The second half of that sentence is the part that separates a language runtime from a script bundle.

Calling Python from the app is the obvious use: a Kotlin screen needs a computation, and instead of porting it you invoke Python. Calling back the other way is what lets Python be a real part of the app rather than a one-way function call. If Python code can reach into the app, then Python can drive application behaviour, own a long-running task, or sit in the middle of a pipeline where the app hands it work and takes results back.

The consequence for architecture is that the boundary between Kotlin and Python stops being a wall. The documentation describes the APIs as simple, which is the right claim to hold the project to, but the actual shape of the boundary is a decision you make, not one the SDK makes for you. Where you place the line determines what your team has to keep in sync during a rewrite, and whether a future port to pure Kotlin is a rewrite at all.

A second consequence follows from the packaging story. The `server/pypi` build scripts mean the third-party package set is compiled for Android rather than merely declared, so a package that cannot be cross-compiled, or that assumes a desktop platform, is not available. The project names SciPy, Pandas and Pillow as examples of what works, which is a useful signal about the kind of workload this is aimed at: numerical and data processing on device.

## The build needs the repository declared before mavenCentral

If you want to build an app against this repository rather than against published artifacts, the project gives you a precise instruction: edit the `repositories` block in your `settings.gradle` or `build.gradle` file to declare the repository before `mavenCentral`. Either an HTTP URL or a local path can be used.

Ordering matters here, and the reason is visible in how Gradle resolves. A repository declared ahead of `mavenCentral` is consulted first for the artifacts the build asks for, so the Chaquopy versions you want are found before the central ones. The requirement is a property of Gradle's resolution order rather than something specific to Chaquopy, and it is the kind of detail that produces a confusing failure when it is wrong, because a build can resolve an older artifact from the central repository without complaining.

For building Chaquopy itself, the guidance is to see the README files in each subdirectory, since `product/gradle-plugin`, `product/runtime`, `target` and `server/pypi` are separate builds. All build outputs go into the `maven` directory, which is the local artifact repository the app build then points at. That local path option is what makes the whole flow testable on a developer machine without publishing anything.

The `demo/` directory holds a working sample application with a `build.gradle.kts`, its own `settings.gradle.kts`, a Gradle wrapper and a `tests.md` describing the tests, so the fastest way to understand the integration is to read that build and then the `demo/app` module.

## Where Chaquopy is the wrong tool

The clearest case is when the Python requirement is small. If you need one numeric routine, adding a Python runtime and its build integration to an Android app is a large amount of machinery for a small amount of code, and a Kotlin implementation is easier to review, debug and profile. The size of the payload is the part people underestimate, because a Python runtime plus a compiled package set is not a small addition to an APK, and the project does not publish a figure for it, so the number has to be measured on your own build.

The second case is a data processing job that does not need to be on device. If your Python code is a training script, a batch transformation over files, or a service that talks to a database, running it in the Android app buys you nothing and costs you the runtime, the package build and the interop layer. The same Python in a server process, called over HTTP, is a much simpler system.

The third constraint is the package set. Availability of a Python package on Android is a build question, not a pip question, and the repository handles it with per-package build scripts under `server/pypi`. A package with a native extension that has no Android build is simply not an option, and the project names SciPy, Pandas and Pillow as examples rather than publishing an exhaustive list in the README, so you need to check the documentation for the specific package you want. The tree also contains `debugger/` and `hooks/` directories, which indicate that the development and integration surface goes beyond the build, but the repository does not describe what those contain at this level of detail.

## The alternative is usually to move the Python, not to embed it

There are two credible alternatives, and the choice between them and Chaquopy is mostly about where the work should live.

The first is to keep Python on a server. Your Android app calls an HTTP endpoint, the endpoint runs Python with whatever packages it likes, and the app receives JSON. The difference in approach is stark: the app ships no Python runtime and no compiled package set, the Python side gets a normal server environment with normal tooling, and the cost is network dependency, latency and a backend to operate. For a team that already runs services this is often the smaller change, and it is the right answer for anything batch or scheduled.

The second is to rewrite in Kotlin. The difference is that there is no runtime, no interop boundary and no second language in the codebase, and the code runs with the platform's own performance characteristics. The cost is that you now maintain two versions of the logic if the Python still has to run somewhere, and the port is real work rather than a config change.

Chaquopy sits between these. It is the option that keeps Python in the app process, on device, offline and close to the data, without a service dependency. That is the case it is built for, and it is why the package story, with SciPy, Pandas and Pillow compiled for Android, is the centre of the project rather than an afterthought. When your requirement genuinely is on-device Python, there is no equivalent in the other two approaches.

## Conclusion

Chaquopy fits an Android team that already has Python code or Python-shaped data processing to run on device and wants to keep it in Python rather than port it to Kotlin, and it does not fit a team whose only requirement is a single small numeric routine. Before adopting, read the documentation at chaquo.com/chaquopy/doc/current/ for the version compatibility table, and note the build requirement: the repository has to be declared ahead of `mavenCentral` in `settings.gradle` or `build.gradle`, which is an ordering constraint in your build file that you own and have to keep right.

## FAQ

### What is Chaquopy?

Chaquopy is the Python SDK for Android. It provides a Gradle plugin, a runtime library for the app, and build scripts that compile Python and third-party packages such as SciPy, Pandas and Pillow for the Android target.

### How do I add Chaquopy to an Android project?

The project integrates with Android Studio's standard Gradle build system through its Gradle plugin, and the getting started instructions are in the documentation at chaquo.com/chaquopy/doc/current/. If you build against the repository directly, you must declare it in the `repositories` block of your `settings.gradle` or `build.gradle` ahead of `mavenCentral`.

### Can Kotlin and Python call each other in Chaquopy?

Yes. The project lists simple APIs for calling Python code from Java or Kotlin and for calling Python the other way. The documentation for the current release is at chaquo.com/chaquopy/doc/current/.

### How do Chaquopy version numbers work?

The version has three components in order of importance, corresponding to incompatible changes, features and bugfixes. The changelog is generated with towncrier into `product/runtime/docs/sphinx/changelog.rst`, and the current release line is 17, with 17.1.0 released on 2026-10-12.

## Sources

- [chaquo/chaquopy on GitHub](https://github.com/chaquo/chaquopy)
- [License: MIT](https://github.com/chaquo/chaquopy/blob/master/LICENSE)
- [Project website](https://chaquo.com/chaquopy/)
- [README](https://github.com/chaquo/chaquopy/blob/master/README.md)
- [Releases](https://github.com/chaquo/chaquopy/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/chaquo-chaquopy
