WhatsApp Automation for Python
A Python library for WhatsApp automation. A native Go core built on whatsmeow is compiled into a shared library and exposed to Python through a zero-copy FFI layer.
Getting Started | Features | Examples | Documentation | Contributing
Why Neonize?
| Go core performance | The WhatsApp multidevice protocol runs in Go, called directly through ctypes. No subprocesses, no HTTP bridges. |
| Python native | Fully typed, idiomatic API. Sync and async clients with identical surfaces. |
| Persistent sessions | SQLite or PostgreSQL. Pair once, reconnect forever. |
| Enterprise ready | Structured error hierarchy, FFmpeg diagnostics, robust FFI with retry logic. |
Features
Messaging
- Send and receive text, images, videos, documents, audio, voice notes, stickers
- Message replies, reactions, polls, interactive buttons and lists
- Receipt and presence tracking
Groups and Channels
- Create, update, and manage groups (name, description, photo, participants)
- Newsletter/channel operations: fetch messages, update profile, send media
Contacts and Presence
- Profile picture retrieval, push name updates
- Typing and recording indicators
- Contact sync and blocklist management
Architecture
- Sync (
NewClient) and async (NewAClient) with identical APIs - Multi-session support via
ClientFactory - Event-driven with 37+ typed event classes
- QR code and phone-number pairing
Getting Started
Prerequisites
- Python 3.10 or newer
- FFmpeg (required for media operations: stickers, audio, video, thumbnails)
Installation
pip install neonize
Quick Start
from neonize.client import NewClient
from neonize.events import ConnectedEv, MessageEv
client = NewClient("session.db")
@client.event(ConnectedEv)
def on_connected(client: NewClient, _: ConnectedEv) -> None:
print("Connected")
@client.event(MessageEv)
def on_message(client: NewClient, message: MessageEv) -> None:
text = message.Message.conversation or message.Message.extendedTextMessage.text
if text == "ping":
client.reply_message("pong", message)
client.connect()
Async Quick Start
import asyncio
from neonize.aioze.client import NewAClient
from neonize.aioze.events import ConnectedEv, MessageEv
client = NewAClient("async_session.db")
@client.event(ConnectedEv)
async def on_connected(client: NewAClient, _: ConnectedEv) -> None:
print("Connected")
@client.event(MessageEv)
async def on_message(client: NewAClient, message: MessageEv) -> None:
text = message.Message.conversation or message.Message.extendedTextMessage.text
if text == "ping":
await client.reply_message("pong", message)
async def main():
await client.connect()
await client.idle()
asyncio.run(main())
Examples
Sending Media
from neonize.utils.jid import build_jid
jid = build_jid("1234567890", "s.whatsapp.net")
# Text
client.send_message(jid, "Hello from Neonize")
# Image with caption
with open("photo.jpg", "rb") as f:
msg = client.build_image_message(f.read(), caption="Photo", mime_type="image/jpeg")
client.send_message(jid, message=msg)
# Document
with open("report.pdf", "rb") as f:
msg = client.build_document_message(
f.read(), filename="report.pdf", mime_type="application/pdf"
)
client.send_message(jid, message=msg)
Handling Incoming Messages
from neonize.events import MessageEv, ReceiptEv, PresenceEv
from neonize.utils.message import extract_text
@client.event(MessageEv)
def on_message(client: NewClient, event: MessageEv) -> None:
text = extract_text(event.Message)
sender = event.Info.MessageSource.Sender
if text == "help":
client.reply_message("Available commands: help, time", event)
@client.event(ReceiptEv)
def on_receipt(client: NewClient, event: ReceiptEv) -> None:
print(f"Receipt: {event.Receipt.Type} for {event.MessageIDs}")
@client.event(PresenceEv)
def on_presence(client: NewClient, event: PresenceEv) -> None:
print(f"{event.MessageSource.Sender} is {event.Presence}")
Group Management
from neonize.utils.jid import build_jid
# Create group
participants = [build_jid("1234567890"), build_jid("0987654321")]
info = client.create_group("Project Team", participants)
print(f"Group created: {info.JID}")
# Update settings
client.set_group_name(info.JID, "New Name")
client.set_group_description(info.JID, "Updated description")
# Manage participants
client.update_group_participants(info.JID, [build_jid("5555555555")], "add")
Multi-Session (Async)
import asyncio
from neonize.aioze.client import ClientFactory, NewAClient
from neonize.aioze.events import MessageEv, ConnectedEv
factory = ClientFactory("multisession.db")
# Load existing sessions
for device in factory.get_all_devices():
factory.new_client(device.JID)
# Pair a new account
factory.new_client(uuid="second-account", new_device=True)
@factory.event(ConnectedEv)
async def on_connected(client: NewAClient, event: ConnectedEv) -> None:
print("Client connected")
@factory.event(MessageEv)
async def on_message(client: NewAClient, event: MessageEv) -> None:
if event.Message.conversation == "ping":
await client.reply_message("pong", event)
async def main():
await factory.run()
await factory.idle_all()
asyncio.run(main())
Integration with FastAPI
from contextlib import asynccontextmanager
from fastapi import FastAPI
from neonize.aioze.client import NewAClient
from neonize.aioze.events import MessageEv
from neonize.utils.jid import build_jid
client = NewAClient("fastapi_bot")
@client.event(MessageEv)
async def on_message(client: NewAClient, event: MessageEv) -> None:
if event.Message.conversation == "/status":
await client.reply_message("API is running", event)
@asynccontextmanager
async def lifespan(app: FastAPI):
await client.connect()
yield
await client.disconnect()
app = FastAPI(lifespan=lifespan)
@app.get("/send")
async def send(phone: str, message: str):
await client.send_message(build_jid(phone), message)
return {"status": "sent"}
Database Configuration
Neonize stores session data in a database. The default is SQLite, which works well for development and single-instance deployments.
# SQLite (default)
client = NewClient("bot", database="./session.db")
# PostgreSQL (recommended for production)
client = NewClient("bot", database="postgres://user:pass@localhost:5432/neonize")
# Connection pooling
client = NewClient(
"bot", database="postgres://user:pass@localhost/neonize?pool_min_conns=5&pool_max_conns=20"
)
# In-memory (testing only)
client = NewClient("bot", database=":memory:")
Project Structure
neonize/
├── examples/ # Runnable example bots
│ ├── basic.py
│ ├── async_basic.py
│ ├── multisession.py
│ ├── multisession_async.py
│ └── paircode.py
├── goneonize/ # Go shared library (FFI core)
│ ├── main.go
│ ├── defproto/ # Generated protobuf definitions
│ └── utils/ # Go encoder helpers
├── neonize/ # Python package
│ ├── __init__.py
│ ├── client.py # Sync client (NewClient)
│ ├── aioze/ # Async client (NewAClient)
│ ├── events.py # Event types and dispatcher
│ ├── exc.py # Exception hierarchy
│ ├── ext/ # Extensions (interactive messages)
│ ├── proto/ # Python protobuf bindings
│ └── utils/ # Helpers (JID, media, FFmpeg, etc.)
├── docs/ # Zensical documentation source
├── tools/ # Build, release, and dev scripts
└── pyproject.toml # Project metadata and dependencies
Contributing
We welcome contributions. See CONTRIBUTING.md for the branching model, conventional-commit standards, and release process.
# Clone and setup
git clone https://github.com/krypton-byte/neonize.git
cd neonize
uv sync --dev
# Build the Go shared library
CGO_ENABLED=1 uv run task build goneonize
# Run tests
uv run --with pytest python -m pytest
# Lint
uv run ruff check .
uv run ruff format --check .
Workflow: feature branches target dev, merges to master trigger the
automated release pipeline.
Documentation
Full documentation is available at neonize.readthedocs.io
Related Projects
| Project | Description |
|---|---|
| Thundra | High-level bot framework built on Neonize |
| Tryx | Rust-powered Python SDK for WhatsApp automation |
| Neonize Dart | Dart/Flutter wrapper for Neonize |
| Whatsmeow | Go WhatsApp Web API library that powers Neonize |
License
This project is licensed under the Apache License 2.0. See LICENSE for details.
Built by krypton-byte and contributors
Metadata
Release files for neonize 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 64.6 MB
Release files / neonize-0.7.0-py310-none-win_arm64.whl
| Download URL | neonize-0.7.0-py310-none-win_arm64.whl |
|---|---|
| Size | 6.5 MB |
| Tags | Python 3.10 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
2f7540f8ff3980e6a8a154d703a93fa7f3da5f089c02fc490ec6ee1d037121c9
|
|
BLAKE2b-256 checksum How to use checksums |
20ab2e50a0db8885bf3b13a91c226e59250d1851ee51d6363c07c84ecafa2c0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-win_amd64.whl
| Download URL | neonize-0.7.0-py310-none-win_amd64.whl |
|---|---|
| Size | 7.1 MB |
| Tags | Python 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
9c7480c2759bc8bd455fad7891783987b1692ecefdb83003be897d15e5d1853f
|
|
BLAKE2b-256 checksum How to use checksums |
e9c1fd85a4cc06f52b88ea1a943cd73e743c77d5a124168cbfaf84656e77d447
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-win32.whl
| Download URL | neonize-0.7.0-py310-none-win32.whl |
|---|---|
| Size | 7.0 MB |
| Tags | Python 3.10 Windows x86-32 |
|
SHA-256 checksum How to use checksums |
5790237c3ea7614c6118a96e4a853761de01c7fa8529b7df6af053b026ac4447
|
|
BLAKE2b-256 checksum How to use checksums |
6c9095224834abe0d46429e9566eaccff89e517f5c0b52d013c605e738320f44
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-manylinux2014_x86_64.whl
| Download URL | neonize-0.7.0-py310-none-manylinux2014_x86_64.whl |
|---|---|
| Size | 7.2 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3.10 |
|
SHA-256 checksum How to use checksums |
b64edf24d6c9a1694b737de831615ee9d7375bc492474ef0e3d0c87910d10332
|
|
BLAKE2b-256 checksum How to use checksums |
29a5302e4c52159c295a4203a58580cbb35d82a23b224da90caeaecdf02564c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-manylinux2014_s390x.whl
| Download URL | neonize-0.7.0-py310-none-manylinux2014_s390x.whl |
|---|---|
| Size | 7.2 MB |
| Tags | Linux glibc 2.17+ IBM System/390x Python 3.10 |
|
SHA-256 checksum How to use checksums |
35c29474fa171697b8396fa941ec933b5d1c50226d786ff66870594bd8d13191
|
|
BLAKE2b-256 checksum How to use checksums |
d2865081129f1b9f40ef966b677352744e2e1f7dbb31f461007e36af70a166f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-manylinux2014_i686.whl
| Download URL | neonize-0.7.0-py310-none-manylinux2014_i686.whl |
|---|---|
| Size | 9.7 MB |
| Tags | Linux glibc 2.17+ x86-32 Python 3.10 |
|
SHA-256 checksum How to use checksums |
9a2c161762f51845b9dc89dac00151476dc7fecbbb14c60053d3daf46eeeab41
|
|
BLAKE2b-256 checksum How to use checksums |
56344f40f84fff754cc4b08d913da4f0a1d68f5e39014fc30faff907e247f14a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-manylinux2014_aarch64.whl
| Download URL | neonize-0.7.0-py310-none-manylinux2014_aarch64.whl |
|---|---|
| Size | 6.7 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3.10 |
|
SHA-256 checksum How to use checksums |
b71b46a50c08b6d0f71c706ec0717fde24299fc3300ea75bbbd5a3e2e0a6ea16
|
|
BLAKE2b-256 checksum How to use checksums |
7a8f46edab39a94b9233b648ca7bd11bbf21104e652eed20ee896bfa5ee0998f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-macosx_12_0_x86_64.whl
| Download URL | neonize-0.7.0-py310-none-macosx_12_0_x86_64.whl |
|---|---|
| Size | 6.9 MB |
| Tags | Python 3.10 macOS 12.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
effca1626371c0434622359f572d227aceeddc3016fad4e7f90e161f16a050cc
|
|
BLAKE2b-256 checksum How to use checksums |
8873a00d4d02df0488414b4dea0e651198b83ab6c6bc94f539e3650a1501ea0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / neonize-0.7.0-py310-none-macosx_12_0_arm64.whl
| Download URL | neonize-0.7.0-py310-none-macosx_12_0_arm64.whl |
|---|---|
| Size | 6.4 MB |
| Tags | Python 3.10 macOS 12.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b6d6472fa99e77ace139b1f1f4ad35a43b8e304aa3481b29fc837b7c6869fef8
|
|
BLAKE2b-256 checksum How to use checksums |
c5db78ffb182684e34ce3178edef606c61685003f99490358656e899b4809a9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for neonize 0.7.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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.