npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

edgymeow

v0.0.18

Published

EdgyMeow - WhatsApp WebSocket RPC Server with JSON-RPC 2.0 protocol

Readme

EdgyMeow

npm version PyPI version License: MIT

WebSocket JSON-RPC 2.0 API for QR Based WhatsApp Web.

Installation

npm install edgymeow

Pre-built binaries are automatically downloaded for your platform (Linux, macOS, Windows).

Quick Start

# Start the API server
npx edgymeow start

# Check status
npx edgymeow status

# Stop the server
npx edgymeow stop

Architecture

┌─────────────────────────────────────────────────────────┐
│                     Your Application                     │
│              (Node.js, Python, Go, etc.)                │
└─────────────────────────┬───────────────────────────────┘
                          │
                          │ WebSocket (JSON-RPC 2.0)
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│              EdgyMeow Server (:9400)                 │
│  ┌─────────────────────────────────────────────────┐    │
│  │  • JSON-RPC 2.0 Handler                         │    │
│  │  • Rate Limiter (anti-ban protection)           │    │
│  │  • Event Emitter (real-time notifications)      │    │
│  │  • Message History Store (SQLite)               │    │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────┬───────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                 whatsmeow (Go Library)                   │
│                WhatsApp Web Protocol                     │
└─────────────────────────┬───────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   WhatsApp Servers                       │
└─────────────────────────────────────────────────────────┘

Data Storage:
┌─────────────────────────────────────────────────────────┐
│  data/                                                   │
│  ├── whatsapp.db    (SQLite: session, contacts, history)│
│  └── groups.json    (Group cache)                       │
└─────────────────────────────────────────────────────────┘

CLI Commands

npx edgymeow start           # Start API server (background)
npx edgymeow stop            # Stop API server
npx edgymeow restart         # Restart API server
npx edgymeow status          # Check if running
npx edgymeow api --foreground  # Run in foreground (for Docker)
npx edgymeow build           # Build from source (requires Go)
npx edgymeow web             # Start standalone web dashboard (no Python needed)
npx edgymeow dev             # Start API + web dashboard together

# Custom port
npx edgymeow start --port 8080

Web Dashboard

A standalone static web client that connects directly to the Go WebSocket backend -- no Python/Flask required:

# Start API server first
npx edgymeow start

# Then start the web dashboard
npx edgymeow web --port 3001 --ws-port 9400

# Or start both together
npx edgymeow dev

Open http://localhost:3001 for the full dashboard with pages for messaging, groups, contacts, and settings.

The web client is in web/client/ and can also be served by any static file server. Set window.WS_PORT to point to the Go backend port.

Docker

FROM node:20-alpine
WORKDIR /app
RUN npm init -y && npm install edgymeow
RUN mkdir -p /app/data
ENV PORT=9400
EXPOSE 9400
CMD ["npx", "edgymeow", "api", "--foreground"]

API Reference

Connect via WebSocket to ws://localhost:9400/ws/rpc and send JSON-RPC 2.0 requests.

Connection & Status

| Method | Description | |--------|-------------| | status | Get connection status (connected, has_session, running, pairing, device_id) | | start | Start WhatsApp service | | stop | Stop WhatsApp service | | restart | Full reset: logout, clear all caches, cleanup, start fresh | | reset | Reset session (logout and delete credentials) | | diagnostics | Get detailed diagnostics information | | qr | Get QR code for pairing (code, image_data as base64 PNG) |

Messaging

| Method | Parameters | Description | |--------|------------|-------------| | send | phone or group_id, type, message/media_data/location/contact | Send message | | media | message_id | Download media from received message (returns base64) | | typing | jid, state (composing/paused) | Send typing indicator | | presence | status (available/unavailable) | Set online/offline status | | mark_read | message_ids[], chat_jid, sender_jid | Mark messages as read |

Message Types: text, image, video, audio, document, sticker, location, contact

Contacts

| Method | Parameters | Description | |--------|------------|-------------| | contacts | query (optional) | List all contacts with saved names | | contact_info | phone | Get full contact info (name, business status, profile pic) | | contact_check | phones[] | Check if numbers are on WhatsApp | | contact_profile_pic | jid, preview | Get profile picture (returns URL and base64) |

Groups

| Method | Parameters | Description | |--------|------------|-------------| | groups | - | List all groups | | group_info | group_id | Get group details (name, topic, participants, admins) | | group_update | group_id, name, topic | Update group name/description | | group_participants_add | group_id, participants[] | Add members to group | | group_participants_remove | group_id, participants[] | Remove members from group | | group_invite_link | group_id | Get invite link | | group_revoke_invite | group_id | Revoke and regenerate invite link |

Channels (Newsletters)

| Method | Parameters | Description | |--------|------------|-------------| | newsletters | refresh | List subscribed channels (cached 24h) | | newsletter_info | jid or invite, refresh | Get channel details | | newsletter_create | name, description, picture | Create a new channel | | newsletter_follow | jid | Subscribe to a channel | | newsletter_unfollow | jid | Unsubscribe from a channel | | newsletter_mute | jid, mute | Mute/unmute a channel | | newsletter_messages | jid, count, offset, before, since, until, media_type, search, refresh | Get channel messages (lazy cached, filterable) | | newsletter_send | group_id, type, message/media_data | Send to channel (admin only) | | newsletter_mark_viewed | jid, server_ids[] | Mark messages as viewed | | newsletter_react | jid, server_id, reaction | React to a channel message | | newsletter_live_updates | jid | Subscribe to live view/reaction updates | | newsletter_stats | jid or invite, count | Get channel statistics (views, reactions) |

Chat History

| Method | Parameters | Description | |--------|------------|-------------| | chat_history | chat_id/phone/group_id, limit, offset, sender_phone, text_only | Get stored message history |

Rate Limiting (Anti-Ban Protection)

| Method | Parameters | Description | |--------|------------|-------------| | rate_limit_get | - | Get config and statistics | | rate_limit_set | enabled, min_delay_ms, max_delay_ms, max_messages_per_hour, etc. | Update configuration | | rate_limit_stats | - | Get current statistics only | | rate_limit_unpause | - | Resume after automatic pause |

Events

The server pushes events as JSON-RPC notifications (no id field):

{"jsonrpc": "2.0", "method": "event.message_received", "params": {...}}

| Event | Description | |-------|-------------| | event.status | Initial status on WebSocket connection | | event.connected | WhatsApp connected successfully | | event.disconnected | WhatsApp disconnected | | event.connection_failure | Connection failed | | event.logged_out | User logged out | | event.temporary_ban | Temporary ban received | | event.qr_code | New QR code available (code, image_data) | | event.message_sent | Message sent successfully | | event.message_received | New message received (includes forwarding info) | | event.history_sync_complete | History sync completed after first login | | event.newsletter_join | Joined a channel | | event.newsletter_leave | Left a channel | | event.newsletter_mute_change | Channel mute state changed | | event.newsletter_live_update | Live view/reaction count updates |

Message Received Event Fields

{
  "message_id": "ABC123",
  "sender": "[email protected]",
  "chat_id": "[email protected]",
  "timestamp": "2025-01-15T10:30:00Z",
  "is_from_me": false,
  "is_group": false,
  "is_forwarded": false,
  "forwarding_score": 0,
  "message_type": "text",
  "text": "Hello world!",
  "group_info": { "group_jid": "...", "sender_jid": "...", "sender_name": "..." }
}

Examples

Send Text Message

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "send",
  "params": {
    "phone": "1234567890",
    "type": "text",
    "message": "Hello from API!"
  }
}

Send Image with Caption

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "send",
  "params": {
    "phone": "1234567890",
    "type": "image",
    "media_data": {
      "data": "base64_encoded_image_data",
      "mime_type": "image/jpeg",
      "caption": "Check this out!"
    }
  }
}

Send to Group

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "send",
  "params": {
    "group_id": "[email protected]",
    "type": "text",
    "message": "Hello group!"
  }
}

Send Location

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "send",
  "params": {
    "phone": "1234567890",
    "type": "location",
    "location": {
      "latitude": 37.7749,
      "longitude": -122.4194,
      "name": "San Francisco",
      "address": "California, USA"
    }
  }
}

Reply to Message

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "send",
  "params": {
    "phone": "1234567890",
    "type": "text",
    "message": "This is a reply!",
    "reply": {
      "message_id": "ABC123",
      "sender": "[email protected]",
      "content": "Original message text"
    }
  }
}

Get Chat History

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "chat_history",
  "params": {
    "phone": "1234567890",
    "limit": 50,
    "text_only": true
  }
}

Configure Rate Limiting

{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "rate_limit_set",
  "params": {
    "enabled": true,
    "min_delay_ms": 5000,
    "max_messages_per_hour": 30,
    "simulate_typing": true,
    "randomize_delays": true
  }
}

List Channels

{
  "jsonrpc": "2.0",
  "id": 8,
  "method": "newsletters",
  "params": {}
}

Get Channel Info by Invite Link

{
  "jsonrpc": "2.0",
  "id": 9,
  "method": "newsletter_info",
  "params": {
    "invite": "https://whatsapp.com/channel/0029Va..."
  }
}

Send Message to Channel

{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "newsletter_send",
  "params": {
    "group_id": "123456789@newsletter",
    "type": "text",
    "message": "Hello subscribers!"
  }
}

Get Channel Statistics

{
  "jsonrpc": "2.0",
  "id": 11,
  "method": "newsletter_stats",
  "params": {
    "jid": "123456789@newsletter",
    "count": 20
  }
}

Error Codes

| Code | Description | |------|-------------| | -32700 | Parse error - Invalid JSON | | -32600 | Invalid Request - Not a valid JSON-RPC 2.0 request | | -32601 | Method not found | | -32602 | Invalid params | | -32000 | Server error (WhatsApp operation failed) | | -32001 | No QR available |

Environment Variables

| Variable | Default | Description | |----------|---------|-------------| | PORT | 9400 | WebSocket API port | | EDGYMEOW_PORT | 9400 | WebSocket API port (alternative to PORT) | | EDGYMEOW_SKIP_BINARY_DOWNLOAD | - | Set to 1 to skip binary download | | EDGYMEOW_PREFER_SOURCE | - | Set to 1 to build from source if Go is installed |

Data Files

| Path | Description | |------|-------------| | data/whatsapp.db | SQLite database (session, contacts, message history) | | data/groups.json | Group cache (auto-generated on connection) |

Building from Source

Requires Go 1.21+:

npm run build

Full Schema

See schema.json for complete OpenRPC specification.

Python Client

An async Python client is available on PyPI:

pip install edgymeow
import asyncio
from edgymeow import WhatsAppRPCClient

async def main():
    client = WhatsAppRPCClient("ws://localhost:9400/ws/rpc")
    await client.connect()

    status = await client.status()
    print(status)

    await client.send(phone="1234567890", type="text", message="Hello!")
    await client.close()

asyncio.run(main())

See src/python/README.md for full Python client documentation.

Android Integration

Cross-compile the server for Android and embed it in your app:

# Build for all platforms including Android
npm run build-cross

# Or manually:
# arm64 real device
CGO_ENABLED=0 GOOS=android GOARCH=arm64 go build -ldflags="-s -w" -o libedgymeow.so ./src/go/cmd/server

# x86_64 emulator (use GOOS=linux, not android)
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o libedgymeow-x86_64.so ./src/go/cmd/server

Place binaries in your Android project:

app/android/app/src/main/jniLibs/
    arm64-v8a/libedgymeow.so
    x86_64/libedgymeow-x86_64.so

Required Gradle config (build.gradle.kts):

android {
    packaging { jniLibs { useLegacyPackaging = true } }
    defaultConfig { ndk { abiFilters += listOf("x86_64", "arm64-v8a") } }
}

Launch from Kotlin:

val binary = File(applicationInfo.nativeLibraryDir, "libedgymeow.so")
val pb = ProcessBuilder(binary.absolutePath)
pb.environment()["SSL_CERT_DIR"] = "/system/etc/security/cacerts"
pb.environment()["EDGYMEOW_ANDROID"] = "1"  // enables Android DNS resolver
pb.start()

Then connect via WebSocket at ws://127.0.0.1:9400/ws/rpc.

CrossMeow (Flutter Example App)

A complete Flutter Android app is in examples/android/. It bundles the Go binary and the static web client into a single APK:

cd examples/android

# Build Go binary for emulator
cd ../../ && npm run build-cross  # or manually cross-compile

# Copy binary to jniLibs
cp bin/libedgymeow-android-arm64.so examples/android/android/app/src/main/jniLibs/arm64-v8a/libedgymeow.so

# Build APK
cd examples/android && flutter build apk --debug

The app uses a Dart HTTP server to serve the web client from Flutter assets, with a WebView loading the dashboard. See examples/android/ for the full source.

Requirements

  • Node.js 18+
  • Pre-built binaries available for:
    • Linux (amd64, arm64)
    • macOS (amd64, arm64)
    • Windows (amd64)
    • Android (arm64, x86_64)

License

MIT