---
title: "Hargapedia on the web"
description: "After two and a half years as a mobile app, Hargapedia now has a website where people can browse products and compare online prices, with its own serverless API behind it."
url: "https://rayson.me/writing/hargapedia-web/"
category: "Engineering"
author: "Janarayson"
published: 2020-07-28
---

Hargapedia has been available on iOS and Android since January 2018, but until recently, the website didn't do much beyond telling people about the app.

We launched [hargapedia.app](https://hargapedia.app) last year with information about the features, screenshots, download links and a blog. There was also a page for each product, mainly so that someone opening a shared product link on their laptop would have somewhere to land.

You couldn't actually browse prices on it.

That changed this month with the launch of [www.hargapedia.com.my](http://www.hargapedia.com.my). We've brought the products to the web, so people can search for them, browse categories and compare prices without having to install the app.

There are a couple of differences from the mobile version, though.

## Bringing the products to the browser

I designed the website in June, covering both desktop and mobile layouts.

The home page follows much the same structure as the app. There are banners and a carousel at the top, followed by product categories, specials, rows of products with their prices, vouchers and the latest HargaNews articles.

From there, you can browse categories, search for products or retailers, and open individual product pages. Category pages have breadcrumbs and pagination, while product pages show the category tree along the side and the available prices underneath.

I also made a mobile layout, so the site works on a phone without having to squeeze the desktop interface into a smaller screen. On iPhone, Safari can also offer to open the page in the Hargapedia app.

It's largely the same set of products, but we made one deliberate distinction between what people see on the website and what they see in the app.

## Keeping in-store prices in the app

The Hargapedia app shows both online and physical store prices. You can compare what something costs at a supermarket with what sellers are charging online.

For the website, we decided to show online prices only.

Online offers still have their prices and Buy Now buttons, which take you to the retailer. Physical store offers appear in the list too, but their prices are masked, with a prompt to download Hargapedia to see them.

<Figure
  src={productPage}
  alt="The product page design for Anmum Essential Step 4 Honey 1.1kg: breadcrumbs reading Home, For Baby, Baby Milk Powder, 3 years & above, then the product; the category tree down the left; the product card with a Cheapest Online tag on the Fernleaf Lazada price with a Buy Now button and share icons; and a list of prices below, where Manjaku and Fernleaf on Shopee and Lazada show a price and a Buy Now button, and the Billion row shows RMXX.XX with a Show Me button and the words Download Hargapedia for price"
  caption="The Anmum product page from the June design. Online prices are visible, while in-store prices are reserved for the app."
  wide
/>

We didn't just hide those prices with CSS or replace them with asterisks in the browser.

The website has its own API, and that's where the restriction happens. It removes the actual in-store prices before returning the data, so those amounts never reach the browser.

That was one reason for putting a separate API between the website and Hargapedia's existing backend.

## A separate API for the website

The new site is a React single-page application. Once it loads, the browser requests the data it needs through an API.

Hargapedia already has a GraphQL API that serves the mobile app, but the website doesn't call it directly.

A colleague built a separate API for the website over June and July, using AWS Lambda functions behind API Gateway. Each function handles a particular part of the site, such as fetching a product, retrieving a category and its products, searching, or loading the home page with its banners, carousel, specials, vouchers and popups.

There are also functions for things like breadcrumbs.

Underneath, these functions still call the same GraphQL API the mobile app uses. The difference is that they request only the fields needed by the website, remove the in-store prices and return plain JSON.

That way, the website gets a smaller, purpose-built response without exposing everything available through the app's API.

The Lambda functions share middleware for input validation, security headers and CORS. We also have scheduled requests to keep the functions warm, so someone visiting after a quiet period is less likely to have to wait for a cold start.

Deployment runs through a GitLab pipeline.

There's another difference between the website and the app that happens on the backend rather than in React.

## Watermarking the product images

Product photos on the website carry a Hargapedia watermark. The same photos in the mobile app don't.

We didn't want to create and store a second copy of the entire image library just to add watermarks.

Instead, we added a flag to the product image field in the main API. The website's API sets that flag when requesting an image, while the mobile app leaves it off.

With the flag enabled, the API returns a signed URL for an image proxy rather than the original image address.

We're using [imgproxy](https://imgproxy.net) for this. It retrieves the original image from storage, applies the Hargapedia watermark in the centre and returns the result.

Both image sizes used by the website, thumbnails and larger product photos, go through the same process.

The URL contains the transformation instructions and is signed using a key and salt. That prevents someone from supplying an arbitrary image URL and using our proxy to process it.

We initially had the watermark at 50% opacity, but changed it to full opacity within the first week.

So while the website and mobile app share the same products and backend data, we can control what each one receives. The app continues to show physical store prices and unwatermarked images, while the website serves online prices and watermarked photos.

It's the first time people can properly browse Hargapedia's products from a browser, rather than using the website mainly as a route into the app.

<Note label="Update, May 2021">

We've since replaced the React single-page application with a server-rendered website built on Next.js. I wrote about the rebuild in [Moving the web version to Next.js for SEO](/writing/hargapedia-web-seo/).

</Note>
