[object Object]

← back to Commercialrealestate

CRE: reroute fetch-sfr-redfin off Browserbase to local Chrome ($0)

98859708651f58d6e13f1fe71aba504af2ded64b · 2026-08-18 12:03:23 -0700 · Steve Abrams

TK-10655 follow-up (Steve approved the residual). Same one-line default flip as
its condo sibling: LOCAL is now the default (CC_LOCAL=0 opts back into paid
Browserbase); SDK + creds lazy-loaded only on the paid path. Residential IP
clears Redfin's gis-csv wall. Completes the Browserbase->local reroute across
all CRE Redfin scrapers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 98859708651f58d6e13f1fe71aba504af2ded64b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Aug 18 12:03:23 2026 -0700

    CRE: reroute fetch-sfr-redfin off Browserbase to local Chrome ($0)
    
    TK-10655 follow-up (Steve approved the residual). Same one-line default flip as
    its condo sibling: LOCAL is now the default (CC_LOCAL=0 opts back into paid
    Browserbase); SDK + creds lazy-loaded only on the paid path. Residential IP
    clears Redfin's gis-csv wall. Completes the Browserbase->local reroute across
    all CRE Redfin scrapers.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 scripts/fetch-sfr-redfin.js | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/scripts/fetch-sfr-redfin.js b/scripts/fetch-sfr-redfin.js
index 415368b..9415034 100644
--- a/scripts/fetch-sfr-redfin.js
+++ b/scripts/fetch-sfr-redfin.js
@@ -3,7 +3,8 @@
 // Same gis-csv feed that cracked the condo sweep (fetch-condos-redfin.js) but uipt=1 (single-family
 // detached) instead of uipt=3 (condo). status=9 = active for-sale. For each resolved LA region
 // (data/redfin-regions.json cities + redfin-neighborhoods.json hoods, 229 region_ids) we warm ONE
-// Browserbase session and fetch the gis-csv feed in-page, then upsert each SFR into cre.sfr.
+// LOCAL real-Chrome session (default; residential IP, $0 — TK-10655) and fetch the gis-csv feed
+// in-page, then upsert each SFR into cre.sfr. CC_LOCAL=0 opts back into paid Browserbase.
 //
 //   /stingray/api/gis-csv?al=1&region_id=<id>&region_type=<6 city|1 hood>&uipt=1&num_homes=350&status=9
 //
@@ -25,18 +26,22 @@
 const fs = require('fs');
 const path = require('path');
 const { chromium } = require('playwright-core');
-const Browserbase = require('@browserbasehq/sdk').default;
 const { Pool } = require('pg');
 const { inLACounty } = require('./sources/la-county');
 
-const bbEnv = fs.readFileSync(process.env.HOME + '/.claude/skills/browserbase/.env', 'utf8');
 const get = (t, k) => (t.match(new RegExp('^' + k + '=(.*)$', 'm')) || [])[1]?.replace(/['"]/g, '').trim();
 const ROOT = path.join(__dirname, '..');
 const pool = new Pool({ host: '/tmp', port: 5432, database: 'cre', user: process.env.USER || 'stevestudio2' });
 
-// CC_LOCAL=1 launches local Chrome (residential IP clears Redfin) instead of a paid Browserbase
-// session — $0/run. Same in-page gis-csv fetch; only the browser transport differs.
-const LOCAL = process.env.CC_LOCAL === '1';
+// LOCAL is now the DEFAULT (TK-10655, prefer-local rule): drive the local Google Chrome (residential
+// IP clears Redfin's bot wall) at $0/run. Opt back into paid Browserbase ONLY with CC_LOCAL=0.
+// Same in-page gis-csv fetch; only the browser transport differs. Browserbase creds/SDK are loaded
+// lazily below and ONLY when CC_LOCAL=0, so a default local run needs no browserbase .env present.
+const LOCAL = process.env.CC_LOCAL !== '0';
+function bbCreds() {
+  const bbEnv = fs.readFileSync(process.env.HOME + '/.claude/skills/browserbase/.env', 'utf8');
+  return { KEY: get(bbEnv, 'BROWSERBASE_API_KEY'), PROJECT: get(bbEnv, 'BROWSERBASE_PROJECT_ID') };
+}
 const CHROME_PATH = process.env.CHROME_PATH || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
 const SESSION_COST = LOCAL ? 0 : 0.04;
 const MAX_SESSIONS = +(process.env.CC_MAX_SESSIONS || (LOCAL ? 999 : 30));
@@ -187,8 +192,12 @@ function loadRegions() {
       if (LOCAL) {
         browser = await chromium.launch({ executablePath: CHROME_PATH, args: ['--disable-blink-features=AutomationControlled'] });
       } else {
-        const bb = new Browserbase({ apiKey: get(bbEnv, 'BROWSERBASE_API_KEY') });
-        session = await bb.sessions.create({ projectId: get(bbEnv, 'BROWSERBASE_PROJECT_ID'), browserSettings: { solveCaptchas: true, viewport: { width: 1440, height: 1000 } } });
+        // Paid fallback, opt-in only (CC_LOCAL=0). SDK + creds loaded lazily so a default local run
+        // never touches Browserbase.
+        const Browserbase = require('@browserbasehq/sdk').default;
+        const { KEY, PROJECT } = bbCreds();
+        const bb = new Browserbase({ apiKey: KEY });
+        session = await bb.sessions.create({ projectId: PROJECT, browserSettings: { solveCaptchas: true, viewport: { width: 1440, height: 1000 } } });
         browser = await chromium.connectOverCDP(session.connectUrl);
       }
       const ctx = browser.contexts()[0] || await browser.newContext({ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', viewport: { width: 1440, height: 1000 } });

← 9ac1e11 Fix mls.html empty grid: relative fetch() threw on credentia  ·  back to Commercialrealestate  ·  Apply credential-safe fetch wrapper fleet-wide (22 CRCP page d6f3dbf →