Simon Willison Builds an iNaturalist Observation Tracker with His Phone + Claude Code

Simon Willison built an iNaturalist visualization tool on his phone with Claude Code while camping.
Renowned developer Simon Willison built an iNaturalist nature observation visualization tool during a camping trip using only his phone and AI coding assistant Claude Code. The project features a three-layer decoupled architecture: a Python CLI tool for fetching and clustering data, Git Scraping via GitHub Actions for zero-cost automated data updates, and a pure frontend page for visualization. The project demonstrates the viability of AI coding assistants on mobile devices, as well as the importance of precise prompt writing and elegant data pipeline design.
Project Background: Development Inspiration While Camping
Simon Willison — renowned developer and creator of Datasette — recently shared an interesting weekend project: while camping, he built an iNaturalist observation visualization tool entirely using his phone and Claude Code. This project demonstrates the practicality of AI coding assistants on mobile devices and showcases an elegant data pipeline design approach.
Simon Willison is one of the co-creators of the Django web framework. He later created Datasette — an open-source tool that instantly transforms SQLite databases into interactive APIs and data browsing interfaces. He has long been involved in data journalism, open data, and developer tools. In recent years, he has become one of the most active practitioners and evangelists in AI-assisted programming, frequently sharing detailed case studies of real-world development with LLMs on his blog.
Why Build This Tool
iNaturalist is a widely popular nature observation community platform where users can upload photos of plants and animals and receive species identification. The platform is jointly operated by the California Academy of Sciences and the National Geographic Society, with over 150 million observation records, making it one of the world's largest citizen science platforms. Its core functionality uses community collaboration and computer vision models to identify species from user-uploaded photos. Once verified by community experts, identifications can achieve Research Grade status and are widely used in ecological research and biodiversity monitoring. The platform provides an open REST API that allows developers to query observation data by user, location, species, and other dimensions.
Simon has two iNaturalist accounts, and he wanted to merge observations from both accounts and display them grouped by time and location. This need seems simple, but iNaturalist doesn't offer a cross-account aggregated view. So Simon decided to build it himself — and did so on his phone while camping.
Three-Step Architecture: CLI → Git Scraping → Frontend
The project's architecture is elegantly designed across three layers, each worth examining closely.
Step One: Python CLI Tool for Fetching and Clustering Data
Simon first built inaturalist-clumper, a Python command-line tool that fetches observation data from the iNaturalist API and performs "clumping." The default clustering rule groups observations that are within 2 hours of each other in time and within 5 kilometers in geographic distance.
The clustering here is essentially a connected-component clustering method based on spatiotemporal proximity: if two observations are separated by no more than 2 hours in time and no more than 5 kilometers in space, they're considered part of the same "trip." This approach is similar to the DBSCAN density clustering concept in data science, but with simpler, more intuitive rules. Geographic distance calculation typically uses the Haversine formula to compute spherical distance based on the latitude and longitude of two points. These threshold parameters can be adjusted based on actual use cases — for example, cycling observations might need a larger distance threshold, while urban park observations could use a smaller range.
This design is very practical — when you're walking around a location observing nature, these records naturally get grouped into a single "outing" rather than scattered independent records.
Step Two: Zero-Cost Automation with Git Scraping
The second step uses Simon's signature technique — Git Scraping. He created the simonw/inaturalist-clumps repository, using GitHub Actions to periodically run the CLI tool, write clustering results to a clumps.json file, and commit it to the repository.
Git Scraping is a data collection pattern Simon proposed in 2020: leveraging GitHub Actions' scheduled task capability to periodically scrape data and record changes as Git commits. The core idea is using a Git repository as a time-series database. GitHub Actions provides cron-triggered scheduling with a maximum frequency of once every 5 minutes (actual scheduling may have delays). Each execution fetches the latest data from the target source and writes it to a file in the repository — if the data has changed, a new Git commit is created. This means you can precisely track every change in the data through git log and git diff. This pattern has been widely adopted for tracking changes in government public data, monitoring website content updates, recording API response changes, and more. Simon maintains a list of hundreds of Git Scraping projects covering everything from pandemic data to flight information.
This approach has three clear benefits:
- Zero-cost hosting: GitHub provides free storage and CDN
- Complete version history: Every data change has a Git record for easy tracing
- CORS-friendly: GitHub's raw files can be directly fetched by browser-side JavaScript without a backend proxy
The third point deserves elaboration: CORS (Cross-Origin Resource Sharing) is a browser security mechanism that by default blocks webpage JavaScript from making requests to different domains. If your frontend is hosted on domain A and you want to use fetch() to get data from domain B, domain B's server must explicitly allow cross-origin access in its response headers. GitHub's raw.githubusercontent.com domain has a permissive CORS policy by default, allowing frontend code from any origin to directly read file contents from repositories. This characteristic enables developers to store JSON data files in GitHub repositories, and frontend pages can fetch data directly without setting up any backend API server, dramatically reducing infrastructure costs for small projects.
Step Three: Using Claude Code to Generate a Pure Frontend Display Page
The final step was building the frontend page. Simon sent Claude Code a precise prompt, requesting it to:
- Fetch JSON data from a GitHub raw URL
- Display all observations using iNaturalist's thumbnail URLs
- Support
loading=lazyfor performance optimization - Show a larger image in a modal when thumbnails are clicked
- Display common names of species
loading=lazy is a native HTML lazy-loading attribute for images, first implemented in Chrome in 2019 and now supported by all major browsers. When an image has this attribute set, the browser only initiates a network request to load the image resource when it's about to enter the viewport, rather than requesting all images at once during page load. For pages like iNaturalist observations that might contain hundreds of thumbnails, lazy loading can significantly reduce initial page load time and bandwidth consumption, improving user experience. Previously, developers typically needed to use the Intersection Observer API or third-party JavaScript libraries to achieve similar functionality.
The prompt was highly specific, including URL patterns, interaction logic, and data field requirements. The resulting tool is hosted on Simon's tools site.
Key Takeaways from This Project
Mobile AI Programming Is Already Viable
The entire project was completed on a phone, demonstrating that Claude Code is powerful enough to accomplish meaningful development work on mobile devices. Claude Code is a command-line AI programming tool from Anthropic that supports writing, modifying, and debugging code through natural language conversation in a terminal environment. Using Claude Code on a phone typically requires connecting to a remote server via an SSH client (such as Termius, Blink Shell, etc.) or using mobile apps that support terminal emulation. While phone screens and keyboards make traditional coding nearly impossible to do efficiently, AI programming assistants change the equation — developers only need to describe requirements in natural language while the AI generates complete code, dramatically reducing input volume and making mobile development feasible.
For developers, this means you can start building whenever inspiration strikes, without waiting to get back to a computer.
Well-Written Prompts Produce Code That Works on the First Try
Simon's prompt to Claude Code is exemplary: it's not a vague requirements description but includes specific URL formats, technical details (lazy loading, modal popups), and data processing logic.
This reflects several key principles in Prompt Engineering: First, Specificity — he didn't say "make a display page" but explicitly specified the data source URL, image URL concatenation patterns, specific HTML attributes, and interaction behaviors. Second, Context — he described the data structure and field meanings so the AI understood the data model. Third, Constraints — he clearly defined the tech stack (pure frontend, no framework dependencies) and performance requirements. This approach mirrors what makes a "good requirements document" in software engineering — the more precise the input, the more directly usable the output, reducing back-and-forth iterations.
This kind of precise prompting dramatically increases the probability of generating working code on the first try and is a key technique for efficiently using AI programming tools.
The Decoupled Data Pipeline Design Is Worth Emulating
Completely decoupling data fetching (CLI), data storage (Git Scraping), and data display (frontend) is an extremely practical architectural pattern. Each layer can iterate independently, the frontend is purely static, requires no backend server, and has virtually zero maintenance cost.
This decoupled design follows the Unix philosophy of "do one thing well": the CLI tool only handles data fetching and clustering logic, GitHub Actions only handles scheduled execution and versioned storage, and the frontend only handles data visualization. If any layer has issues or needs upgrading, it won't affect the others. For example, if iNaturalist's API changes, only the CLI tool needs modification; if you want a different frontend presentation, the data pipeline doesn't need any changes. This pattern is suitable for many personal projects and small-scale data display scenarios, especially projects that don't update frequently but require long-term maintenance.
Conclusion: Phone + AI, Turn Ideas into Tools Anytime, Anywhere
While this project is modest in scale, it demonstrates the power of modern developer toolchains: AI coding assistants like Claude Code lower the barrier to writing code, Git Scraping provides a free data pipeline, and GitHub Pages provides free hosting. During a gap in a weekend camping trip, with just a phone, you can turn an idea into a working tool.
This is perhaps what's most exciting about AI-assisted programming — it doesn't replace developers, but enables them to quickly bring ideas to life at any time, in any place. When the barrier to coding drops from "needing a computer, an IDE, and several hours of focused time" to "a phone and a few natural language descriptions," the release of creativity will no longer be constrained by physical conditions. Simon's camping project may be just a small glimpse of this new development paradigm.
Related articles
Product ReviewsThe Programmer's Desk Setup Guide: Building a Workspace That Feels Like Home
Discover how programmers build productive, comfortable workspaces. From multi-monitor setups to ergonomic design, explore the desk philosophy that drives focus and flow.
Product ReviewsQoder vs Cursor Real-World Comparison: Which $20/Month AI IDE Is Better?
Hands-on comparison of Qoder vs Cursor AI IDEs: Agent autonomy, human interaction count, and architecture decisions. Qoder needed only 2 interactions vs Cursor's 8.
Product ReviewsCursor Cloud Agent Demo: Eliminating Bottlenecks Across the Entire Software Development Lifecycle
Deep analysis of Cursor's Cloud Agent demo showing how cloud VMs, automated test artifacts, and a full-chain control plane systematically eliminate human bottlenecks across the software development lifecycle.