PG Marketplace Engine
Trovare is a real-time PG accommodation marketplace in Bangalore. It lists 500+ verified PGs across Koramangala, Indiranagar, HSR Layout and Whitefield, with no-broker owner contact. RECNOS built the platform as two applications on one API: a server-rendered public site with programmatically generated locality pages, and an authenticated owner and administrator app.
Real-time PG accommodations discovery engine in Bangalore with AI search indexing, interactive maps, and payment integration.
Last updated: · By The RECNOS Engineering Team
Impact
1000+ active monthly users
Challenge
A PG marketplace competes for searches that are intensely local — "PG in Koramangala", "girls PG near Whitefield" — and there are thousands of such queries, each with too little inventory to justify a hand-written page. The platform also had to serve two very different audiences from one backend: renters browsing anonymously on a phone, and PG owners managing listings, subscriptions and leads behind a login. The hard constraint was publishing locality and intent pages at scale without generating thin, duplicated content that search engines would penalise, and without hand-maintaining a page per neighbourhood.
Approach
We split the product into two apps against one API: a server-rendered public site for renters, and a separate authenticated application for owners and administrators. The public site is where the interesting work sits. Locality and intent pages are generated programmatically from live inventory rather than authored, with publication rules encoded in the codebase: a page only becomes indexable once it clears a configurable minimum-listing threshold, and a filtered variant such as "girls PG in Koramangala" is only published when its result set is a materially distinct subset of the parent locality — otherwise it canonicalises to the parent and is left out of the sitemap entirely. That rule is what lets the site scale to thousands of pages without cannibalising its own rankings. Titles and descriptions use floor-rounded counts so a cached search snippet stays true as inventory changes, while structured data and page body carry the exact figure. Geospatial work runs through a Bangalore bounding box: addresses are geocoded only if they resolve inside it, and nearby-locality suggestions are ranked by haversine distance. On the owner side we built the full account system — one-time-password login, Google sign-in, multi-factor authentication for administrators, password reset, and subscription checkout through Razorpay — behind an HTTP client that transparently refreshes expired tokens and retries the original request once before redirecting to login.
Outcome
Trovare publicly lists 500+ verified PG listings across Bangalore, covering Koramangala, Indiranagar, HSR Layout and Whitefield, with search near IT parks and no-broker direct owner contact. Source: trovare.in (retrieved 15 Oct 2026). trovare.in
Stack
- Public site
- Next.js 16.3 (App Router, Turbopack)
- Owner app
- Vite 7 + React 19 SPA
- Language
- TypeScript 5 (strict)
- Styling
- Plain CSS, no framework
- Payments
- Razorpay subscription checkout
- Hosting
- Self-hosted nginx, API on a separate service
Engineering
Programmatic locality and intent pages with publication rules
Pages are generated from live inventory for four intents — PG, boys, girls and co-living — across each city and locality. A configurable threshold (default three active listings) gates publication, and a filtered intent page is published only when its count is both above the threshold and genuinely smaller than the parent locality's, so a "girls PG" page for a locality that is entirely girls' PGs collapses into the parent instead of competing with it.
Snippet-stable counts
Titles and descriptions round counts down to a stable bucket — exact below ten, then to the nearest ten, then the nearest hundred — so "47 PGs" becomes "40+" and a cached search result stays truthful as listings are added and removed. Structured data and body copy keep the precise number.
Bounding-box geocoding
Address geocoding is constrained to a Bangalore bounding box and rejects city-level partial matches, so an ambiguous address cannot silently place a listing in the wrong part of the city. Results are cached for thirty days. Locality suggestions are ranked by haversine distance from the current listing.
Nine structured-data types across the catalogue
Search results, listing pages, locality pages, blogs and breadcrumbs each emit appropriate schema — including lodging and apartment-complex markup with per-room pricing offers, FAQ markup on locality pages, and aggregate price ranges on collection pages — so both search engines and AI answer engines can read inventory directly.
Sitemaps generated from live inventory
A sitemap index fans out into separate city, property and blog sitemaps, each generated on request from the API and filtered by the same publication rules as the pages themselves, so unlisted or below-threshold pages never enter the index.
Token refresh with transparent retry
The owner application's HTTP client attaches credentials to every request and, on a 401, refreshes the token and replays the original request once before clearing the session and returning the user to login. Error handling normalises server, network and validation failures into a single shape for the UI.
Full owner and administrator account system
One-time-password login for owners and users, Google sign-in with account linking, multi-factor authentication for administrators, password reset and email verification, plus subscription checkout and payment history. The admin surface covers listing approval, owner management, featured placement and payment reporting.
Server-rendered first page with client-side infinite scroll
Search and listing pages server-render their first page of results for fast first paint and crawlable content, then continue loading subsequent pages through an intersection observer as the visitor scrolls, rather than paginating through numbered pages.
Pages
24 routes in the shipped product.
| Route | What it does |
|---|---|
| / | Homepage — featured and finest listings, popular localities and tech parks, blog highlights. |
| /properties | All-properties grid; first page server-rendered, further pages load on scroll. |
| /property/pg/[slug] | Listing detail — rooms and pricing, amenities, food plans, house rules, photos, map, nearby PGs, and generated FAQs. |
| /search | Search with budget, gender and sort filters over server-fetched results. |
| /search/[place] | Search scoped to a named place, resolved from a curated Bangalore place list. |
| /pg-in-[city] | Programmatic city page listing PGs in that city. |
| /pg-in-[city]/[locality] | Programmatic locality page, published once it clears the listing threshold. |
| /boys-pg-in-[city]/[locality] | Gender-filtered locality page, published only when materially distinct from its parent. |
| /girls-pg-in-[city]/[locality] | Gender-filtered locality page, same publication rule. |
| /coliving-pg-in-[city]/[locality] | Co-living locality page, same publication rule. |
| /finestProperties | Curated finest-properties collection. |
| /finest_pgs/[id] | Finest-property detail with image gallery and owner contact. |
| /blogs | Blog index across seven categories. |
| /blogs/[slug] | Blog article page. |
| /dashboard | Owner dashboard — listing status, notifications and overview (authenticated). |
| /create_pg | Multi-step PG listing wizard: details, amenities, photos, pricing, review (authenticated). |
| /pg/[id]/leads | Per-listing lead management (authenticated). |
| /subscription | Subscription plan selection and Razorpay checkout (authenticated). |
| /payments | Owner payment history (authenticated). |
| /admin/approval | Listing approval queue (administrator). |
| /admin/pgs | Listing table with server-side filters (administrator). |
| /admin/owners | Owner management (administrator). |
| /admin/payments | Payment reporting (administrator). |
| /admin/featured | Featured-placement management (administrator). |