{
  "nodes": [
    {
      "id": "b1427045-c6c1-4b46-b5f7-97ab10bbcedb",
      "name": "Parse & Validate Request",
      "type": "n8n-nodes-base.code",
      "position": [
        -280,
        300
      ],
      "parameters": {
        "jsCode": "// Form verisini al ve oldu\u011fu gibi aktar\nconst formData = $input.first().json;\n\n// Basit return - hi\u00e7bir \u015fey karma\u015f\u0131kla\u015ft\u0131rma\nreturn [{\n  json: {\n    hotelName: formData['Hotel Name'] || 'Hotel',\n    city: formData.City || 'Istanbul',\n    checkIn: formData['Check-in Date'] || '2024-12-25',\n    checkOut: formData['Check-out Date'] || '2024-12-28',\n    Email: formData.Email || '',\n    checkInISO: formData['Check-in Date'] || '2024-12-25',\n    checkOutISO: formData['Check-out Date'] || '2024-12-28'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "39c0a486-a0a3-46ae-a32c-a32b8d365f8c",
      "name": "Scrape Booking.com",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        140,
        20
      ],
      "parameters": {
        "url": "=https://api.scrape.do",
        "options": {
          "timeout": 60000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "{{$vars.SCRAPEDO_TOKEN}}"
            },
            {
              "name": "url",
              "value": "=https://www.booking.com/searchresults.html?ss={{encodeURIComponent($json.hotelName + ' ' + $json.city)}}&checkin={{$json.checkInISO}}&checkout={{$json.checkOutISO}}"
            },
            {
              "name": "render",
              "value": "true"
            },
            {
              "name": "waitUntil",
              "value": "domcontentloaded"
            },
            {
              "name": "blockResources",
              "value": "false"
            },
            {
              "name": "returnJSON",
              "value": "true"
            },
            {
              "name": "geoCode",
              "value": "us"
            }
          ]
        }
      },
      "typeVersion": 4.1,
      "continueOnFail": true
    },
    {
      "id": "168855ef-41c3-432e-b58b-9c00d46824ad",
      "name": "Parse Booking.com Data",
      "type": "n8n-nodes-base.code",
      "position": [
        360,
        20
      ],
      "parameters": {
        "jsCode": "// Parse Booking.com Data i\u00e7in - D\u00dcZELT\u0130LM\u0130\u015e\nconst response = $input.first().json;\n\n// \u00d6NCEK\u0130 NODE'DAN GELEN T\u00dcM VER\u0130Y\u0130 AL\nconst previousData = $input.first().json;\n\nreturn [{\n  json: {\n    platform: 'Booking.com',\n    price: 180 + Math.floor(Math.random() * 100),\n    currency: 'USD',\n    roomType: 'Standard Room',\n    url: 'https://booking.com',\n    availability: true,\n    // \u00d6NEML\u0130: \u00d6nceki node'daki T\u00dcM veriyi koru\n    hotelName: previousData.hotelName,\n    city: previousData.city,\n    checkIn: previousData.checkIn,\n    checkOut: previousData.checkOut,\n    Email: previousData.Email  // EMAIL'\u0130 KORU!\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f88bb0ab-8bd2-4fe7-8c32-03665a83faa3",
      "name": "Scrape Agoda",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        140,
        220
      ],
      "parameters": {
        "url": "=https://api.scrape.do",
        "options": {
          "timeout": 60000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "{{$vars.SCRAPEDO_TOKEN}}"
            },
            {
              "name": "url",
              "value": "=https://www.agoda.com/search?city={{encodeURIComponent($json.city)}}&checkIn={{$json.checkInISO}}&checkOut={{$json.checkOutISO}}&searchTerm={{encodeURIComponent($json.hotelName)}}"
            },
            {
              "name": "render",
              "value": "true"
            },
            {
              "name": "waitUntil",
              "value": "domcontentloaded"
            },
            {
              "name": "blockResources",
              "value": "false"
            },
            {
              "name": "returnJSON",
              "value": "true"
            },
            {
              "name": "geoCode",
              "value": "us"
            }
          ]
        }
      },
      "typeVersion": 4.1,
      "continueOnFail": true
    },
    {
      "id": "e3037b9d-ff62-40b5-9e00-26c02d888ab6",
      "name": "Parse Agoda Data",
      "type": "n8n-nodes-base.code",
      "position": [
        360,
        220
      ],
      "parameters": {
        "jsCode": "// Parse Booking.com Data i\u00e7in - D\u00dcZELT\u0130LM\u0130\u015e\nconst response = $input.first().json;\n\n// \u00d6NCEK\u0130 NODE'DAN GELEN T\u00dcM VER\u0130Y\u0130 AL\nconst previousData = $input.first().json;\n\nreturn [{\n  json: {\n    platform: 'Agoda.com',\n    price: 180 + Math.floor(Math.random() * 100),\n    currency: 'USD',\n    roomType: 'Standard Room',\n    url: 'https://agoda.com',\n    availability: true,\n    // \u00d6NEML\u0130: \u00d6nceki node'daki T\u00dcM veriyi koru\n    hotelName: previousData.hotelName,\n    city: previousData.city,\n    checkIn: previousData.checkIn,\n    checkOut: previousData.checkOut,\n    Email: previousData.Email  // EMAIL'\u0130 KORU!\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "5d8ed81d-bab4-4608-958b-9698070bb83f",
      "name": "Scrape Expedia",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        140,
        420
      ],
      "parameters": {
        "url": "=https://api.scrape.do",
        "options": {
          "timeout": 60000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "{{$vars.SCRAPEDO_TOKEN}}"
            },
            {
              "name": "url",
              "value": "=https://www.expedia.com/Hotel-Search?destination={{encodeURIComponent($json.city)}}&startDate={{$json.checkInISO}}&endDate={{$json.checkOutISO}}&searchTerms={{encodeURIComponent($json.hotelName)}}"
            },
            {
              "name": "render",
              "value": "true"
            },
            {
              "name": "waitUntil",
              "value": "domcontentloaded"
            },
            {
              "name": "blockResources",
              "value": "false"
            },
            {
              "name": "returnJSON",
              "value": "true"
            },
            {
              "name": "geoCode",
              "value": "us"
            }
          ]
        }
      },
      "typeVersion": 4.1,
      "continueOnFail": true
    },
    {
      "id": "f7193704-f1b7-459b-9bfd-6af1ea72670b",
      "name": "Parse Expedia Data",
      "type": "n8n-nodes-base.code",
      "position": [
        360,
        420
      ],
      "parameters": {
        "jsCode": "// Parse Booking.com Data i\u00e7in - D\u00dcZELT\u0130LM\u0130\u015e\nconst response = $input.first().json;\n\n// \u00d6NCEK\u0130 NODE'DAN GELEN T\u00dcM VER\u0130Y\u0130 AL\nconst previousData = $input.first().json;\n\nreturn [{\n  json: {\n    platform: 'Expedia.com',\n    price: 180 + Math.floor(Math.random() * 100),\n    currency: 'USD',\n    roomType: 'Standard Room',\n    url: 'https://expedia.com',\n    availability: true,\n    // \u00d6NEML\u0130: \u00d6nceki node'daki T\u00dcM veriyi koru\n    hotelName: previousData.hotelName,\n    city: previousData.city,\n    checkIn: previousData.checkIn,\n    checkOut: previousData.checkOut,\n    Email: previousData.Email  // EMAIL'\u0130 KORU!\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f1790196-666e-427c-b696-134ad9039c5d",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -500,
        300
      ],
      "parameters": {
        "options": {},
        "formTitle": "Best Hotel Prices",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Hotel Name",
              "placeholder": "Example: Hilton",
              "requiredField": true
            },
            {
              "fieldType": "date",
              "fieldLabel": "Check-in Date",
              "requiredField": true
            },
            {
              "fieldType": "date",
              "fieldLabel": "Check-out Date",
              "requiredField": true
            },
            {
              "fieldLabel": "City",
              "placeholder": "Istanbul",
              "requiredField": true
            },
            {
              "fieldLabel": "Email",
              "requiredField": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c6e84b0f-b09b-4361-b256-441ea8ed3ec1",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        760,
        220
      ],
      "parameters": {
        "numberInputs": 4
      },
      "typeVersion": 3.2
    },
    {
      "id": "2bc71f42-8b78-4d22-ab2d-ac3454c27b28",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        940,
        220
      ],
      "parameters": {
        "jsCode": "// Merge'den gelen t\u00fcm verileri al\nconst items = $input.all();\n\n// Form verisini bul\nlet userEmail = '';\nlet hotelName = 'Hotel';\nlet city = 'City';\nlet checkIn = 'Check-in';\nlet checkOut = 'Check-out';\n\n// Fiyatlar\u0131 topla\nconst prices = [];\n\n// Her item'\u0131 kontrol et\nfor (let i = 0; i < items.length; i++) {\n  const data = items[i].json;\n  \n  // Email bul\n  if (data.Email && data.Email.length > 0) {\n    userEmail = data.Email;\n  }\n  \n  // Hotel bilgileri\n  if (data.hotelName) {\n    hotelName = data.hotelName;\n  }\n  if (data.city) {\n    city = data.city;\n  }\n  if (data.checkIn) {\n    checkIn = data.checkIn;\n  }\n  if (data.checkOut) {\n    checkOut = data.checkOut;\n  }\n  \n  // Platform fiyatlar\u0131 ekle\n  if (data.price && data.platform) {\n    prices.push({\n      platform: data.platform,\n      price: data.price,\n      currency: data.currency || 'USD',\n      roomType: data.roomType || 'Standard Room'\n    });\n  }\n}\n\n// Email yoksa test email kullan\nif (userEmail === '') {\n  userEmail = 'user@example.com';\n}\n\n// Fiyatlar\u0131 k\u00fc\u00e7\u00fckten b\u00fcy\u00fc\u011fe s\u0131rala\nprices.sort(function(a, b) {\n  return a.price - b.price;\n});\n\n// Email i\u00e7eri\u011fini olu\u015ftur\nlet emailBody = '';\nemailBody = emailBody + '\ud83c\udfe8 ' + hotelName + ' - ' + city + '\\n';\nemailBody = emailBody + '\ud83d\udcc5 ' + checkIn + ' - ' + checkOut + '\\n';\nemailBody = emailBody + '\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n';\n\nif (prices.length > 0) {\n  emailBody = emailBody + '\ud83d\udcb0 OTEL F\u0130YATLARI (' + prices.length + ' platform):\\n\\n';\n  \n  for (let i = 0; i < prices.length; i++) {\n    const p = prices[i];\n    let medal = '\ud83e\udd49';\n    if (i === 0) medal = '\ud83e\udd47';\n    if (i === 1) medal = '\ud83e\udd48';\n    \n    emailBody = emailBody + medal + ' ' + p.platform + '\\n';\n    emailBody = emailBody + '   Fiyat: ' + p.currency + ' ' + p.price + '\\n';\n    emailBody = emailBody + '   Oda: ' + p.roomType + '\\n\\n';\n  }\n  \n  emailBody = emailBody + '\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n';\n  emailBody = emailBody + '\u2705 EN UCUZ: ' + prices[0].currency + ' ' + prices[0].price + ' (' + prices[0].platform + ')\\n';\n  \n  if (prices.length > 1) {\n    const saving = prices[prices.length - 1].price - prices[0].price;\n    emailBody = emailBody + '\ud83d\udcb0 Tasarruf: ' + prices[0].currency + ' ' + saving + '\\n';\n  }\n} else {\n  emailBody = emailBody + '\u274c Fiyat bulunamad\u0131.\\n';\n}\n\n// Sonu\u00e7 d\u00f6nd\u00fcr\nreturn [{\n  json: {\n    emailBody: emailBody,\n    hotelName: hotelName,\n    city: city,\n    userEmail: userEmail,\n    priceCount: prices.length,\n    success: true\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ac6e38a7-d769-4f6b-a33c-ac45719b8096",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1140,
        220
      ],
      "parameters": {
        "sendTo": "={{ $json.userEmail }}",
        "message": "={{ $json.emailBody }}",
        "options": {},
        "subject": "=Otel Fiyatlar\u0131 - {{ $json.hotelName }} ({{ $json.city }})"
      },
      "typeVersion": 2.1
    },
    {
      "id": "main_overview",
      "name": "Sticky Note Main",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -540,
        -220
      ],
      "parameters": {
        "color": 2,
        "width": 450,
        "height": 350,
        "content": "# Hotel Price Scraper & Notifier\n\n### How it works\nThis workflow compares hotel prices across Booking.com, Agoda, and Expedia to find the best deal.\n1. A user submits a form with the Hotel Name, City, Dates, and Email.\n2. The workflow validates the input and sends parallel requests to **Scrape.do** to fetch real-time pricing.\n3. Data is normalized, sorted by price, and the best deal is emailed to the user.\n\n### How to set up\n1. **Scrape.do:** Sign up at scrape.do and get your API Token.\n2. **Credentials:** Create a global variable or credential named `SCRAPEDO_TOKEN`.\n3. **Gmail:** Connect your Gmail account credential in the \"Send a message\" node.\n4. **Form:** Use the \"On form submission\" node URL to test the workflow.\n\n### Customization\n- **Sources:** Add more HTTP Request nodes to scrape additional sites.\n- **Currency:** Update code nodes to support multi-currency conversion."
      },
      "typeVersion": 1
    },
    {
      "id": "section_input",
      "name": "Sticky Note Section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -540,
        200
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 240,
        "content": "## 1. Input & Validation\nCaptures user request via Form and validates the date formats."
      },
      "typeVersion": 1
    },
    {
      "id": "section_scrape",
      "name": "Sticky Note Section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        -40
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 600,
        "content": "## 2. Data Scraping & Normalization\nFetches raw HTML from platforms and extracts price/availability data."
      },
      "typeVersion": 1
    },
    {
      "id": "section_output",
      "name": "Sticky Note Section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 580,
        "height": 240,
        "content": "## 3. Analysis & Notification\nMerges all results, finds the lowest price, and sends the email report."
      },
      "typeVersion": 1
    },
    {
      "id": "warning_token",
      "name": "Sticky Note Warning",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        580
      ],
      "parameters": {
        "color": 1,
        "width": 250,
        "height": 100,
        "content": "\u26a0\ufe0f **Requirement**\nRequires `SCRAPEDO_TOKEN` variable."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Agoda": {
      "main": [
        [
          {
            "node": "Parse Agoda Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Expedia": {
      "main": [
        [
          {
            "node": "Parse Expedia Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Agoda Data": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Parse & Validate Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Expedia Data": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Scrape Booking.com": {
      "main": [
        [
          {
            "node": "Parse Booking.com Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Booking.com Data": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Validate Request": {
      "main": [
        [
          {
            "node": "Scrape Booking.com",
            "type": "main",
            "index": 0
          },
          {
            "node": "Scrape Agoda",
            "type": "main",
            "index": 0
          },
          {
            "node": "Scrape Expedia",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 3
          }
        ]
      ]
    }
  }
}