{
  "version": "1.0.0",
  "exported_at": "2026-05-31T07:45:00.000Z",
  "project": {
    "name": "Google Maps Listings Scraper by URLs",
    "description": "Scrapes Google Maps listing/search result pages by URL. The workflow opens each Google Maps URL in navigate.urls, maximizes the browser window, dismisses common Google consent prompts if present, clicks the Google Maps Back button when a search URL opens a selected place panel, dynamically scrolls the results feed when one is visible, prepares extraction rows, and exports business listing cards to CSV. Important fix: only cards inside div[role='feed'] are treated as listings, so nested place-page cards such as 'At this place' are not exported as false listings. If Google still redirects directly to a single place detail page, the template falls back to extracting the main visible place record. Best-effort template: Google Maps may show CAPTCHA, consent screens, localized UI text, redirect searches to single places, or omit phone/website fields depending on query, region, and session.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "set-window-size-1",
      "block_type": "process",
      "title": "Set Window Size",
      "description": "Set browser window dimensions",
      "position_x": 120,
      "position_y": 160,
      "config": {
        "width": 1920,
        "height": 1200,
        "color": "bg-[#4589ff]"
      }
    },
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 480,
      "position_y": 160,
      "config": {
        "urls": [
          "https://www.google.com/maps/search/?api=1&query=Pizza%20Hut%20in%20London%2C%20UK&hl=en"
        ],
        "color": "bg-[#4589ff]"
      }
    },
    {
      "block_id": "wait-for-page-load-1",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 840,
      "position_y": 160,
      "config": {
        "timeout": 45,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1200,
      "position_y": 160,
      "config": {
        "jsCode": "Array.from(document.querySelectorAll('button')).find(b => /^(Accept all|I agree|Accept)$/i.test((b.textContent || '').trim()))?.click(); window.__uscraperGmapsScrollCount = 0; document.querySelectorAll('[data-uscraper-scroll-marker],.uscraper-gmap-row,#uscraper-gmap-row-holder').forEach(el => el.remove()); return true;",
        "waitForCompletion": true,
        "timeout": 5,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 1560,
      "position_y": 160,
      "config": {
        "selector": "div[role=\"feed\"] div[role=\"article\"], h1.DUwDvf, h1",
        "timeout": 60,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-4",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1920,
      "position_y": 160,
      "config": {
        "jsCode": "(function(){ const feedCards=document.querySelectorAll('div[role=\"feed\"] div[role=\"article\"]').length; const hasPlaceHeader=!!document.querySelector('h1.DUwDvf,h1'); if(feedCards>1) return {clicked:false,reason:'feed already visible',feedCards}; const buttons=Array.from(document.querySelectorAll('button')); const back=buttons.find(b=>/back/i.test(b.getAttribute('aria-label')||'')) || buttons.find(b=>((b.textContent||'').trim()==='')); if(back && hasPlaceHeader && location.href.includes('/maps/place/')){ back.click(); return {clicked:true,reason:'clicked maps back button'}; } return {clicked:false,reason:'no useful back button',feedCards,hasPlaceHeader,url:location.href}; })();",
        "waitForCompletion": true,
        "timeout": 8,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 2280,
      "position_y": 160,
      "config": {
        "duration": 3,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-2",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 2640,
      "position_y": 160,
      "config": {
        "selector": "div[role=\"feed\"] div[role=\"article\"], h1.DUwDvf, h1",
        "timeout": 30,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-2",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1560,
      "position_y": 780,
      "config": {
        "jsCode": "(function(){ const markerText = 'USCRAPER_SCROLL_DONE'; document.querySelectorAll('[data-uscraper-scroll-marker]').forEach(el => el.remove()); window.__uscraperGmapsScrollCount = (window.__uscraperGmapsScrollCount || 0) + 1; const bodyText = document.body ? document.body.innerText || '' : ''; const hasGoogleEndText = /you['’]?ve reached the end of the list/i.test(bodyText); const feed = document.querySelector('div[role=\"feed\"]'); const listingCardsFound = feed ? feed.querySelectorAll('div[role=\"article\"]').length : 0; const scrollables = Array.from(document.querySelectorAll('div')).filter(el => { const style = window.getComputedStyle(el); const rect = el.getBoundingClientRect(); return rect.height > 250 && el.scrollHeight > el.clientHeight + 250 && style.visibility !== 'hidden' && style.display !== 'none'; }).sort((a,b) => (b.scrollHeight - b.clientHeight) - (a.scrollHeight - a.clientHeight)); const scroller = feed || scrollables[0] || document.scrollingElement || document.documentElement; const hasPlacePage = !!document.querySelector('h1.DUwDvf, h1'); if (scroller) { try { scroller.scrollTop = (scroller.scrollTop || 0) + 3200; scroller.dispatchEvent(new Event('scroll', { bubbles: true })); } catch(e) { window.scrollBy(0, 3200); } } else { window.scrollBy(0, 3200); } const maxScrollReached = window.__uscraperGmapsScrollCount >= (feed ? 25 : 3); if (hasGoogleEndText || maxScrollReached || (!feed && hasPlacePage)) { const marker = document.createElement('div'); marker.setAttribute('data-uscraper-scroll-marker', 'true'); marker.textContent = markerText; marker.style.cssText = 'position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;overflow:hidden;'; document.body.appendChild(marker); } return { scrollCount: window.__uscraperGmapsScrollCount, feedFound: !!feed, listingCardsFound: listingCardsFound, placePage: hasPlacePage, endText: hasGoogleEndText }; })();",
        "waitForCompletion": true,
        "timeout": 10,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1920,
      "position_y": 780,
      "config": {
        "duration": 2,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "text-contains-1",
      "block_type": "process",
      "title": "Text Contains",
      "description": "Check if page contains text",
      "position_x": 2280,
      "position_y": 500,
      "config": {
        "text": "USCRAPER_SCROLL_DONE",
        "selector": "body",
        "caseSensitive": false,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "inject-javascript-3",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 2640,
      "position_y": 500,
      "config": {
        "jsCode": "(function(){document.querySelectorAll('.uscraper-gmap-row,#uscraper-gmap-row-holder').forEach(e=>e.remove());const feed=document.querySelector('div[role=\"feed\"]');let cards=feed?Array.from(feed.querySelectorAll('div[role=\"article\"]')).filter(c=>{const t=(c.innerText||'').trim();return t.length>0&&(c.querySelector('a.hfpxzc[href],a[href*=\"/maps/place/\"]')||c.getAttribute('aria-label')||c.querySelector('.qBF1Pd'));}):[];const unique=[];const seen=new Set();for(const c of cards){const key=(c.querySelector('a.hfpxzc[href],a[href*=\"/maps/place/\"]')?.href||c.getAttribute('aria-label')||c.innerText.slice(0,160));if(!seen.has(key)){seen.add(key);unique.push(c);}}cards=unique;const mode=cards.length?'listing':'place';const count=cards.length||(document.querySelector('h1.DUwDvf,h1')?1:0);const holder=document.createElement('div');holder.id='uscraper-gmap-row-holder';holder.style.cssText='display:none';for(let i=0;i<count;i++){const d=document.createElement('div');d.className='uscraper-gmap-row';d.setAttribute('data-index',String(i));d.setAttribute('data-mode',mode);holder.appendChild(d);}document.body.appendChild(holder);function clean(s){return (s||'').replace(/\\s+/g,' ').trim();}function hrefTarget(h){try{if(!h)return '';if(h.includes('/url?')){const u=new URL(h);return u.searchParams.get('q')||h;}return h;}catch(e){return h||'';}}function rowObj(row){const idx=parseInt(row.getAttribute('data-index')||'0',10);return mode==='listing'?(cards[idx]||document.body):document.body;}function header(){return document.querySelector('.TIHn2')||document.querySelector('[role=\"main\"]')||document.body;}function listingName(R){return clean(R.getAttribute('aria-label')||R.querySelector('.qBF1Pd')?.textContent||R.querySelector('a.hfpxzc')?.getAttribute('aria-label')||R.querySelector('[role=\"heading\"]')?.textContent||'');}function placeUrlFrom(R,isPlace){if(!isPlace)return R.querySelector('a.hfpxzc[href],a[href*=\"/maps/place/\"]')?.href||'';return location.href;}function coords(url,which){let m=(url||'').match(/!3d(-?\\d+(?:\\.\\d+)?).*?!4d(-?\\d+(?:\\.\\d+)?)/);if(m)return which==='lat'?m[1]:m[2];m=(url||'').includes('/maps/place/')?(url||'').match(/@(-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?)/):null;return m?(which==='lat'?m[1]:m[2]):'';}function visiblePlaceAddress(){let a=document.querySelector('[data-item-id=\"address\"] .Io6YTe')?.textContent||document.querySelector('button[data-item-id=\"address\"]')?.getAttribute('aria-label')||document.querySelector('.MngOvd [data-tooltip=\"Copy address\"] .JpCtJf .DkEaL')?.textContent||document.querySelector('.MngOvd .JpCtJf .DkEaL')?.textContent||'';return clean(a.replace(/^Address:\\s*/i,''));}function visiblePlaceStatus(){let s=document.querySelector('[data-item-id=\"oh\"] .Io6YTe')?.textContent||document.querySelector('button[data-item-id=\"oh\"]')?.getAttribute('aria-label')||'';return clean(s);}window.__gmapsField=function(row,field){try{const R=rowObj(row);const isPlace=row.getAttribute('data-mode')==='place';const H=header();const text=R.innerText||'';const flat=clean(text);const purl=placeUrlFrom(R,isPlace);if(field==='original_url')return location.href;if(field==='keyword'){const m=location.href.match(/\\/maps\\/search\\/([^/@?]+)/);if(m)return decodeURIComponent(m[1].replace(/\\+/g,' '));const q=new URL(location.href).searchParams.get('query')||'';return q?decodeURIComponent(q.replace(/\\+/g,' ')):(document.querySelector('input#searchboxinput,input[aria-label*=\"Search\"]')?.value||'');}if(field==='name')return isPlace?clean(document.querySelector('h1.DUwDvf,h1')?.textContent||''):listingName(R);if(field==='rating'){if(isPlace){const v=H.querySelector('.F7nice span[aria-hidden=\"true\"], .F7nice .MW4etd')?.textContent||'';return clean((v.match(/\\d\\.\\d/)||[])[0]||v);}return clean(R.querySelector('.MW4etd')?.textContent||((text.match(/\\b\\d\\.\\d\\b/)||[])[0]||''));}if(field==='review_count'){if(isPlace){let v=H.querySelector('.F7nice [aria-label*=\"review\" i]')?.getAttribute('aria-label')||H.querySelector('.F7nice')?.textContent||'';let m=v.match(/[\\d,]+(?=\\s*reviews?)/i)||v.match(/\\(([\\d,]+)\\)/);return m?(m[1]||m[0]).replace(/[()]/g,''):'';}let v=R.querySelector('.UY7F9')?.textContent||R.querySelector('[aria-label*=\"review\" i]')?.getAttribute('aria-label')||'';let m=v.match(/[\\d,]+/);if(m)return m[0];m=text.match(/\\(([\\d,]+)\\)/);return m?m[1]:'';}if(field==='price_range'){const source=isPlace?(H.innerText||''):text;const m=source.match(/(?:£|\\$){1,4}(?:\\s?\\d+\\s?[–-]\\s?\\d+)?|£\\d+\\s?[–-]\\s?\\d+/);return m?m[0]:'';}if(field==='category'){if(isPlace)return clean(H.querySelector('.LBgpqf button[jsaction*=\"category\"], .LBgpqf button.DkEaL')?.textContent||'');const name=listingName(R);const parts=flat.split('·').map(clean).filter(Boolean);return parts.find(p=>p!==name&&!/review|stars?|open|closed|opens|closes|website|directions|menu|order|call|route|^\\(?[\\d,]+\\)?$|^(£|\\$)/i.test(p)&&p.length<60&&!/\\d+\\s+(street|st\\b|road|rd\\b|avenue|ave\\b|square|sq\\b|lane|ln\\b|drive|dr\\b|way|place|pl\\b|row|hill|strand)/i.test(p))||'';}if(field==='address'){if(isPlace)return visiblePlaceAddress();const parts=flat.split('·').map(clean).filter(Boolean);const c=parts.filter(p=>!/open|closed|opens|closes|website|directions|menu|order|call|stars?|reviews?/i.test(p)&&/\\d|street|st\\b|road|rd\\b|avenue|ave\\b|square|sq\\b|lane|ln\\b|drive|dr\\b|way|place|pl\\b|boulevard|blvd|row|hill|strand/i.test(p));return c[c.length-1]||'';}if(field==='latitude')return coords(purl,'lat');if(field==='longitude')return coords(purl,'lng');if(field==='current_status'){const source=isPlace?visiblePlaceStatus():text;const m=source.match(/\\b(Open 24 hours|Open|Closed|Temporarily closed|Permanently closed)\\b/i);return m?m[1]:'';}if(field==='next_status'){const source=isPlace?visiblePlaceStatus():clean(text);const m=source.match(/\\b(?:Opens|Closes)\\s+[^·\\n]+/i);return m?clean(m[0]):'';}if(field==='scraped_at')return new Date().toISOString();if(field==='website'){const scope=isPlace?document:R;let preferred=scope.querySelector('[data-item-id=\"authority\"] a[href], a[data-item-id=\"authority\"][href]');let links=Array.from(scope.querySelectorAll('a[href]'));let a=preferred||links.find(a=>/website|visit website/i.test((a.getAttribute('aria-label')||'')+' '+(a.textContent||'')))||links.find(a=>/google\\.com\\/url\\?q=/.test(a.href)&&!/maps\\/(place|dir)|accounts\\.google|support\\.google|business\\.google|contrib|tel:/i.test(a.href));let href=hrefTarget(a?a.href:'');if(/business\\.google|accounts\\.google|support\\.google|google\\.com\\/maps|^tel:/i.test(href))return '';return href;}if(field==='telephone'){const scope=isPlace?document:R;const tel=scope.querySelector('a[href^=\"tel:\"]')?.getAttribute('href');if(tel)return tel.replace(/^tel:/,'').trim();let phone=scope.querySelector('[data-item-id^=\"phone\"] .Io6YTe, button[data-item-id^=\"phone\"]')?.textContent||scope.querySelector('button[data-item-id^=\"phone\"]')?.getAttribute('aria-label')||'';phone=phone.replace(/^Phone:\\s*/i,'');if(clean(phone))return clean(phone);const m=text.match(/(?:\\+?\\d[\\d\\s().-]{7,}\\d)/);return m?m[0].trim():'';}if(field==='tags'){const source=isPlace?(document.querySelector('.E0DTEd')?.innerText||document.body.innerText||''):text;return ['Dine-in','Curbside pickup','No-contact delivery','Delivery','Takeout','Takeaway','Outdoor seating','Wheelchair accessible','Order online','Collection','LGBTQ+ friendly'].filter(x=>new RegExp(x,'i').test(source)).join('·');}if(field==='detail_url')return purl||location.href;return '';}catch(e){return '';}};return {mode:mode,count:count,cards:cards.length};})();",
        "waitForCompletion": true,
        "timeout": 10,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 3000,
      "position_y": 160,
      "config": {
        "rowSelector": ".uscraper-gmap-row",
        "fileName": "google-maps-scraper-listing-page-by-url.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "original_url",
            "selector": "window.__gmapsField(ROW,'original_url')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "keyword",
            "selector": "window.__gmapsField(ROW,'keyword')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "name",
            "selector": "window.__gmapsField(ROW,'name')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating",
            "selector": "window.__gmapsField(ROW,'rating')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "review_count",
            "selector": "window.__gmapsField(ROW,'review_count')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "price_range",
            "selector": "window.__gmapsField(ROW,'price_range')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "category",
            "selector": "window.__gmapsField(ROW,'category')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "address",
            "selector": "window.__gmapsField(ROW,'address')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "latitude",
            "selector": "window.__gmapsField(ROW,'latitude')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "longitude",
            "selector": "window.__gmapsField(ROW,'longitude')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "current_status",
            "selector": "window.__gmapsField(ROW,'current_status')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "next_status",
            "selector": "window.__gmapsField(ROW,'next_status')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "scraped_at",
            "selector": "window.__gmapsField(ROW,'scraped_at')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "website",
            "selector": "window.__gmapsField(ROW,'website')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "telephone",
            "selector": "window.__gmapsField(ROW,'telephone')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "tags",
            "selector": "window.__gmapsField(ROW,'tags')",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "detail_url",
            "selector": "window.__gmapsField(ROW,'detail_url')",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 3360,
      "position_y": 160,
      "config": {
        "color": "bg-[#8d8d8d]"
      }
    }
  ],
  "connections": [
    {
      "from_block_id": "set-window-size-1",
      "from_connector_id": "right",
      "to_block_id": "navigate-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "navigate-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-page-load-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-page-load-1",
      "from_connector_id": "right",
      "to_block_id": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-1",
      "from_connector_id": "right",
      "to_block_id": "inject-javascript-4",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-4",
      "from_connector_id": "right",
      "to_block_id": "sleep-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-2",
      "from_connector_id": "right",
      "to_block_id": "wait-for-element-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-2",
      "from_connector_id": "right",
      "to_block_id": "inject-javascript-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-2",
      "from_connector_id": "right",
      "to_block_id": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-1",
      "from_connector_id": "right",
      "to_block_id": "text-contains-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "text-contains-1",
      "from_connector_id": "true",
      "to_block_id": "inject-javascript-3",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "text-contains-1",
      "from_connector_id": "false",
      "to_block_id": "inject-javascript-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-3",
      "from_connector_id": "right",
      "to_block_id": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-1",
      "from_connector_id": "right",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-entry",
      "element_type": "group",
      "title": "Entry & Setup",
      "color": "#4589ff",
      "position_x": 48,
      "position_y": 56,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "set-window-size-1"
        ]
      }
    },
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 408,
      "position_y": 56,
      "width": 2480,
      "height": 916,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "wait-for-element-1",
          "sleep-2",
          "wait-for-element-2",
          "sleep-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1128,
      "position_y": 56,
      "width": 1760,
      "height": 916,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1",
          "inject-javascript-4",
          "inject-javascript-2",
          "inject-javascript-3"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 2208,
      "position_y": 56,
      "width": 1400,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "text-contains-1",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2928,
      "position_y": 56,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Google Maps listing/search result pages by URL. The workflow opens each Google Maps URL in navigate.urls, maximizes the browser window, dismisses common Google consent prompts if present, clicks the Google Maps Back button when a search URL opens a selected place panel, dynamically scrolls the results feed when one is visible, prepares extraction rows, and exports business listing cards to CSV. Important fix: only cards inside div[role='feed'] are treated as listings, so nested place-page cards such as 'At this place' are not exported as false listings. If Google still redirects directly to a single place detail page, the template falls back to extracting the main visible place record. Best-effort template: Google Maps may show CAPTCHA, consent screens, localized UI text, redirect searches to single places, or omit phone/website fields depending on query, region, and session.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `Array.from(document.querySelectorAll('button')).find(b => /^(Accept all|I agree|Accept)$/i.test((b.t...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 140,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-1"
      }
    },
    {
      "id": "note-block-inject-javascript-4",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(function(){ const feedCards=document.querySelectorAll('div[role=\"feed\"] div[role=\"article\"]').lengt...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 140,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-4"
      }
    },
    {
      "id": "note-block-inject-javascript-2",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(function(){ const markerText = 'USCRAPER_SCROLL_DONE'; document.querySelectorAll('[data-uscraper-sc...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 760,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-2"
      }
    },
    {
      "id": "note-block-text-contains-1",
      "element_type": "note",
      "title": "Note: Text Contains",
      "content": "Condition block: checks `body`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 2480,
      "position_y": 480,
      "width": 340,
      "height": 131,
      "z_index": 22,
      "data": {
        "block_id": "text-contains-1"
      }
    },
    {
      "id": "note-block-inject-javascript-3",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(function(){document.querySelectorAll('.uscraper-gmap-row,#uscraper-gmap-row-holder').forEach(e=>e.r...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 2840,
      "position_y": 480,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-3"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (original_url, keyword, name, rating, review_count). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 3200,
      "position_y": 140,
      "width": 340,
      "height": 130,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-loop-continue-1",
      "element_type": "note",
      "title": "Note: Loop Continue",
      "content": "Loop Continue advances a multi-URL or multi-text loop. Place at the end of the loop body with a clear back-edge to the loop start.",
      "color": "#ee5396",
      "position_x": 3560,
      "position_y": 140,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}