property-hunt
NewAutomated UK flat hunt. Searches SpareRoom, OpenRent and Zoopla for 1-bed and 2-bed flats across your target postcodes, deduplicates and price-tracks them in a spreadsheet, writes ready-to-send outreach messages for the best finds, and emails you a phone-friendly summary. Reads every personal setting from config.md.
Overview
Property Hunt
Run an automated flat hunt with no user present. Work through every step to the end, then send the summary email even if nothing new turned up.
All values written as [LIKE_THIS] come from config.md. Copy config.example.md to config.md and fill it in before the first run.
Who you are searching for
Read these from config:
- •
[NAME],[AGE],[PROFESSION] - •Tenant profile:
[PROFILE_DESCRIPTION] - •Move-in: around
[MOVE_IN_DATE], give or take a week - •Target postcodes:
[POSTCODES] - •Budgets: 1-bed up to
[ONE_BED_BUDGET]pcm, 2-bed up to[TWO_BED_BUDGET]pcm
Postcode to location mapping
Config holds a [POSTCODE_LOCATIONS] table that maps each postcode to a human area name (for example KT3 = New Malden). Use it to fill the Location column in the tracker and the email tables. If a postcode is not in the table, use the postcode itself as the location.
What to search for
Self-contained flats only. Skip anything that is a room in a shared house or a house share.
Run this filter on every listing before adding it:
- •1-bed and price within
[ONE_BED_BUDGET]: add to the 1-bed results - •2-bed and price within
[TWO_BED_BUDGET]: add to the 2-bed results - •Studio or 0-bed: skip
- •3-bed or larger: skip
- •1-bed over budget: skip
- •2-bed over budget: skip
- •Bed count unknown: add with a note, "Verify 1 to 2 bed before messaging"
Building the search URLs
Loop over each postcode in [POSTCODES] and each bed count (1 then 2). Build the URLs from these patterns, substituting the postcode, the matching budget for that bed count, and the bed count itself.
SpareRoom (one URL per postcode and bed count):
https://www.spareroom.co.uk/flats-to-rent/[postcode]?max_rent=[budget]&min_bedrooms=[beds]&max_bedrooms=[beds]&sort=posted_date&mode=listOpenRent (one URL per postcode and bed count, using the postcode area name for the slug and term):
https://www.openrent.co.uk/properties-to-rent/[postcode-slug]?term=[POSTCODE]%20[Area],%20London&prices_max=[budget]&bedrooms_min=[beds]&bedrooms_max=[beds]&isLive=trueZoopla (one URL per area name and bed count; Zoopla uses the location slug, not the postcode):
https://www.zoopla.co.uk/to-rent/flats/[location-slug]/?beds_min=[beds]&beds_max=[beds]&price_frequency=per_month&price_max=[budget]&results_sort=newest_listings&pn=1Rightmove (one URL per postcode and bed count). Rightmove does not take a plain postcode in the URL. It uses a numeric location identifier of the form OUTCODE^NNNN. Resolve it once per postcode: open https://www.rightmove.co.uk, type the postcode into the search box, start a rent search, and read the locationIdentifier value out of the results URL. Reuse that value on later runs. Then build:
https://www.rightmove.co.uk/property-to-rent/find.html?locationIdentifier=OUTCODE%5E[code]&minBedrooms=[beds]&maxBedrooms=[beds]&maxPrice=[budget]&propertyTypes=flat&includeLetAgreed=falseOpen each search results page in the browser. Prefer the structured data the site already embeds over scraping rendered HTML:
- •Rightmove embeds listing JSON in a
__NEXT_DATA__script tag. - •Zoopla embeds JSON-LD in an
lsrp-schemascript tag. - •OpenRent and SpareRoom: read the page text through the accessibility tree.
If a browser JavaScript call returns truncated output (there is a roughly 900 character limit on returned strings), inject the data into a hidden <pre> element in the DOM and read it back with the page-text tool. The DOM acts as a transfer buffer for payloads of any size.
Tracker
File: [HUNT_DIR]/property_hunt.xlsx, sheet Apartments.
Columns, in order:
Address | Price | Price Change | Furnished | URL | Location | Status | Priority | Found On | Available | BedsRun the dedup and price check on every listing:
- Look for a row whose URL matches exactly.
- No match means a new listing. Add a row with Status
NEW, Price Change blank, Found On today. - Match found means an existing listing. Compare the scraped price to the stored Price:
- Price unchanged, Status is NEW, and Found On is not today: set Status to ACTIVE. The listing is still live but was found on an earlier run, so it is no longer new. - Price unchanged and Status is anything other than NEW: skip, no update needed. - Price dropped: update the Price cell, set Price Change to down by [diff] (was [old]), set Status to PRICE DROP. - Price rose: update the Price cell, set Price Change to up by [diff] (was [old]), set Status to PRICE RISE. - Note "Updated [today]" in the Found On cell for any row you changed.
Dedup is by URL, so the run is idempotent and safe to repeat as often as you like.
Priority, read from the config tiers [HIGH_POSTCODES], [MEDIUM_POSTCODES], [LOW_POSTCODES]:
- •HIGH: a high-tier postcode, within budget, available by around
[MOVE_IN_DATE]plus a week - •MEDIUM: a medium-tier postcode within budget and timing
- •LOW: a low-tier postcode, late availability, or outer area
Row fill colours: HIGH E2EFDA, MEDIUM FFFFC7, LOW FCE4D6.
Email, fully self-contained for phone use
The reader may only have a phone, so the email has to be actionable on its own without opening any other file.
Use gmail_create_draft with contentType text/html, to [EMAIL].
Subject: London flat hunt, [DATE] ([morning or evening]), [N] new listings
HTML body sections:
A. Header. Date, run time, platforms searched. Bold counts: HIGH N, MEDIUM N, PRICE DROPS N, TOTAL NEW N.
B. HIGH, new today. Listings where Priority is HIGH, Status is NEW, Found On is today. Two sub-sections, 1-beds first.
- •B1, 1-bedroom (within
[ONE_BED_BUDGET]). HTML table: Address, Price, Furnished, URL, Location. Below it, one green outreach card per listing, under 100 words:
"Hi, [one specific sentence about this listing, such as the location, price, or a standout feature]. I'm [NAME], [AGE], [PROFESSION]. [PROFILE_SUMMARY]. Looking to move around [MOVE_IN_DATE]. Happy to arrange a viewing. [NAME]"
- •B2, 2-bedroom (within
[TWO_BED_BUDGET]). Same table and the same outreach card format.
C. MEDIUM, new today. Priority MEDIUM, Status NEW, Found On today. Same two-section layout, table only, no outreach cards.
D. LOW and skipped. Bullet list only.
E. Price changes since last run.
- •E1, price drops. Table for every listing with Status
PRICE DROP: Address, First Seen, Old Price to New Price, Saving, URL, Location. Add an outreach card for HIGH drops. - •E2, price rises. Bullet list only: Address, old to new price, first seen date, URL.
F. Backlog, uncontacted HIGH, not today. Up to 8 listings where Status is NEW or ACTIVE, Priority is HIGH, Found On is not today. Sort oldest Found On first, then by price ascending, 1-beds before 2-beds. Table: Address, Price, Furnished, First Seen, URL, Location. In the First Seen cell show the Found On date plus days elapsed, for example 2026-05-17 (1 day ago). If a listing is 3 or more days old, bold that cell in amber. Each card gets a grey italic staleness note first: "Listed [N] day(s) ago, still available as of the last check."
G. Stats. Totals by area and bed type, next run time. End with: "[X] days to [MOVE_IN_DATE]. Message at least 5 listings today."
After creating the draft, open https://mail.google.com/mail/u/[GMAIL_ACCOUNT_INDEX]/#drafts, open the draft, and click Send.
Outreach files
Save a .txt file for each HIGH priority listing to [HUNT_DIR]/outreach/.
Success criteria
- •The Apartments sheet is updated, with only 1 and 2 bed self-contained flats added.
- •1-beds within
[ONE_BED_BUDGET]and 2-beds within[TWO_BED_BUDGET], enforced strictly. - •Outreach files saved for HIGH priority listings.
- •Email sent, always, even when there is nothing new.
Install & Usage
mkdir -p .claude/skillsmkdir -p .claude/skills && curl -o .claude/skills/property-hunt.md https://raw.githubusercontent.com/ChevalierOnGithub/property-hunt-skill/main/SKILL.md/property-huntFrequently Asked Questions
What is property-hunt?
Automated UK flat hunt. Searches SpareRoom, OpenRent and Zoopla for 1-bed and 2-bed flats across your target postcodes, deduplicates and price-tracks them in a spreadsheet, writes ready-to-send outreach messages for the best finds, and emails you a phone-friendly summary. Reads every personal setting from config.md.
How to install property-hunt?
To install property-hunt, create the .claude/skills directory in your project, then run the curl command to download the skill file. Once installed, invoke it in Claude Code with /property-hunt.
What is property-hunt best for?
property-hunt is a community categorized under General. Created by ChevalierOnGithub.