Appearance
Kangalou Scraper — Technical Analysis
Platform Overview
Kangalou is Quebec's #1 rental listings platform, owned by CORPIQ (Corporation des propriétaires immobiliers du Québec, 30,000 landlord members). Free for landlords to post, with paid visibility packages ($40-$540).
- ~7,500 active listings (mostly Montreal)
- ~1M+ monthly page views
- Bilingual (FR/EN)
- URL:
https://kangalou.com
Data Available Per Listing
| Field | Available | Notes |
|---|---|---|
| Title | Yes | Property type + size + location |
| Price (rent/month) | Yes | In dollars |
| Property type | Yes | Apartment, condo, house, room, loft, studio |
| Size (rooms) | Yes | Quebec notation: 3½, 4½, 5½ |
| Bedrooms / Bathrooms | Yes | Numeric |
| Floor | Yes | Floor number |
| Area (sq ft / m²) | Yes | Both units |
| Availability date | Yes | Specific date or "now" |
| City / Neighborhood | Yes | Montreal neighborhoods |
| Description | Yes | Full text, mostly French |
| Images | Yes | Multiple, via kangalou.com/images/glide/ |
| Coordinates (lat/lng) | Yes | Embedded in HTML — no geocoding needed |
| Street address | Partial | Some in URL slug, some neighborhood only |
| Amenities | Yes | Pets, parking, laundry, furnished, etc. |
| Contact name | Yes | Landlord name on page |
| Phone number | Auth-gated | Requires login + reCAPTCHA v3 |
| No | Message form only | |
| Listing ID | Yes | Numeric (e.g., 222455) |
Technical Architecture
| Component | Details |
|---|---|
| Server | Nginx (no CDN, no Cloudflare) |
| Backend | PHP (custom, not WordPress/Laravel) |
| Frontend | jQuery, server-side rendered HTML |
| Maps | Google Maps |
| Anti-bot | None — no WAF, no CAPTCHA on search, no rate limiting |
Internal API Endpoints
Discovered from JS bundle at /dist/js/kangalou.js:
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/:lang/api/search | POST | No | Main search — returns JSON with HTML listings |
/:lang/api/process | POST | No | Autocomplete/instant search |
/:lang/api/listings/:id/contact-phone | GET | Yes (401) | Phone number reveal |
/:lang/api/listings/:id/contact-message | POST | Yes | Send message |
/:lang/api/listings/:id/visit-days | GET | ? | Visit schedule |
/:lang/api/postal-codes/:code/locations | GET | No | Postal code lookup |
Search API
POST /:lang/api/search — the main discovery endpoint.
Parameters (form body):
search-string— text query (e.g., "montreal")search-filter-city— city filtersearch-filter-sort— sort order (newest,pasc)page— pagination (1-indexed)s— size filtert[]— type filter (array)pmin/pmax— price rangef[]— feature/amenity filterg[],z[]— unknown filters
Response: JSON { ok: true, html: "<div>...</div>" } — server-rendered HTML with listing cards.
~53 listings per page, ~142 pages for full inventory.
URL Structure
- Search:
/:lang/search/or/:lang/recherche/ - City:
/:lang/location/:city/ - Neighborhood:
/:lang/location/:city/:neighborhood/ - Detail:
/:lang/listing/:slug/:id/(EN) or/:lang/annonce/:slug/:id/(FR)
Anti-Bot Assessment
| Measure | Status |
|---|---|
| Cloudflare / WAF | None |
| CAPTCHA on search | None |
| CAPTCHA on phone | reCAPTCHA v3 (site key: 6LepJboUAAAAAIWJCyG8PzlT2kTSl6fGmVtRSZXi) |
| Rate limiting | None detected |
| Bot detection JS | None |
| User-Agent check | None — curl works |
| IP blocking | Not observed |
Verdict: Very low protection. Orders of magnitude easier than Kijiji.
Recommended Scraping Approach
HTTP-only — no Playwright/browser needed.
- Discovery: POST to
/en/api/searchwith pagination → listing URLs + basic card data - Detail: GET each listing page → full data (description, coordinates, amenities, images, contact name)
- Phone numbers: Skip unless account is created (auth + reCAPTCHA v3)
Stack: undici/fetch + cheerio for HTML parsing. Fits existing BaseScraper interface.
Estimated Scrape Time
| Phase | Volume | Time (sequential) | Time (5 concurrent) |
|---|---|---|---|
| Search pages | 142 pages × 18s | ~43 min | ~9 min |
| Detail pages | 7,500 × 3.6s | ~7.5 hours | ~1.5 hours |
| Total | ~2 hours |
Phone Numbers
Phone numbers are behind auth at /:lang/api/listings/:id/contact-phone (returns 401 without login). Also protected by reCAPTCHA v3.
Options:
- Create an account, solve reCAPTCHA v3 tokens programmatically — moderate difficulty
- Skip phone numbers initially, only import listings with phones from other sources
- Use Playwright for phone reveal (same approach as Kijiji) — heavier but proven
Legal Risk
Moderate — same category as Kijiji.
ToS prohibitions:
- "use, download or otherwise copy... any directory of Users"
- "gather or otherwise collect information about others, including email addresses"
- All content copyrighted by Kangalou/CORPIQ
Mitigating factors:
- Listing data is publicly accessible without login
- No aggressive anti-bot enforcement suggests they tolerate some scraping
- Phone numbers are the most sensitive data (auth-gated)
Risk owner: CORPIQ — organized Quebec landlord association with resources to enforce.
Mitigation: Avoid storing landlord names. Rate-limit respectfully. Don't scrape phone numbers without careful consideration.
Comparison to Kijiji
| Factor | Kijiji | Kangalou |
|---|---|---|
| Anti-bot | High (Cloudflare, reCAPTCHA Enterprise) | Very low (nothing) |
| Browser needed | Yes (Playwright) | No (HTTP + cheerio) |
| Data format | Apollo GraphQL JSON | Server-rendered HTML |
| Phone numbers | reCAPTCHA Enterprise (hard) | Auth + reCAPTCHA v3 (moderate) |
| Listings (MTL) | ~5,000-10,000 | ~7,500 |
| Rate limiting | Aggressive | None |
| Implementation effort | 2-3 weeks | 3-5 days |
| Overlap with Kijiji | N/A | Low-moderate |
| Coordinates included | No (need geocoding) | Yes (embedded) |
Implementation Priority
High priority — easiest scraper to build. Kangalou should be the next scraper after Kijiji because:
- Zero anti-bot → simple HTTP client
- No browser dependency → faster, less resource-intensive
- Coordinates embedded → no geocoding API calls needed
- Good data quality (CORPIQ-verified landlords)
- Complementary inventory to Kijiji
- 3-5 day implementation estimate