[ Building · · 7 min read ]
What I Learned Shipping a Python SDK to PyPI
Building Inscrape taught me that the hard part of an SDK is not the code — it is the developer experience. Here is what I got right and what I would change.
When I decided to build Inscrape — an AI-powered web scraping SDK — I assumed the hardest part would be the extraction engine. Getting structured data out of arbitrary web pages using AI is genuinely difficult. But after shipping v0.1.0 to PyPI, I can tell you the extraction logic was maybe 30% of the work. The other 70% was developer experience.
The first lesson: your SDK is only as good as its simplest use case. If a developer cannot get value in under 60 seconds, they will close the tab and write their own scraper. Inscrape's design goal was three lines of code from install to structured output: initialise the client, call scrape, get JSON back. Every API decision was filtered through that constraint. Can the developer do this without reading the docs? If no, redesign it.
The second lesson: typed error handling is not optional. When I first shipped Inscrape, errors came back as generic exceptions with string messages. Developers had to parse error messages to figure out if they had hit a rate limit, had an auth problem or had exhausted their quota. The fix was obvious in retrospect: distinct exception classes for each failure mode — AuthError, RateLimitError, QuotaExhaustedError — so developers can catch exactly what they need. This one change eliminated 80% of the support questions.
The third lesson: async support must be first-class, not bolted on. I originally built Inscrape as a synchronous SDK and added AsyncInscrape later. The problem is that most production data pipelines are async — and wrapping sync code in async wrappers is a recipe for subtle bugs and performance issues. If I were starting over, I would build async-first and derive the sync interface from it.
Publishing to PyPI itself was surprisingly straightforward. Hatchling as the build system, a clean pyproject.toml, pytest for testing, Ruff for linting. The actual publishing is one command. The lesson is that the tooling for publishing Python packages is mature and well-documented — the hard part is building something worth publishing.
Written by Ganesh Khetawat, founder of Aletheia AI
Need this built? See our MVP development work, or tell us what you’re building.
Read nextThe Rise of AI-Powered Ransomware: What Defenders Need to Know→