Real Estate Lead Nurture
Module 19 · business · intermediate
parse.js
// Turn any inquiry into one clean lead: structured JSON, a pasted portal email, or the Gmail trigger.
const viaApi = $('New Lead API').isExecuted;
const src = viaApi ? $('New Lead API').first().json : $('Portal Lead Emails').first().json;
const b = viaApi ? src.body ?? {} : {};
// Raw email text (API "raw_email" or Gmail trigger)
const from = viaApi ? String(b.from ?? '') : String(src.from?.value?.[0]?.address ?? src.from ?? '');
const subject = viaApi ? String(b.subject ?? '') : String(src.subject ?? '');
const raw = viaApi ? String(b.raw_email ?? '') : String(src.text ?? src.snippet ?? '');
const all = `${subject}\n${raw}`;
const field = (label) => (raw.match(new RegExp(`^\\s*${label}\\s*[:\\-]\\s*(.+)$`, 'im'))?.[1] ?? '').trim();
const name = String(b.name ?? '').trim() || field('Name') || field('From');
const email = (String(b.email ?? '').trim() || field('Email') || (raw.match(/[\w.+-]+@[\w-]+\.[\w.-]+/)?.[0] ?? '')).toLowerCase();
let phone = (String(b.phone ?? '') || field('Phone') || (raw.match(/\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}/)?.[0] ?? '')).replace(/[^\d+]/g, '');
if (/^\d{10}$/.test(phone)) phone = '+1' + phone;
if (/^1\d{10}$/.test(phone)) phone = '+' + phone;
const message = String(b.message ?? '').trim() || field('Message') || field('Comments');
const property = String(b.property ?? '').trim() || field('Property') || field('Listing') || (all.match(/\d{2,6} [A-Z][\w ]+? (?:St|Street|Ave|Avenue|Rd|Road|Dr|Drive|Ln|Lane|Blvd|Ct|Way)\b[^\n]*/)?.[0] ?? '').trim();
const listingId = String(b.listing_id ?? '').trim() || field('Listing ID') || (all.match(/\b(?:MLS|Listing)\s*#?\s*([A-Z0-9-]{4,})/i)?.[1] ?? '');
const text = `${message} ${subject} ${raw}`.toLowerCase();
const sourceHay = `${b.source ?? ''} ${from} ${subject}`.toLowerCase();
const source = ['zillow', 'realtor.com', 'homes.com', 'redfin', 'trulia'].find((s) => sourceHay.includes(s)) ?? (String(b.source ?? '').toLowerCase() || 'website');
const intent = /\b(rent|lease|rental)\b/.test(text) ? 'renter' : /(sell my|home value|what.?s my home worth|list my|selling)/.test(text) ? 'seller' : 'buyer';
const timeframe = (text.match(/\b(asap|this week|this month|next month|30 days|60 days|90 days|3 months|6 months|this year|just looking|browsing)\b/)?.[1]) ?? null;
return [{
json: {
name, first_name: name.split(' ')[0] || 'there', email, phone, message, property, listing_id: listingId,
source, intent, timeframe, pre_approved: /pre-?approved|preapproved/.test(text),
valid: Boolean(email || phone),
dry_run: viaApi && src.query?.dry_run === 'true',
via_api: viaApi,
received_at: DateTime.now().toISO(),
},
}];