{
  "id": "TuCCJd7wyzGdDiJk",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Create real estate listing packages from room photos with Anthropic Claude",
  "tags": [],
  "nodes": [
    {
      "id": "1f9ce148-4e08-4032-8ac4-03dd44ae0485",
      "name": "Sticky Note - Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        -640
      ],
      "parameters": {
        "color": "#FFF700",
        "width": 940,
        "height": 1108,
        "content": "## Empty-Room to Full-Listing Pipeline\n\nTurn a single empty-room photo into a ready-to-publish real estate listing: an AI-staged render, a comp-based price recommendation, and AI-written listing copy \u2014 delivered straight to your inbox.\n\nBuilt for real estate agents, property managers, and listing platforms who want a listing-ready package minutes after a photo shoot, not days.\n\n### How it works\n1. A form captures the empty-room photo plus property basics (address, type, beds, baths, square footage).\n2. Two APIs run in parallel: a virtual-staging/3D-rendering API furnishes and styles the room and returns a walkthrough link, while a comps API pulls recent comparable sales near the address.\n3. A Code node merges both responses into pricing inputs: average comp price, price-per-sqft, and a suggested price range.\n4. Claude writes the listing title, description, key selling points, and a suggested list price.\n5. A Code node parses the AI output into structured data (with a rule-based fallback if parsing fails), then assembles the final package.\n6. The complete listing is emailed to the agent, ready to publish.\n\n### Setup\n1. Import this workflow into n8n.\n2. Add your Anthropic Claude credentials to the Anthropic model node.\n3. Add your virtual-staging/3D-rendering API credentials to Fetch AI Virtual Staging Render.\n4. Add your comps/market-data API credentials to Fetch Comparable Listings & Market Data.\n5. Add SMTP credentials to Send Full Listing Package Email and update the from/to addresses.\n6. Activate the workflow and open the form URL to submit a room photo.\n\n### Customization\n- Add staging style options (Modern, Traditional, Scandinavian) as a form field.\n- Log every generated listing to a Google Sheet or CRM.\n- Add a second AI pass to generate social captions from the listing copy.\n- Push the finished listing directly into your MLS or listing platform instead of email."
      },
      "typeVersion": 1
    },
    {
      "id": "a3cbc4d4-aec9-4930-84b6-29feedcf02ee",
      "name": "Sticky Note - Stage 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        -368
      ],
      "parameters": {
        "color": 4,
        "width": 1300,
        "height": 760,
        "content": "## Stage 1: Photo In, Staging & Comps Out\n\nThe form captures the room photo and property details. Two APIs run in parallel \u2014 AI staging/3D render and comps data. A Code node merges them into pricing inputs (avg price, price/sqft, suggested range)."
      },
      "typeVersion": 1
    },
    {
      "id": "c6d84e5b-475a-4e36-8fee-d4d38ee7d3a9",
      "name": "Sticky Note - Stage 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3552,
        -352
      ],
      "parameters": {
        "color": 3,
        "width": 1028,
        "height": 760,
        "content": "## Stage 2: AI Copywriting\n\nA short wait respects API rate limits. Claude then turns the staged render, comp pricing, and property details into a listing title, description, selling points, and suggested list price."
      },
      "typeVersion": 1
    },
    {
      "id": "c5323703-a0b9-4448-b5b4-f382b14c8907",
      "name": "Sticky Note - Stage 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4704,
        -368
      ],
      "parameters": {
        "color": 4,
        "width": 892,
        "height": 760,
        "content": "## Stage 3: Assemble & Deliver\n\nA Code node parses the AI output (with a rule-based fallback), then another assembles the staged image, 3D link, comp pricing, and copy into one package \u2014 emailed to the agent, ready to publish."
      },
      "typeVersion": 1
    },
    {
      "id": "200f265a-3e46-43ce-a10f-7941661cce9a",
      "name": "Form - Upload Empty Room Photo",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        2304,
        96
      ],
      "parameters": {
        "options": {},
        "formTitle": "=",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "Empty Room Photo",
              "requiredField": true
            },
            {
              "fieldLabel": "Property Address",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Property Type",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Single Family Home"
                  },
                  {
                    "option": "Condo"
                  },
                  {
                    "option": "Townhouse"
                  },
                  {
                    "option": "Apartment"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Bedrooms"
            },
            {
              "fieldType": "number",
              "fieldLabel": "Bathrooms"
            },
            {
              "fieldType": "number",
              "fieldLabel": "Square Feet"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b1483cae-63f2-4d19-bb71-0a4913475fb3",
      "name": "Fetch AI Virtual Staging Render",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2624,
        -48
      ],
      "parameters": {
        "url": "https://api.staging-provider.example.com/v1/render",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"image_base64\": \"{{ $json['Empty Room Photo'] }}\",\n  \"style\": \"Modern\",\n  \"output_types\": [\"staged_image\", \"3d_walkthrough\"]\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "38533782-3776-475f-b2f1-8a90a8fb749b",
      "name": "Fetch Comparable Listings & Market Data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2624,
        224
      ],
      "parameters": {
        "url": "=https://api.comps-provider.example.com/v1/comparables?address={{ encodeURIComponent($json['Property Address']) }}&beds={{ $json['Bedrooms'] }}&baths={{ $json['Bathrooms'] }}&sqft={{ $json['Square Feet'] }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7d5a274f-ebb5-4c17-85a8-cc3b9bbdd31f",
      "name": "Merge - Combine Staging & Comps Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        2960,
        96
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "b64c9bd3-5b0f-46aa-a868-253840c03e1f",
      "name": "JS - Build Property Baseline & Pricing Inputs",
      "type": "n8n-nodes-base.code",
      "position": [
        3280,
        96
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\nconst formData = $('Form - Upload Empty Room Photo').first().json;\n\nconst stagedImageUrl = item.stagedImageUrl || item.staged_image_url || '';\nconst walkthrough3dUrl = item.walkthrough3dUrl || item['3d_walkthrough_url'] || '';\nconst styleApplied = item.styleApplied || item.style || 'Modern';\n\nconst comparables = item.comparables || item.comps || [];\n\nconst prices = comparables\n  .map(c => parseFloat(c.price))\n  .filter(p => !isNaN(p) && p > 0);\n\nconst avgCompPrice = prices.length\n  ? Math.round(prices.reduce((sum, p) => sum + p, 0) / prices.length)\n  : null;\n\nconst pricePerSqftValues = comparables\n  .map(c => {\n    const p = parseFloat(c.price);\n    const s = parseFloat(c.squareFeet || c.sqft);\n    return (!isNaN(p) && !isNaN(s) && s > 0) ? p / s : null;\n  })\n  .filter(v => v !== null);\n\nconst avgPricePerSqft = pricePerSqftValues.length\n  ? Math.round((pricePerSqftValues.reduce((sum, v) => sum + v, 0) / pricePerSqftValues.length) * 100) / 100\n  : null;\n\nconst squareFeet = parseFloat(formData['Square Feet']) || 0;\n\nconst estimatedValueFromComps = avgPricePerSqft && squareFeet\n  ? Math.round(avgPricePerSqft * squareFeet)\n  : avgCompPrice;\n\nconst suggestedPriceLow = estimatedValueFromComps ? Math.round(estimatedValueFromComps * 0.97) : null;\nconst suggestedPriceHigh = estimatedValueFromComps ? Math.round(estimatedValueFromComps * 1.03) : null;\n\nreturn {\n  json: {\n    address: formData['Property Address'],\n    propertyType: formData['Property Type'],\n    bedrooms: parseInt(formData['Bedrooms'], 10) || 0,\n    bathrooms: parseFloat(formData['Bathrooms']) || 0,\n    squareFeet,\n    stagedImageUrl, walkthrough3dUrl, styleApplied,\n    comparableCount: comparables.length,\n    avgCompPrice, avgPricePerSqft,\n    suggestedPriceLow, suggestedPriceHigh, estimatedValueFromComps\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "78800387-6498-4131-b7a1-96176f87cc0e",
      "name": "Wait For Staging & Comps Buffer",
      "type": "n8n-nodes-base.wait",
      "position": [
        3600,
        96
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "e2368acd-19cf-4ca9-933d-40127e0c6ab9",
      "name": "AI - Generate Listing Copy & Price Recommendation",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        3984,
        96
      ],
      "parameters": {
        "text": "=You are a real estate copywriter creating a listing from a newly staged room render and comparable-sales pricing data.\n\nProperty:\nAddress: {{ $json.address }}\nType: {{ $json.propertyType }}\nBedrooms: {{ $json.bedrooms }} | Bathrooms: {{ $json.bathrooms }} | Square Feet: {{ $json.squareFeet }}\nStaging Style Applied: {{ $json.styleApplied }}\n\nComp-Based Pricing ({{ $json.comparableCount }} comparables):\nAverage Comp Price: ${{ $json.avgCompPrice }}\nAverage Price per Sqft: ${{ $json.avgPricePerSqft }}\nEstimated Value: ${{ $json.estimatedValueFromComps }}\nSuggested Price Range: ${{ $json.suggestedPriceLow }} - ${{ $json.suggestedPriceHigh }}\n\nWrite a compelling MLS-style listing based on this data.\n\nReturn a JSON object with EXACTLY these fields:\n{\n  \"listingTitle\": \"short punchy headline, under 12 words\",\n  \"listingDescription\": \"3-4 sentence listing description highlighting the staged look and property features\",\n  \"keySellingPoints\": [\"point 1\", \"point 2\", \"point 3\"],\n  \"suggestedListPrice\": number, choose a single price within the suggested range\n}\n\nReturn ONLY the JSON. No markdown, no explanation.",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 1.6
    },
    {
      "id": "3286b901-ae22-4ef8-88ac-8254686e0188",
      "name": "Anthropic - Copywriting Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        3856,
        240
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-20250514"
        },
        "options": {
          "temperature": 0.4
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "3b27dfe0-aa4e-48fa-afa8-cda6bcb0eae3",
      "name": "JS - Parse AI Output & Format Listing Copy",
      "type": "n8n-nodes-base.code",
      "position": [
        4416,
        96
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\nlet parsed = {};\ntry {\n  const rawText = item.output || item.text || item.response || '{}';\n  const clean = rawText.replace(/```json|```/g, '').trim();\n  parsed = JSON.parse(clean);\n} catch (e) {\n  const price = item.estimatedValueFromComps || item.avgCompPrice || 0;\n  parsed = {\n    listingTitle: `${item.propertyType} at ${item.address}`,\n    listingDescription: `This ${item.bedrooms}-bed, ${item.bathrooms}-bath ${item.propertyType.toLowerCase()} at ${item.address} has been beautifully staged in a ${item.styleApplied} style. Based on ${item.comparableCount} nearby comparables, it's priced to move.`,\n    keySellingPoints: [\n      `${item.squareFeet} square feet of living space`,\n      `Freshly staged in a ${item.styleApplied} style`,\n      `Priced using ${item.comparableCount} nearby comparable sales`\n    ],\n    suggestedListPrice: price\n  };\n}\n\nreturn {\n  json: {\n    ...item,\n    ...parsed\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "fdad79b0-514a-468a-92ef-a337921190ce",
      "name": "JS - Assemble Final Listing Package",
      "type": "n8n-nodes-base.code",
      "position": [
        4816,
        96
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item.json;\n\nconst packageGeneratedAt = new Date().toISOString();\nconst sellingPointsText = (item.keySellingPoints || [])\n  .map(p => `- ${p}`)\n  .join('\\n');\n\nconst listingPackageBody = `${item.listingTitle}\\nGenerated: ${packageGeneratedAt}\\n\\n${item.address}\\n${item.propertyType} | ${item.bedrooms} bed | ${item.bathrooms} bath | ${item.squareFeet} sqft\\n\\nStaged Photo: ${item.stagedImageUrl}\\n3D Walkthrough: ${item.walkthrough3dUrl}\\nStaging Style: ${item.styleApplied}\\n\\n${item.listingDescription}\\n\\nKey Selling Points:\\n${sellingPointsText}\\n\\nComp-Based Pricing (${item.comparableCount} comparables):\\nAverage Comp Price: $${item.avgCompPrice}\\nAverage Price/Sqft: $${item.avgPricePerSqft}\\nSuggested Range: $${item.suggestedPriceLow} - $${item.suggestedPriceHigh}\\n\\nSuggested List Price: $${item.suggestedListPrice}`;\n\nreturn {\n  json: {\n    ...item,\n    packageGeneratedAt,\n    listingPackageBody\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "240c383f-da9e-43ea-bf2d-3898be7c762d",
      "name": "Send Full Listing Package Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        5232,
        96
      ],
      "parameters": {
        "options": {},
        "subject": "=New Listing Ready: {{ $json.listingTitle }} - ${{ $json.suggestedListPrice }}",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "af8ff22a-f9af-4ca2-a2bd-eec6e0815fbb",
      "name": "Wait For Result",
      "type": "n8n-nodes-base.wait",
      "position": [
        5024,
        96
      ],
      "parameters": {},
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "e61fb86b-0723-4171-821e-06ea29c208a3",
  "nodeGroups": [],
  "connections": {
    "Wait For Result": {
      "main": [
        [
          {
            "node": "Send Full Listing Package Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic - Copywriting Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI - Generate Listing Copy & Price Recommendation",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Form - Upload Empty Room Photo": {
      "main": [
        [
          {
            "node": "Fetch AI Virtual Staging Render",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Comparable Listings & Market Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch AI Virtual Staging Render": {
      "main": [
        [
          {
            "node": "Merge - Combine Staging & Comps Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait For Staging & Comps Buffer": {
      "main": [
        [
          {
            "node": "AI - Generate Listing Copy & Price Recommendation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Assemble Final Listing Package": {
      "main": [
        [
          {
            "node": "Wait For Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge - Combine Staging & Comps Data": {
      "main": [
        [
          {
            "node": "JS - Build Property Baseline & Pricing Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Comparable Listings & Market Data": {
      "main": [
        [
          {
            "node": "Merge - Combine Staging & Comps Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "JS - Parse AI Output & Format Listing Copy": {
      "main": [
        [
          {
            "node": "JS - Assemble Final Listing Package",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JS - Build Property Baseline & Pricing Inputs": {
      "main": [
        [
          {
            "node": "Wait For Staging & Comps Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI - Generate Listing Copy & Price Recommendation": {
      "main": [
        [
          {
            "node": "JS - Parse AI Output & Format Listing Copy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}