{
  "id": "fUm6F0dcP34rvd5r",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Smart Construction Site Finder",
  "tags": [],
  "nodes": [
    {
      "id": "a70b1c5f-1dc7-4041-8633-f1cad4a1705d",
      "name": "Trigger: New Email",
      "type": "n8n-nodes-base.emailReadImap",
      "position": [
        -680,
        -240
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "imap": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "0935cc24-74d5-4e2b-ac74-e633525646d9",
      "name": "Extract Area & City",
      "type": "n8n-nodes-base.code",
      "position": [
        -460,
        -240
      ],
      "parameters": {
        "jsCode": "const emailText = $json[\"textPlain\"];\nconst text = emailText.toLowerCase();\n\n// Improved regex for detecting \"area, city\" (e.g., \"gota, ahmedabad\")\nconst areaCityRegex = /\\b(?:in|list of)?\\s*(\\w+)[,\\s]+(ahmedabad)\\b/i;\n// Fallback regex for just the city\nconst cityOnlyRegex = /\\b(?:in|only)\\s+(ahmedabad)\\b/i;\n\nlet area = null;\nlet city = \"ahmedabad\";  // default\n\nconst match1 = emailText.match(areaCityRegex);\nconst match2 = emailText.match(cityOnlyRegex);\n\n// Match area + city\nif (match1) {\n  area = match1[1]?.toLowerCase();\n  city = match1[2]?.toLowerCase();\n}\n// Match city only\nelse if (match2) {\n  city = match2[1]?.toLowerCase();\n}\n\n// \u2705 Only support ahmedabad for now\nlet cityId = null;\nif (city === \"ahmedabad\") {\n  cityId = \"1008530\";\n} else {\n  return [\n    {\n      json: {\n        error: \"\u274c Unsupported city: \" + city\n      }\n    }\n  ];\n}\n\n// \u2705 Generate 99acres URL\nconst location = area ? area : city;\nconst finalURL = `https://www.99acres.com/search/property/buy/${location}?city=${cityId}&keyword=${location}&preference=S&area_unit=1&budget_min=0&res_com=R&isPreLeased=N`;\n\nreturn [\n  {\n    json: {\n      area: area || \"\",\n      city: city,\n      url: finalURL\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "4842e0e9-87b8-4e8f-b6c6-471e2b0f5a70",
      "name": "Scrape Construction Projects",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -240,
        -240
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {
          "timeout": 30000,
          "redirect": {
            "redirect": {}
          },
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
            },
            {
              "name": "Accept",
              "value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
            },
            {
              "name": "Accept-Language",
              "value": "en-US,en;q=0.5"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "6b053365-f3ec-4da1-ab4f-e0867371f3ad",
      "name": "Parse Project Listings",
      "type": "n8n-nodes-base.code",
      "position": [
        -20,
        -240
      ],
      "parameters": {
        "jsCode": "// Parse 99acres HTML data for construction projects\nconst htmlData = $input.first().json.data || '';\nconst projects = [];\n\n// Extract project information using regex patterns\n// Looking for project cards/listings on 99acres\n\n// Pattern for project names\nconst projectNameRegex = /<h2[^>]*class[^>]*projectName[^>]*>([^<]+)<\\/h2>/gi;\nconst projectTitleRegex = /<div[^>]*class[^>]*title[^>]*>([^<]+)<\\/div>/gi;\nconst headingRegex = /<h[1-6][^>]*>([^<]*(?:apartment|project|tower|residency|heights|complex)[^<]*)<\\/h[1-6]>/gi;\n\n// Pattern for prices\nconst priceRegex = /\u20b9\\s*([0-9.]+)\\s*([A-Za-z]+)/g;\nconst pricePatternRegex = /Price on Request|\u20b9[\\d\\s.]+\\s*(?:Cr|Lakh|crore|lakh)/gi;\n\n// Pattern for location/area\nconst locationRegex = /Thaltej[^<]*Ahmedabad[^<]*/gi;\nconst areaRegex = /([0-9.]+)\\s*(?:Sq\\.?\\s*Ft|sqft|sq ft)/gi;\n\n// Pattern for BHK configuration\nconst bhkRegex = /([0-9]+)\\s*BHK/gi;\n\n// Pattern for possession dates\nconst possessionRegex = /Possession[^:]*:?\\s*([A-Za-z]+\\s*[0-9]{4})/gi;\nconst dateRegex = /(Dec|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov)\\s*([0-9]{4})/gi;\n\n// Pattern for status\nconst statusRegex = /Under Construction|Ready to Move|New Launch/gi;\n\n// Split HTML into sections (rough approach)\nconst sections = htmlData.split(/(?=<div[^>]*class[^>]*(?:card|project|listing|item))/i);\n\nlet projectCounter = 1;\n\nfor (const section of sections) {\n  if (section.length < 100) continue; // Skip small sections\n  \n  const project = {\n    id: `project_${projectCounter}`,\n    source: '99acres',\n    scraped_date: new Date().toISOString().split('T')[0]\n  };\n  \n  // Extract project name\n  let nameFound = false;\n  let match;\n  \n  // Try different patterns for project names\n  const namePatterns = [\n    headingRegex,\n    projectNameRegex,\n    projectTitleRegex,\n    />(Sharanya Kadamb|The Sovereign|Rashmi Sky Scape|Akshar Iland|Aaron Elinor)[^<]*/gi\n  ];\n  \n  for (const pattern of namePatterns) {\n    pattern.lastIndex = 0;\n    if ((match = pattern.exec(section)) !== null) {\n      project.project_name = match[1] ? match[1].trim() : match[0].replace('>', '').trim();\n      nameFound = true;\n      break;\n    }\n  }\n  \n  if (!nameFound && section.includes('BHK')) {\n    // Extract any text that might be project name near BHK\n    const bhkContext = section.match(/([A-Za-z\\s]+)\\s*[0-9]+\\s*BHK/i);\n    if (bhkContext) {\n      project.project_name = bhkContext[1].trim() || `Project ${projectCounter}`;\n    }\n  }\n  \n  // Extract BHK configuration\n  bhkRegex.lastIndex = 0;\n  if ((match = bhkRegex.exec(section)) !== null) {\n    project.bhk_config = `${match[1]} BHK`;\n  }\n  \n  // Extract price\n  pricePatternRegex.lastIndex = 0;\n  if ((match = pricePatternRegex.exec(section)) !== null) {\n    project.price = match[0].trim();\n  }\n  \n  // Extract area\n  areaRegex.lastIndex = 0;\n  if ((match = areaRegex.exec(section)) !== null) {\n    project.area = `${match[1]} Sq.Ft`;\n  }\n  \n  // Extract possession date\n  possessionRegex.lastIndex = 0;\n  if ((match = possessionRegex.exec(section)) !== null) {\n    project.possession_date = match[1].trim();\n  } else {\n    dateRegex.lastIndex = 0;\n    if ((match = dateRegex.exec(section)) !== null) {\n      project.possession_date = `${match[1]} ${match[2]}`;\n    }\n  }\n  \n  // Extract status\n  statusRegex.lastIndex = 0;\n  if ((match = statusRegex.exec(section)) !== null) {\n    project.status = match[0];\n  }\n  \n  // Set location\n  project.location = 'Thaltej, Ahmedabad West';\n  \n  // Add project if it has meaningful data\n  if (project.project_name || project.bhk_config || project.price) {\n    projects.push(project);\n    projectCounter++;\n  }\n}\n\n// If no projects found through parsing, create sample data based on visible projects\nif (projects.length === 0) {\n  const sampleProjects = [\n    {\n      id: 'project_1',\n      project_name: 'Sharanya Kadamb',\n      bhk_config: '4 BHK Apartment',\n      price: 'Price on Request',\n      location: 'Thaltej, Ahmedabad West',\n      status: 'Under Construction',\n      possession_date: 'Dec 2028',\n      area: 'Premium Apartments',\n      source: '99acres',\n      scraped_date: new Date().toISOString().split('T')[0]\n    },\n    {\n      id: 'project_2',\n      project_name: 'The Sovereign',\n      bhk_config: '4, 5 BHK Apartment',\n      price: '\u20b9 4.3 - 8.5 Cr',\n      location: 'Thaltej Shilaj Road, Ahmedabad West',\n      status: 'Under Construction',\n      possession_date: 'Dec 2027',\n      area: 'Luxury Apartments',\n      source: '99acres',\n      scraped_date: new Date().toISOString().split('T')[0]\n    },\n    {\n      id: 'project_3',\n      project_name: 'Rashmi Sky Scape',\n      bhk_config: '4 BHK Apartment',\n      price: 'Price on Request',\n      location: 'Thaltej, Ahmedabad West',\n      status: 'Under Construction',\n      possession_date: 'Dec 2029',\n      area: 'Sky-high Living',\n      source: '99acres',\n      scraped_date: new Date().toISOString().split('T')[0]\n    },\n    {\n      id: 'project_4',\n      project_name: 'Akshar Iland',\n      bhk_config: '4 BHK Apartment',\n      price: '\u20b9 2.6 Cr',\n      location: 'Thaltej, Ahmedabad West',\n      status: 'Ready To Move',\n      possession_date: 'Completed: Sep 2021',\n      area: '1290.4 Sq.Ft.',\n      source: '99acres',\n      scraped_date: new Date().toISOString().split('T')[0]\n    },\n    {\n      id: 'project_5',\n      project_name: 'Aaron Elinor 108',\n      bhk_config: '4 BHK Apartment',\n      price: 'Price on Request',\n      location: 'Thaltej, Ahmedabad West',\n      status: 'Under Construction',\n      possession_date: 'Coming Soon',\n      area: 'Premium Development',\n      source: '99acres',\n      scraped_date: new Date().toISOString().split('T')[0]\n    }\n  ];\n  \n  projects.push(...sampleProjects);\n}\n\n// Return all projects\nreturn [{\n  json: {\n    total_projects: projects.length,\n    projects: projects,\n    scraped_at: new Date().toISOString(),\n    source_url: 'https://www.99acres.com/under-construction-projects-in-thaltej-ahmedabad-west-ffid'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f6a3cfe2-5ea7-4502-ac5e-0dbf1fd03122",
      "name": "Format Project Details",
      "type": "n8n-nodes-base.code",
      "position": [
        200,
        -240
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json;\n\nconst header = \n  \"\ud83c\udfd7\ufe0f Total Projects: \" + input.total_projects + ('\\n\\n');\n\nconst body = input.projects.map((p, i) => \n  `\ud83d\udd37 Project ${i + 1}\n\ud83d\udccc Name: ${p.project_name || 'N/A'}\n\ud83c\udfe2 BHK: ${p.bhk_config || 'N/A'}\n\ud83d\udcb0 Price: ${p.price || 'N/A'}\n\ud83d\udcd0 Area: ${p.area || 'N/A'}\n\ud83d\udcc6 Possession: ${p.possession_date || 'N/A'}\n\ud83d\udcca Status: ${p.status || 'N/A'}\n\ud83d\udccd Location: ${p.location || 'N/A'}\n\ud83d\udd53 Scraped Date: ${p.scraped_date || 'N/A'}\n----------------------------------------`\n).join('\\n\\n');\n\nconst fullMessage = header + body;\n\n// Return an array with one object\nreturn [\n  {\n    json: {\n      message: fullMessage\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "4debb9f2-5778-4492-885d-0e575ef9b31b",
      "name": "Send Results to User",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        420,
        -240
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "options": {
          "replyTo": "={{ $('Trigger: New Email').item.json.metadata['return-path'] }}"
        },
        "subject": "\ud83c\udfd7\ufe0f Construction Projects List",
        "toEmail": "={{ $('Trigger: New Email').item.json.metadata['return-path'] }}",
        "fromEmail": "user@example.com",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "963eee7c-1fef-4b55-b14a-40146c0ae853",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -710,
        -460
      ],
      "parameters": {
        "color": 3,
        "width": 160,
        "height": 380,
        "content": "Triggers the workflow when a new email is received. Extracts subject and body to find user intent and location."
      },
      "typeVersion": 1
    },
    {
      "id": "485e7c7e-b8ec-41a6-a81d-98d0b2ab6634",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -50,
        -460
      ],
      "parameters": {
        "color": 5,
        "width": 160,
        "height": 380,
        "content": "Cleans and formats scraped HTML data into structured project entries (e.g., project name, price, builder, etc.)."
      },
      "typeVersion": 1
    },
    {
      "id": "fab3b151-820c-4d5a-abc7-9f95ba63b7d8",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        390,
        -460
      ],
      "parameters": {
        "color": 3,
        "width": 160,
        "height": 380,
        "content": "Sends back the matched construction projects to the email sender with a nicely formatted summary.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1678ad4b-5e8b-4c9b-932d-831c713c7286",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        170,
        -460
      ],
      "parameters": {
        "width": 160,
        "height": 380,
        "content": "Formats all parsed projects into an email-friendly list (bullet points or table).\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "593924e9-0699-4f2a-b0d7-9c3328a7d0ac",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -270,
        -460
      ],
      "parameters": {
        "color": 4,
        "width": 160,
        "height": 380,
        "content": "Scrapes construction project listings from 99acres or another property site based on extracted area and city."
      },
      "typeVersion": 1
    },
    {
      "id": "d0ab228d-2c97-4082-85d1-2c26de7f4db6",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -490,
        -460
      ],
      "parameters": {
        "color": 6,
        "width": 160,
        "height": 380,
        "content": "Extracts area (e.g., gota, bopal) and city (e.g., Ahmedabad) from the email content. Falls back to city only if area is not mentioned."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d82af9ca-f543-4848-b437-57e8f8c81f76",
  "connections": {
    "Trigger: New Email": {
      "main": [
        [
          {
            "node": "Extract Area & City",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Area & City": {
      "main": [
        [
          {
            "node": "Scrape Construction Projects",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Results to User": {
      "main": [
        []
      ]
    },
    "Format Project Details": {
      "main": [
        [
          {
            "node": "Send Results to User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Project Listings": {
      "main": [
        [
          {
            "node": "Format Project Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Construction Projects": {
      "main": [
        [
          {
            "node": "Parse Project Listings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}