gdpy¶
A modern, type-safe Python library for interacting with the Geometry Dash private API.
Why gdpy?¶
Instead of manually crafting HTTP requests and parsing custom response formats, gdpy gives you:
- Clean Pythonic API —
client.get_user(account_id=71)vs constructing URLs and parsingkey:valuestrings - Full type safety — IDE autocomplete and catch errors before runtime with Pydantic models
- Built-in crypto — GJP2 encoding, XOR ciphers, and checksums handled automatically
Raw requests require understanding GD's custom formats and encryption. gdpy abstracts that away.
Features¶
Sync & Async - Both synchronous (
Client) and asynchronous (AsyncClient) interfacesModern HTTP - Built with
httpxfor both sync and async operationsType-safe - Full type hints with runtime validation via Pydantic
Well-structured - Clean, pythonic API design
Built-in crypto - XOR cipher, GJP2 encoding, base64 utilities, and checksums
Comprehensive errors - Full exception hierarchy for different error scenarios
Well-documented - Docstrings and examples for all public APIs
API Coverage¶
| Category | Implemented | Total | Coverage |
|---|---|---|---|
| Accounts | 3 | 5 | 60% |
| Users | 4 | 4 | 100% |
| Levels | 10 | 11 | 91% |
| Comments | 7 | 7 | 100% |
| Songs | 3 | 6 | 50% |
| Social | 12 | 12 | 100% |
| Messages | 4 | 4 | 100% |
| Rewards | 2 | 3 | 67% |
| Lists | 1 | 3 | 33% |
| Misc | 2 | 2 | 100% |
| Total | 48 | 57 | 84% |
See API Coverage for detailed endpoint status.
Installation¶
Quick Start¶
from gdpy import Client
from gdpy.models import User, Level
# Use without context manager (remember to close!)
client = Client()
user: User = client.get_user(account_id=71) # RobTop
print(f"Username: {user.username}")
print(f"Stars: {user.stars}")
client.close()
# Or use as context manager (auto-closes)
with Client() as client:
levels: list[Level] = client.search_levels(query="ReTraY", limit=5)
for level in levels:
print(f"{level.name} - {level.downloads} downloads")
import asyncio
from gdpy import AsyncClient
from gdpy.models import User, Level
async def main():
# Use without context manager (remember to close!)
client = AsyncClient()
user: User = await client.get_user(account_id=71)
print(f"Username: {user.username}")
print(f"Stars: {user.stars}")
await client.close()
# Or use as context manager (auto-closes)
async with AsyncClient() as client:
levels: list[Level] = await client.search_levels(query="ReTraY", limit=5)
for level in levels:
print(f"{level.name}")
asyncio.run(main())
Troubleshooting¶
Why am I getting 429 errors?
The Geometry Dash API has aggressive rate limiting. If you make requests too quickly, you'll get -1 responses (handled as InvalidRequestError). Add delays between requests:
How do I handle rate limits?
Catch InvalidRequestError and retry with exponential backoff:
Why does level data look incomplete?
Some fields like level_string (the actual level data) are only included when fetching a single level via get_level(), not in search results. If you need full data:
Requirements¶
- Python 3.10+
httpx- HTTP client (supports both sync and async)pydantic- Data validation
License¶
MIT
Credits: This library is based on the Geometry Dash API documentation.