Runs your property search on Google for one site each week and logs every result page you have not seen, with its title and any price.

UsesClaudeGoogle SheetsSerper

Log new property search results from one site each week

Describe one property search once, such as two bedroom flats for sale in one city, and name the property site. Every week the workflow runs that search on Google, limited to that site, and logs what comes back in Google Sheets: each result page it has not seen before goes on your results tab with the date first seen, the page title, the first price its text shows, the link and Google's short description of the page. A second tab gets one row per run with the counts and a short note on what was added.

Google's results for a property site mix single listings with search pages and area guides, and all of them are logged unless you say how the site's listing links look: set a piece of the address such as '/properties/' and every other page is counted but left out. It is a record, not advice: nothing is valued, no price is called high or low and no prediction is made, and any money figure in the AI's note must appear in the results or the note is dropped for plain counts. A page whose text shows no price gets an empty cell, links already on record are skipped, and rows are only ever appended.

You need Google Sheets, Serper (for the Google search) and Anthropic connected, and a Google Sheet with two tabs, named 'Search results' and 'Weekly summary' unless you choose others; heading rows are written into empty tabs for you. Fill in the search, the site, a name for the market and the sheet's link.

ScheduleRun every 7 days.Run every 7 days.
ValuesSet searchQuery to blank.Set searchQuery to blank.
ValuesSet listingSite to blank.Set listingSite to blank.
ValuesSet marketName to blank.Set marketName to blank.
ValuesSet spreadsheetUrl to blank.Set spreadsheetUrl to blank.
ValuesSet listingsSheetName to Search results.Set listingsSheetName to Search results.
ValuesSet summarySheetName to Weekly summary.Set summarySheetName to Weekly summary.
ValuesSet maxNewListings to 15.Set maxNewListings to 15.
ValuesSet resultsToScan to 20.Set resultsToScan to 20.
ValuesSet listingLinkContains to blank.Set listingLinkContains to blank.
Decisions & LoopsIf listingsSheetName is blankIf listingsSheetName is blank
Yes
ValuesChange listingsSheetName to Search results.Change listingsSheetName to Search results.
No
No steps
Decisions & LoopsIf summarySheetName is blankIf summarySheetName is blank
Yes
ValuesChange summarySheetName to Weekly summary.Change summarySheetName to Weekly summary.
No
No steps
TextMake listingSite lowercase and save it as siteHostRaw.Make listingSite lowercase and save it as siteHostRaw.
ListsGet the first item of the last item of siteHostRaw split by :// split by / and save it as siteHost.Get the first item of the last item of siteHostRaw split by :// split by / and save it as siteHost.
Decisions & LoopsIf siteHost is emptyIf siteHost is empty
Yes
Decisions & LoopsStop and report a problem: 'listingSite' does not look like a web address. Write just the site, for example rightmove.co.uk.Stop and report a problem: 'listingSite' does not look like a web address. Write just the site, for example rightmove.co.uk.
No
No steps
Google SheetsGoogle SheetsRead the rows of spreadsheetUrl. Save it as record.Read the rows of spreadsheetUrl. Save it as record.
ValuesSet recordHeaders to record.headers.Set recordHeaders to record.headers.
ValuesSet recordRows to record.rows.Set recordRows to record.rows.
Decisions & LoopsIf recordHeaders is emptyIf recordHeaders is empty
Yes
Google SheetsGoogle SheetsAdd a row to listingsSheetName in spreadsheetUrl.Add a row to listingsSheetName in spreadsheetUrl.
No
No steps
ValuesSet seenLinks to an empty list.Set seenLinks to an empty list.
Decisions & LoopsFor each recordRow in recordRows:For each recordRow in recordRows:
Decisions & LoopsIf a step below fails, save the error as recordErrorIf a step below fails, save the error as recordError
Try
ListsAdd recordRow.Link in lowercase to the end of seenLinks and save it as seenLinks.Add recordRow.Link in lowercase to the end of seenLinks and save it as seenLinks.
On error
ValuesShow in the output: Ignored a row already on the record that has no Link column: recordError as text.Show in the output: Ignored a row already on the record that has no Link column: recordError as text.
ValuesSet searchUsed to searchQuery site:siteHost.Set searchUsed to searchQuery site:siteHost.
SerperSerperSearch Google for searchUsed. Save it as search.Search Google for searchUsed. Save it as search.
ValuesSet hits to search.results.Set hits to search.results.
ValuesSet newCount to 0.Set newCount to 0.
ValuesSet alreadyCount to 0.Set alreadyCount to 0.
ValuesSet offSiteCount to 0.Set offSiteCount to 0.
ValuesSet newSummary to blank.Set newSummary to blank.
ValuesSet notListingCount to 0.Set notListingCount to 0.
ValuesSet hitLimit to false.Set hitLimit to false.
Decisions & LoopsFor each hit in hits:For each hit in hits:
Decisions & LoopsIf newCount multiplied by 1 is greater than or equal to maxNewListings multiplied…If newCount multiplied by 1 is greater than or equal to maxNewListings multiplied…
Yes
ValuesChange hitLimit to true.Change hitLimit to true.
Decisions & LoopsStop repeating.Stop repeating.
No
No steps
Decisions & LoopsIf a step below fails, save the error as listingErrorIf a step below fails, save the error as listingError
Try
TextTrim hit.link and save it as listingLink.Trim hit.link and save it as listingLink.
Decisions & LoopsIf listingLink is nullIf listingLink is null
Yes
ValuesChange listingLink to blank.Change listingLink to blank.
No
No steps
Decisions & LoopsIf listingLink is emptyIf listingLink is empty
Yes
ValuesShow in the output: Skipped a search result that came back with no link..Show in the output: Skipped a search result that came back with no link..
No
TextMake listingLink lowercase and save it as linkLower.Make listingLink lowercase and save it as linkLower.
ListsGet the first item of the last item of linkLower split by :// split by / and save it as linkHost.Get the first item of the last item of linkLower split by :// split by / and save it as linkHost.
ValuesSet onSite to linkHost is siteHost or linkHost ends with .@siteHost.Set onSite to linkHost is siteHost or linkHost ends with .@siteHost.
Decisions & LoopsIf onSite is yesIf onSite is yes
Yes
Decisions & LoopsIf listingLinkContains isn't blank and linkLower doesn't contain…If listingLinkContains isn't blank and linkLower doesn't contain…
Yes
ValuesAdd 1 to notListingCount.Add 1 to notListingCount.
Else if @seenLinks contains @linkLower
ValuesAdd 1 to alreadyCount.Add 1 to alreadyCount.
Otherwise
TextTrim hit.title and save it as listingTitle.Trim hit.title and save it as listingTitle.
Decisions & LoopsIf listingTitle is nullIf listingTitle is null
Yes
ValuesChange listingTitle to blank.Change listingTitle to blank.
No
No steps
TextTrim hit.snippet and save it as listingSnippet.Trim hit.snippet and save it as listingSnippet.
Decisions & LoopsIf listingSnippet is nullIf listingSnippet is null
Yes
ValuesChange listingSnippet to blank.Change listingSnippet to blank.
No
No steps
ValuesSet listingText to listingTitle listingSnippet.Set listingText to listingTitle listingSnippet.
TextExtract the first match from listingText and save it as priceAsListed.Extract the first match from listingText and save it as priceAsListed.
Google SheetsGoogle SheetsAdd a row to listingsSheetName in spreadsheetUrl.Add a row to listingsSheetName in spreadsheetUrl.
ListsAdd linkLower to the end of seenLinks and save it as seenLinks.Add linkLower to the end of seenLinks and save it as seenLinks.
ValuesChange newSummary to newSummary- listingTitle | price as listed: priceAsListedChange newSummary to newSummary- listingTitle | price as listed: priceAsListed .
ValuesAdd 1 to newCount.Add 1 to newCount.
No
ValuesAdd 1 to offSiteCount.Add 1 to offSiteCount.
On error
ValuesShow in the output: Skipped a search result that could not be read: listingError as text.Show in the output: Skipped a search result that could not be read: listingError as text.
MathSet listingsOnRecord to the length of recordRows plus newCount.Set listingsOnRecord to the length of recordRows plus newCount.
ValuesSet note to Recorded newCount as text new search results for this market; alreadyCount as text results were already on the record.Set note to Recorded newCount as text new search results for this market; alreadyCount as text results were already on the record.
Decisions & LoopsIf newCount multiplied by 1 is greater than 0If newCount multiplied by 1 is greater than 0
Yes
ValuesSet notePrompt to You are writing one short note for a record of property search results.Set notePrompt to You are writing one short note for a record of property search results. Describe only what the search results below say: how many there are, what kinds of property they are, and the prices as they were listed. Quote a figure only if it appears in the text below, written exactly as it is there. Do not give advice, an opinion, a recommendation or a forecast. Do not say whether anything is cheap, expensive, good value, a bargain, over-priced or worth buying. Do not estimate a value, a yield, a return or a future price. Do not compare these results with any market figure you were not given here. Do not describe the market as rising, falling, hot, slow or recovering. Write at most four sentences of plain description, and nothing else. Market: marketName New search results recorded in this run: newSummary.
Decisions & LoopsIf a step below fails, save the error as noteErrorIf a step below fails, save the error as noteError
Try
ClaudeClaudeAsk Claude: notePrompt. Save it as written.Ask Claude: notePrompt. Save it as written. Maximum response length: 400
TextTrim written.response_text and save it as noteText.Trim written.response_text and save it as noteText.
TextExtract all matches from noteText and save it as noteFigures.Extract all matches from noteText and save it as noteFigures.
ValuesSet noteIsClean to true.Set noteIsClean to true.
Decisions & LoopsFor each figure in noteFigures:For each figure in noteFigures:
Decisions & Loops If newSummary doesn't contain figure If newSummary doesn't contain figure
Yes
ValuesChange noteIsClean to false.Change noteIsClean to false.
Decisions & LoopsStop repeating.Stop repeating.
No
No steps
Decisions & LoopsIf noteIsClean is yes and noteText isn't emptyIf noteIsClean is yes and noteText isn't empty
Yes
ValuesChange note to noteText.Change note to noteText.
No
ValuesShow in the output: The written note was left out: it quoted a figure that is not in the listings, or came back empty. The listing rows are unaffected..Show in the output: The written note was left out: it quoted a figure that is not in the listings, or came back empty. The listing rows are unaffected..
On error
ValuesShow in the output: Could not write the run note: noteError as text.Show in the output: Could not write the run note: noteError as text.
No
No steps
Google SheetsGoogle SheetsRead the rows of spreadsheetUrl. Save it as summary.Read the rows of spreadsheetUrl. Save it as summary.
ValuesSet summaryHeaders to summary.headers.Set summaryHeaders to summary.headers.
Decisions & LoopsIf summaryHeaders is emptyIf summaryHeaders is empty
Yes
Google SheetsGoogle SheetsAdd a row to summarySheetName in spreadsheetUrl.Add a row to summarySheetName in spreadsheetUrl.
No
No steps
Google SheetsGoogle SheetsAdd a row to summarySheetName in spreadsheetUrl.Add a row to summarySheetName in spreadsheetUrl.
ValuesSet limitNote to blank.Set limitNote to blank.
Decisions & LoopsIf hitLimit is yesIf hitLimit is yes
Yes
TextBuild the text Stopped at the limit of @maxNewListings new results set in 'maxNewListings'; any others are not recorded this week. and save it as limitNote.Build the text Stopped at the limit of @maxNewListings new results set in 'maxNewListings'; any others are not recorded this week. and save it as limitNote.
No
No steps
ValuesShow in the output: Added newCount new search results to the '@listingsSheetName' tab. alreadyCount were already on the record, notListingCount were not listing pages and offSiteCount were not on siteHost.@limitNote.Show in the output: Added newCount new search results to the '@listingsSheetName' tab. alreadyCount were already on the record, notListingCount were not listing pages and offSiteCount were not on siteHost.@limitNote.