Back to projects

Web Scraping + Full Stack

Deal Round

A Copenhagen deal aggregator that scrapes 8+ Danish deal sites, filters out junk, deduplicates listings, and presents them in a polished web app with search, map view, geolocation, and Telegram alerts.

Dealround — Copenhagen deal finder with mobile list view
Mobile-first deal discovery with live data from 8+ Danish deal sites
Dealround desktop view with grid cards, filters, and stats
Desktop grid view — 312 deals with category filters, price ranges, sort options, and favorites

Status

Live

Deal Sources

8+ sites

Frontend

Vercel

Scraper

Hetzner VPS

Why I built this

Living in Copenhagen, I kept missing good deals on activities, restaurants, and entertainment because they were scattered across different Danish deal sites. I wanted one place to see everything — filtered, deduplicated, and mapped — with Telegram alerts so I never miss a deal that matches my interests.

How it works

1

Scrape deals from 8+ Danish sites

A Python scraper runs twice daily (08:00 + 18:00 CET) on a Hetzner VPS, pulling deals from Meyou.dk, Sweetdeal, All2day, Bownty, Madbillet, and more. Handles Danish compound words and bilingual keyword matching.

2

Filter, deduplicate, and classify

Aggressive quality filtering removes ~60% of raw scrapes — products, fake discounts, non-Copenhagen locations, and junk providers. Duplicate venues across sources keep only the lowest price. Food deals with drink keywords get auto-reclassified.

3

Browse, search, and filter in the web app

A Next.js frontend on Vercel shows deals in grid, list, or map view. Filter by category, price range, time added, and expiry. Sort by newest, cheapest, or highest discount. Use "Near Me" to find deals closest to your location.

4

Get notified via Telegram

New deals matching your interests are sent to a Telegram channel twice daily. SQLite deduplication ensures you only see new deals.

Key features

3 view modes

Grid cards, compact list, and interactive Leaflet map with marker clustering

4 categories

Activities, Food, Drinks, Entertainment — color-coded with smart filtering

Geolocation

"Near Me" button calculates distance to 27 Copenhagen neighborhoods via Haversine

Advanced search

Full-text search, price ranges, time filters, sort by discount/price/date

Dark mode

Auto-detects system preference, instant toggle with no flash on load

Export as PNG

Download any deal card as a shareable image via html2canvas

Add Dealround to home screen
Install as a PWA from the browser
Dealround on iPhone home screen as a native app
Behaves like a native app on your phone

Tech stack

Frontend

Next.jsReactTypeScriptTailwind CSSReact Query

Maps

Leaflet

CartoDB tiles (free, no API key), react-leaflet-cluster for marker grouping

Backend and Scraping

PythonSQLiteTelegram

BeautifulSoup for HTML parsing, APScheduler for cron jobs

Infrastructure

VercelHetzner

Architecture

Dual deploy: Next.js frontend on Vercel, Python scraper + REST API on Hetzner VPS (systemd service). Frontend proxies API calls through Next.js route handlers with 60s ISR revalidation.

SQLite on the VPS stores all deals with deduplication. Quality filtering happens both server-side (scraper) and client-side (dealFilter.ts blocks 47 product keywords, 11 junk providers, and non-Copenhagen locations).

Geolocation uses a static lookup table of 27 Copenhagen neighborhoods with Nominatim API fallback. Markers are jittered deterministically by deal_id hash to prevent overlap.

Mobile-first with pull-to-refresh (damped touch gesture), collapsible filters, and list view as the default on small screens. React Query handles caching and background refetching.

Data sources

Meyou.dkSweetdeal.dkAll2day.dkBowntyMadbilletDowntown.dkZafidaSPOT

Scraped twice daily at 08:00 and 18:00 CET — typically yields 150-200 quality deals after filtering

What I learned

  • -Danish compound words like "healingsmassage" break standard word boundary regex — use substring matching for longer keywords and word boundaries only for short ambiguous ones like "spa".
  • -The hardest part of a deal aggregator is data quality. ~60% of raw scrapes are junk — products, fake discounts, or wrong locations. Aggressive filtering is essential.
  • -Downtown.dk redirects to meyou.dk but still SSR-renders 60+ deal cards — scraping Angular apps works fine when they use server-side rendering.
  • -Free map tiles from CartoDB + Leaflet clustering make a polished map experience without any API key costs.
Next.jsReactTypeScriptTailwind CSSReact QueryLeafletPythonSQLiteTelegramVercelHetzner