Home

Published

- 6 min read

Kopimap: Building a Specialized Cafe Finder for Jakarta

img of Kopimap: Building a Specialized Cafe Finder for Jakarta

Introduction

Kopimap is a web application designed to help coffee lovers find the perfect cafe in DKI Jakarta. Born out of a personal need to overcome decision paralysis when searching for a place to enjoy coffee and work, Kopimap offers unique features not found in general map services like Google Maps.

What sets Kopimap apart are its specialized filters. Users can search for cafes based on criteria such as:

- Presence of a musholla

- Parking availability (including valet options)

- Coffee quality

- Work-friendly amenities (reliable WiFi and power outlets)

These filters aim to simplify the decision-making process for cafe-goers in Jakarta, offering a tailored experience for coffee enthusiasts and remote workers alike.

Tech Stack

Frontend:

- Vite

- Vike (Vite frontend framework supporting SSR/SSG and page-based routing)

- React with TypeScript

- Styling: Tailwind CSS

Map:

- Protomaps (open-source system for interactive web maps)

- React Maplibre-GL (rendering vector tiles)

- Backend: Supabase (postgreSQL, object storage, authentication)

- Search: Meilisearch (search engine)

- Server: Nitro JS (server)

Hosting:

- Cloudflare Pages

- Cloudflare R2 for object storage

Building Kopimap: Key Components and Challenges

1. Choosing the Right Map Technology: Protomaps

The foundation of Kopimap is built on Protomaps, an open-source system for interactive web maps. I chose Protomaps over more well-known options like Google Maps API or Mapbox for its cost-efficiency and customizability.

Key Features and Benefits

- Efficient tile hosting: Protomaps can host map files (with .pmtiles extension) in object storage. This enables HTTP range requests to fetch only the specific tiles relevant to the user’s current view, significantly optimizing performance and reducing costs. Not only that, but we can set the necessary bouding box that comprise the map files. In my case, I fetched the map files only within the DKI Jakarta area. This total size hosted is only 70MB!

- Cost-effective: Compared to Google Maps API or Mapbox, Protomaps is substantially more cost-efficient. You only need to pay for hosting your static pmtiles asset and any associated egress and ingress fees. Using Cloudflare’s R2 object storage further reduced costs as it doesn’t charge for egress/ingress.

- Comprehensive documentation: Protomaps’ documentation is clear and comprehensive, addressing every question I encountered during the implementation process.

Implementation Insights

- Used maplibre for displaying vector tile rendering of Protomaps assets

- Gained experience with GeoJSON and PostGIS for querying cafes within the viewport

- The implementation process introduced me to the broader map visualization ecosystem, expanding my knowledge beyond just Protomaps

2. Implementing Robust Search: Meilisearch

To provide a rich search experience, Kopimap needed to support:

- Geo-location based search (by center coordinate and radius, or bounding box)

- Text-based queries

- Filter-based search

- Combinations of the above

Why Meilisearch?

While PostgreSQL with PostGIS was initially considered, I ultimately chose Meilisearch for several key reasons:

- Search Relevance: Meilisearch offers superior relevance ranking out-of-the-box, including typo tolerance and prefix matching.

- Ease of Implementation: Meilisearch’s simple RESTful API allowed for quicker development compared to writing complex SQL queries.

- Faceted Search: Built-in support for faceted search simplified the implementation of Kopimap’s filter system.

- Geo-search Integration: Meilisearch’s geo-search feature integrated seamlessly with other search criteria.

These advantages made Meilisearch the ideal choice for Kopimap’s requirements, balancing search quality, performance, and development efficiency.

Geo-search Implementation

- Initially opted for radius-based search over bounding box for simplicity

- Recognized that bounding box search might be more aligned with the rectangular map view

- Future consideration: Implementing bounding box search for better alignment with map view and potentially more accurate results

NitroJS

With meilisearch in mind, I’d still need to provide a REST API layer to authorize any creates, updates, and deletes in the search engine. That is why I introduced a minimal web server toolkit called NitroJS in the mix, where I would authorize any creates, updates, and deletes by the JWT token of users, provided by supabase auth.

3. Optimizing for Google: SEO Techniques

One of the biggest challenges in building Kopimap was optimizing it for search engines, given its heavily client-side rendered nature with numerous interactive elements.

SEO Strategy:

- Provide individual links for each cafe to allow search engines to index them separately

- Generate dynamic meta tags for each cafe on the server side to ensure Google could crawl them correctly

Implementation Journey

1. Initially developed using React TypeScript template (no SSR support)

2. Recognized the need for server-side rendering (SSR) to ensure correct metadata for each cafe

3. Explored SSR frameworks like Next.js with its support for React Server Components (RSC)

4. Discovered Vike, a Vite meta-framework supporting SSR/SSG and page-based routing

5. Integrated Hono.js as the server to host server-rendered components

- Faced challenges with Cloudflare function bundle size exceeding the free tier limit of 1MB

6. Switched to Static Site Generation (SSG) approach

- Prerender pages for all cafes (under 7000) at build time

- Generate components with necessary meta title, description, JSON-LD script tags, etc.

- Reduced app size by removing server-side components

- Ensured prerendered pages are served with all necessary tags when crawlers load

This journey showcased the complexities of optimizing a modern web application for SEO and the trade-offs between different rendering strategies.

4. Web Scraping for Data Collection

To populate Kopimap with comprehensive cafe data, I turned to web scraping, specifically using a paid Google Maps scraper (omkarcloud/google-maps-scraper).

Scraping Strategy Evolution:

1. Initial broad query for “Cafes in DKI Jakarta” faced Google Maps’ cap of around 120 results

2. Refined to separate queries for each regency (kabupaten) in DKI Jakarta

3. Further refined to queries for each subdistrict (kecamatan) for more comprehensive coverage

4. Continuous refinement based on user feedback about missing cafes

Rationale:

- Web scraping captured a wider range of data fields compared to Google Places API

- Ability to collect total user ratings, which the API doesn’t provide

- Flexibility to adapt the scraping strategy for more comprehensive results

This approach allowed Kopimap to build a rich, detailed database of cafes across Jakarta, providing users with a more comprehensive selection than what might be immediately available through standard APIs.

Challenges and Future Improvements

1. Geocoding Search: Implement true geocoding capabilities for address-based searches. Currently, users can only search by address if it matches a cafe’s listed address.

2. Mobile Accessibility: While Kopimap has a mobile-friendly website, a native app would provide a better user experience. Exploring Capacitor.js as a potential solution for creating a cross-platform mobile app from the existing web application.

3. Marketing: Developing effective strategies to promote Kopimap and increase its user base remains a significant challenge, especially as a developer venturing into marketing.

4. Localization: Implement proper localization features, which were admittedly an afterthought in the initial development.

5. Monetization: Explore various strategies for sustainable growth and revenue generation.

6. Process Automation: Improve efficiency and scalability of operations, particularly in data collection and updates.

Conclusion

Kopimap addresses a specific need for coffee lovers and remote workers in Jakarta by focusing exclusively on cafes and providing specialized filters. While Google Maps is an excellent general-purpose tool, Kopimap offers a streamlined, clutter-free experience for finding the perfect spot to enjoy a cup of coffee or get some work done.

This project has been a journey of continuous learning and problem-solving. From mastering new mapping technologies to tackling SEO challenges and refining data collection methods, each step has contributed significantly to my growth as a developer. The process of building Kopimap has not only resulted in a useful application but also provided invaluable insights into the complexities of modern web development, from frontend optimizations to backend efficiencies.

Resources

For those interested in learning more about the key technologies used in Kopimap:

Related Posts

There are no related posts yet. 😢