{
  "id": "pzJ1ilEk3GKEeYIn",
  "name": "Redfin Scraper With ScrapeOps",
  "tags": [
    {
      "id": "2kgNrWqNHzb5HXvl",
      "name": "Real Estate Automation",
      "createdAt": "2026-03-10T09:33:35.714Z",
      "updatedAt": "2026-03-10T09:33:35.714Z"
    },
    {
      "id": "5cX1Q7XarLiCrVyq",
      "name": "Redfin Scraper",
      "createdAt": "2026-03-10T09:33:23.320Z",
      "updatedAt": "2026-03-10T09:33:23.320Z"
    },
    {
      "id": "lZKSh2IoxHklnOUw",
      "name": "ScrapeOps",
      "createdAt": "2025-10-20T20:27:13.410Z",
      "updatedAt": "2025-10-20T20:27:13.410Z"
    },
    {
      "id": "yzylwxvLF3YwGBRm",
      "name": "Google Sheets Automation",
      "createdAt": "2026-03-10T07:03:25.329Z",
      "updatedAt": "2026-03-10T07:03:25.329Z"
    },
    {
      "id": "zjUTmlbvYV0JQkxb",
      "name": "Property Listing Tracker",
      "createdAt": "2026-03-10T09:33:48.715Z",
      "updatedAt": "2026-03-10T09:33:48.715Z"
    }
  ],
  "nodes": [
    {
      "id": "8975814a-86ee-4313-8e1d-fdef4c16d347",
      "name": "Set Search Parameters",
      "type": "n8n-nodes-base.set",
      "position": [
        1296,
        912
      ],
      "parameters": {
        "fields": {
          "values": [
            {
              "name": "redfin_url",
              "stringValue": "https://www.redfin.com/city/21853/MD/California"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "27533ae7-b0fe-4330-9e97-7ec5c6b8f264",
      "name": "Filter Valid Properties",
      "type": "n8n-nodes-base.if",
      "position": [
        2640,
        912
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "valid_address_check",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.property_address }}",
              "rightValue": "N/A"
            },
            {
              "id": "valid_price_check",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.price }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "8f7c0dc6-253f-4a9e-8f38-85b669bffc37",
      "name": "Send Slack Summary",
      "type": "n8n-nodes-base.slack",
      "position": [
        2976,
        1024
      ],
      "parameters": {
        "text": "\ud83c\udfe0 Redfin Scrape Complete! | Sheet: https://docs.google.com/spreadsheets/d/1FYbt_m8nUdlkSmCzwZeBjgp4js6sdIKpiyyTIPBsigQ",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09DL0BM2J2",
          "cachedResultName": "testnoor"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.1
    },
    {
      "id": "f6429dff-9a79-42e7-b957-a490cd57018f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        496
      ],
      "parameters": {
        "width": 704,
        "height": 832,
        "content": "# \ud83c\udfe1 Redfin Property Scraper \u2192 Google Sheets + Slack\n\nThis workflow automatically scrapes Redfin property listings on a schedule. It fetches search results via **ScrapeOps Proxy API**, parses them into clean structured data using the **ScrapeOps Redfin Parser API**, filters valid listings, saves them to Google Sheets, and optionally sends a Slack summary.\n\n### How it works\n1. \u23f0 **Schedule Trigger** fires every 6 hours automatically.\n2. \u2699\ufe0f **Set Search Parameters** defines the Redfin search URL to scrape.\n3. \ud83c\udf10 **ScrapeOps: Fetch Redfin Page** loads the listing page with JS rendering and residential proxy via [ScrapeOps Proxy API](https://scrapeops.io/docs/n8n/proxy-api/).\n4. \ud83d\udd0d **ScrapeOps: Parse Redfin Listings** extracts clean structured JSON using the [ScrapeOps Parser API](https://scrapeops.io/docs/n8n/parser-api/).\n5. \ud83d\uddc2\ufe0f **Add Search Metadata** lifts summary fields like total listings, region, and price range.\n6. \ud83d\udce6 **Split Properties Into Items** turns the results array into one item per property.\n7. \ud83d\uddfa\ufe0f **Format Property Fields** normalizes address, price, beds, baths, sqft, and more.\n8. \u2705 **Filter Valid Properties** drops items missing an address or with price = 0.\n9. \ud83d\udcbe **Save Listings to Google Sheets** appends valid rows to your sheet.\n10. \ud83d\udce3 **Send Slack Summary** posts an optional summary with listing count and sheet link.\n\n### Setup steps\n- Register for a free ScrapeOps API key: https://scrapeops.io/app/register/n8n\n- Add ScrapeOps credentials to both ScrapeOps nodes. Docs: https://scrapeops.io/docs/n8n/overview/\n- Duplicate the [Google Sheet template](https://docs.google.com/spreadsheets/d/1FYbt_m8nUdlkSmCzwZeBjgp4js6sdIKpiyyTIPBsigQ/edit?gid=0#gid=0) and paste your Sheet ID into **Save Listings to Google Sheets**.\n- Set your target city URL in **Set Search Parameters**.\n- Optional: configure the Slack node with your channel and credentials.\n\n### Customization\n- Change `redfin_url` to any Redfin city, ZIP, or filtered search page.\n- Adjust `wait` and `scroll` settings in the Proxy node if results are empty.\n- Change the schedule interval to daily or hourly as needed."
      },
      "typeVersion": 1
    },
    {
      "id": "e892ecd8-63ba-4034-9b1f-649ff04ebbda",
      "name": " Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1072,
        912
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "76b652e7-1645-492a-bd32-b889fd7b48e2",
      "name": "ScrapeOps: Fetch Redfin Page (Proxy)",
      "type": "@scrapeops/n8n-nodes-scrapeops.ScrapeOps",
      "position": [
        1584,
        912
      ],
      "parameters": {
        "url": "={{ $json.redfin_url }}",
        "advancedOptions": {
          "wait": 5000,
          "scroll": 2000,
          "country": "us",
          "render_js": true,
          "device_type": "desktop",
          "residential_proxy": true
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f83f344b-7603-438d-b36b-1dd2c7739138",
      "name": "ScrapeOps: Parse Redfin Listings",
      "type": "@scrapeops/n8n-nodes-scrapeops.ScrapeOps",
      "position": [
        1792,
        912
      ],
      "parameters": {
        "apiType": "parserApi",
        "parserUrl": "={{ $('Set Search Parameters').item.json.redfin_url }}",
        "parserHtml": "={{ $json }}",
        "parserDomain": "redfin"
      },
      "typeVersion": 1
    },
    {
      "id": "a4e368d0-372d-49f9-a23b-83b70c3c9e9a",
      "name": "Add Search Metadata",
      "type": "n8n-nodes-base.set",
      "position": [
        2096,
        912
      ],
      "parameters": {
        "fields": {
          "values": [
            {
              "name": "timestamp",
              "stringValue": "={{ new Date().toISOString() }}"
            },
            {
              "name": "search_title",
              "stringValue": "={{ $json.data.search_information.search_title || 'N/A' }}"
            },
            {
              "name": "search_type",
              "stringValue": "={{ $json.data.search_information.search_type || 'N/A' }}"
            },
            {
              "name": "average_price",
              "stringValue": "=total_properties: {{ $json.data.search_information.total_count || 0 }}\n"
            },
            {
              "name": "total_properties",
              "stringValue": "={{ $json.data.search_information.total_count || 0 }}"
            },
            {
              "name": "=region_info",
              "stringValue": "={{ $json.data.search_information.region.name + ', ' + $json.data.search_information.region.state || 'N/A' }}\n"
            },
            {
              "name": "=price_range",
              "stringValue": "={{ ($json.data.search_information.min_price || 0) + ' - ' + ($json.data.search_information.max_price || 0) }}"
            },
            {
              "name": "=average_price: {{ $json.data.search_information.average_price || 0 }}",
              "stringValue": "={{ $json.data.search_information.average_price || 0 }}"
            },
            {
              "name": "=url_scraped",
              "stringValue": "={{ $json.url || 'N/A' }}"
            },
            {
              "name": "=search_results",
              "stringValue": "={{ $json.data.search_results }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "e72e4f6b-0b6e-4987-aca8-f2dffe76fef3",
      "name": "Split Properties Into Items",
      "type": "n8n-nodes-base.code",
      "position": [
        2272,
        912
      ],
      "parameters": {
        "jsCode": "// Parse the search_results array and return individual property items\nconst searchResults = $input.first().json.search_results;\n\n// Handle both string and array cases\nconst propertiesArray = typeof searchResults === 'string' ? \n    JSON.parse(searchResults) : searchResults;\n\nif (!Array.isArray(propertiesArray)) {\n    throw new Error('search_results is not an array');\n}\n\nreturn propertiesArray.map((property, index) => ({\n    json: property,\n    index\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "e8b45f2d-c69d-4239-988f-abad44ed2299",
      "name": "Format Property Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        2448,
        912
      ],
      "parameters": {
        "fields": {
          "values": [
            {
              "name": "property_address",
              "stringValue": "={{ $json.address || $json.title || 'N/A' }}"
            },
            {
              "name": "property_price",
              "stringValue": "={{ $json.price || 0 }}"
            },
            {
              "name": "property_type",
              "stringValue": "={{ $json.property_type || 'N/A' }}"
            },
            {
              "name": "bedrooms",
              "stringValue": "={{ $json.bedrooms || 0 }}"
            },
            {
              "name": "bathrooms",
              "stringValue": "={{ $json.bathrooms || 0 }}"
            },
            {
              "name": "bathrooms_full",
              "stringValue": "={{ $json.bathrooms_full || 0 }}"
            },
            {
              "name": "bathrooms_half",
              "stringValue": "={{ $json.bathrooms_half || 0 }}"
            },
            {
              "name": "square_footage",
              "stringValue": "={{ $json.area || 0 }}"
            },
            {
              "name": "lot_area",
              "stringValue": "={{ $json.lot_area || 0 }}"
            },
            {
              "name": "year_built",
              "stringValue": "={{ $json.year_built || 'N/A' }}"
            },
            {
              "name": "listing_status",
              "stringValue": "={{ $json.listing_status || $json.status || 'N/A' }}"
            },
            {
              "name": "days_on_market",
              "stringValue": "={{ $json.days_on_market || $json.dom || 'N/A' }}"
            },
            {
              "name": "mls_id",
              "stringValue": "={{ $json.mls_id || 'N/A' }}"
            },
            {
              "name": "property_url",
              "stringValue": "={{ $json.url || 'N/A' }}"
            },
            {
              "name": "=photo_url",
              "stringValue": "={{ $json.photo || 'N/A' }}"
            },
            {
              "name": "=location",
              "stringValue": "={{ $json.location || 'N/A' }}"
            },
            {
              "name": "=description",
              "stringValue": "={{ ($json.description || '').substring(0, 200) + '...' }}"
            },
            {
              "name": "=hoa_fee",
              "stringValue": "={{ $json.hoa || 0 }}"
            },
            {},
            {
              "name": "price_per_sqft",
              "stringValue": "= {{ $json.price_per_sqrf || 0 }}"
            },
            {
              "name": "=sold_date",
              "stringValue": "={{ $json.sold_date || 'N/A' }}"
            },
            {
              "name": "time_zone",
              "stringValue": "={{ $json.time_zone || 'N/A' }}"
            },
            {
              "name": "country",
              "stringValue": "={{ $json.country || 'N/A' }}"
            },
            {
              "name": "badges",
              "stringValue": "={{ ($json.badges || []).join(', ') || 'None' }}"
            },
            {
              "name": "latitude",
              "stringValue": "={{ $json.lat_long?.latitude || 0 }}"
            },
            {
              "name": "longitude",
              "stringValue": "={{ $json.lat_long?.longitude || 0 }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "f61461ad-6608-485b-b0d7-69a748c05e61",
      "name": "Save Listings to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2976,
        816
      ],
      "parameters": {
        "columns": {
          "value": {
            "Price": "={{ $('Filter Valid Properties').item.json.price }}",
            "Badges": "={{ $json.badges }}",
            "MLS_ID": "={{ $json.mls_id }}",
            "Status": "={{ $json.listing_status }}",
            "Address": "={{ $json.address }}",
            "HOA_Fee": "={{ $json.hoa_fee }}",
            "Has_HOA": "={{ $json.hoa }}",
            "Bedrooms": "={{ $json.bedrooms }}",
            "Location": "={{ $json.property_address }}",
            "Bathrooms": "={{ $json.bathrooms }}",
            "Lot_Acres": "={{ $json.lot_area }}",
            "Photo_URL": "={{ $json.photo }}",
            "Scraped_At": "={{ new Date().toISOString() }}",
            "Year_Built": "={{ $json.year_built }}",
            "Coordinates": "={{ $json.lat_long.latitude }}, {{ $json.lat_long.longitude }}",
            "Description": "={{ $json.description }}",
            "Square_Feet": "={{ $json.square_footage }}",
            "Property_URL": "={{ $json.property_url }}",
            "Property_Type": "={{ $('Filter Valid Properties').item.json.property_type }}",
            "Price_Per_SqFt": "={{ $json.price_per_sqrf }}"
          },
          "schema": [
            {
              "id": "Address",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Address",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Property_Type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Property_Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Bedrooms",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Bedrooms",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Bathrooms",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Bathrooms",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Square_Feet",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Square_Feet",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Lot_Acres",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Lot_Acres",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Year_Built",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Year_Built",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "MLS_ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "MLS_ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Price_Per_SqFt",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Price_Per_SqFt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "HOA_Fee",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "HOA_Fee",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Has_HOA",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Has_HOA",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Photo_URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Photo_URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Property_URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Property_URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Coordinates",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Coordinates",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Scraped_At",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Scraped_At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Badges",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Badges",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FYbt_m8nUdlkSmCzwZeBjgp4js6sdIKpiyyTIPBsigQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1FYbt_m8nUdlkSmCzwZeBjgp4js6sdIKpiyyTIPBsigQ"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "5fe6aaaf-304f-437a-845d-137287f8d527",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 272,
        "content": "## 1. Trigger & Configuration\nFires on a schedule and sets the Redfin search URL to scrape."
      },
      "typeVersion": 1
    },
    {
      "id": "aa8e1734-476d-41de-9ff9-20f7c5dcca81",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1488,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 272,
        "content": "## 2. Fetch & Parse Listings\nLoad the Redfin page via [ScrapeOps Proxy](https://scrapeops.io/docs/n8n/proxy-api/) with JS rendering, then extract structured listing data using the [ScrapeOps Parser API](https://scrapeops.io/docs/n8n/parser-api/)."
      },
      "typeVersion": 1
    },
    {
      "id": "ffa90a55-997f-4530-af38-f7bf61abedd0",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 800,
        "height": 272,
        "content": "## 3. Transform & Filter\nLift search summary fields, split results into individual items, normalize property fields, and drop listings missing an address or valid price."
      },
      "typeVersion": 1
    },
    {
      "id": "698a5b77-3c8b-4690-a650-15a57fdbac41",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2832,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 480,
        "content": "## 4. Save & Notify\nAppend valid listings to Google Sheets and optionally post a Slack summary with listing count and a link to the sheet."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "1526577e-c512-4256-811c-f1fa04b7a1b9",
  "connections": {
    " Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set Search Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Search Metadata": {
      "main": [
        [
          {
            "node": "Split Properties Into Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Search Parameters": {
      "main": [
        [
          {
            "node": "ScrapeOps: Fetch Redfin Page (Proxy)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Property Fields": {
      "main": [
        [
          {
            "node": "Filter Valid Properties",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Valid Properties": {
      "main": [
        [
          {
            "node": "Save Listings to Google Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Slack Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Properties Into Items": {
      "main": [
        [
          {
            "node": "Format Property Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Listings to Google Sheets": {
      "main": [
        [
          {
            "node": "Send Slack Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ScrapeOps: Parse Redfin Listings": {
      "main": [
        [
          {
            "node": "Add Search Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ScrapeOps: Fetch Redfin Page (Proxy)": {
      "main": [
        [
          {
            "node": "ScrapeOps: Parse Redfin Listings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}