{
  "version": "1.0.0",
  "exported_at": "2026-06-01T14:15:00.000Z",
  "project": {
    "name": "TripAdvisor Hotel Review Scraper for Italy",
    "description": "Scrapes Italian TripAdvisor hotel reviews from supplied Tripadvisor.it ShowUserReviews/hotel review URLs. Extracts hotel metadata, reviewer details, rating, review date, stay date, title, content, helpful votes, and extraction status. Navigation uses a multi-URL input loop plus a click-next pagination loop when TripAdvisor exposes additional review pages. TripAdvisor may show DataDome/CAPTCHA or return a 403 interstitial; when reviews are not visible, this template writes a diagnostic blocked-page row for the URL instead of producing no CSV.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated-tripadvisor-it-hotel-reviews"
  },
  "blocks": [
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 120,
      "position_y": 220,
      "config": {
        "urls": [
          "https://www.tripadvisor.it/ShowUserReviews-g187785-d1068538-r925759592-Decumani_Hotel_de_Charme-Naples_Province_of_Naples_Campania.html",
          "https://www.tripadvisor.it/ShowUserReviews-g187785-d1068538-r835317338-Decumani_Hotel_de_Charme-Naples_Province_of_Naples_Campania.html",
          "https://www.tripadvisor.it/ShowUserReviews-g187785-d1068538-r913856405-Decumani_Hotel_de_Charme-Naples_Province_of_Naples_Campania.html"
        ],
        "color": "bg-[#4589ff]",
        "tags": [
          "input-urls",
          "tripadvisor"
        ]
      }
    },
    {
      "block_id": "wait-for-page-load-1",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 480,
      "position_y": 220,
      "config": {
        "timeout": 45,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 840,
      "position_y": 220,
      "config": {
        "selector": "body",
        "timeout": 30,
        "visible": true,
        "color": "bg-[#08bdba]",
        "tags": [
          "page-body"
        ]
      }
    },
    {
      "block_id": "sleep-3",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "duration": 20,
        "color": "bg-[#08bdba]",
        "tags": [
          "captcha-manual-window"
        ]
      }
    },
    {
      "block_id": "element-exists-2",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "selector": "div[data-reviewid], div[id^=\"review_\"], div[data-automation=\"reviewCard\"], [data-test-target=\"HR_CC_CARD\"], [data-test-target=\"review-card\"], div.review-container, div.reviewSelector",
        "color": "bg-[#ff832b]",
        "tags": [
          "review-card-guard",
          "captcha-safe"
        ]
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1920,
      "position_y": 220,
      "config": {
        "jsCode": "(() => {\n  const labels = ['altro', 'leggi di più', 'leggi tutto', 'more', 'read more'];\n  const buttons = Array.from(document.querySelectorAll('button, a, span[role=\"button\"]'));\n  for (const el of buttons) {\n    const text = (el.innerText || el.textContent || '').trim().toLowerCase();\n    if (labels.some(label => text.includes(label))) {\n      try { el.click(); } catch (e) {}\n    }\n  }\n  return true;\n})()",
        "waitForCompletion": true,
        "timeout": 10,
        "color": "bg-[#a56eff]",
        "tags": [
          "expand-reviews"
        ]
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 2280,
      "position_y": 220,
      "config": {
        "duration": 2,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2640,
      "position_y": 220,
      "config": {
        "rowSelector": "div[data-reviewid], div[id^=\"review_\"], div[data-automation=\"reviewCard\"], [data-test-target=\"HR_CC_CARD\"], [data-test-target=\"review-card\"], div.review-container, div.reviewSelector",
        "fileName": "crawler-recensioni-hotel-tripadvisor.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "tags": [
          "reviews",
          "csv"
        ],
        "columns": [
          {
            "name": "pagina_attuale",
            "selector": "window.location.href",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "nome_hotel",
            "selector": "(() => { const candidates = [document.querySelector('h1')?.innerText, document.querySelector('[data-test-target=\"top-info-header\"]')?.innerText, document.querySelector('[data-automation=\"mainH1\"]')?.innerText, document.querySelector('meta[property=\"og:title\"]')?.content, document.title].filter(Boolean).map(v => String(v).trim()).filter(Boolean); const value = candidates[0] || ''; return value.replace(/\\s*-\\s*Tripadvisor.*$/i, '').replace(/\\s*Recensioni.*$/i, '').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "recensioni_totali",
            "selector": "(() => { const txt = document.body.innerText || ''; const m = txt.match(/([\\d\\.\\,]+\\s+recensioni)/i) || txt.match(/([\\d\\.\\,]+)\\s+reviews/i); return m ? m[1].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating_hotel",
            "selector": "(() => { const txt = document.body.innerText || ''; const candidates = Array.from(document.querySelectorAll('[aria-label*=\"su 5\"], [aria-label*=\"of 5\"]')).map(e => e.getAttribute('aria-label') || '').filter(Boolean); for (const aria of candidates) { const m = aria.match(/([0-5](?:[\\.,]\\d)?)/); if (m) return m[1].replace(',', '.'); } const m2 = txt.match(/([0-5](?:[\\.,]\\d)?)\\s*(?:su|\\/)\\s*5/i); return m2 ? m2[1].replace(',', '.') : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "nome_utente",
            "selector": "(() => { const selectors = ['[data-test-target=\"review-user-name\"]', 'a.ui_header_link', '.info_text .username', '.member_info .username', '[class*=\"username\"]', '[class*=\"userName\"]']; for (const s of selectors) { const el = ROW.querySelector(s); const text = el && (el.innerText || el.textContent || '').trim(); if (text) return text; } const lines = (ROW.innerText || '').split('\\n').map(s => s.trim()).filter(Boolean); return lines[0] || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "indirizzo_utente",
            "selector": "(() => { const selectors = ['[data-test-target=\"review-user-location\"]', '.userLoc', '.default .userLoc', '[class*=\"userLoc\"]', '[class*=\"location\"]']; for (const s of selectors) { const el = ROW.querySelector(s); const text = el && (el.innerText || el.textContent || '').trim(); if (text) return text; } return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating",
            "selector": "(() => { const ariaEl = ROW.querySelector('[aria-label*=\"su 5\"], [aria-label*=\"of 5\"]'); const aria = ariaEl ? ariaEl.getAttribute('aria-label') || '' : ''; let m = aria.match(/([0-5](?:[\\.,]\\d)?)/); if (m) return m[1].replace(',', '.'); const bubble = ROW.querySelector('[class*=\"bubble_\"]'); const cls = bubble ? String(bubble.className) : ''; m = cls.match(/bubble_(\\d+)/); if (m) return (parseInt(m[1], 10) / 10).toFixed(1); const svgTitle = ROW.querySelector('svg title'); const svgText = svgTitle ? svgTitle.textContent || '' : ''; m = svgText.match(/([0-5](?:[\\.,]\\d)?)/); return m ? m[1].replace(',', '.') : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "data_della_recensione",
            "selector": "(() => { const selectors = ['[data-test-target=\"review-date\"]', '.ratingDate', '[class*=\"ratingDate\"]', 'span[title]']; for (const s of selectors) { const el = ROW.querySelector(s); if (!el) continue; const text = (el.getAttribute('title') || el.innerText || el.textContent || '').trim(); if (text) return text.replace(/^Recensito\\s*/i, '').replace(/^Written\\s*/i, '').trim(); } const txt = ROW.innerText || ''; const m = txt.match(/\\b(\\d{1,2}\\s+[a-zàèéìòù]{3,}\\.?\\s*\\d{0,4}|gen\\s*\\d{4}|feb\\s*\\d{4}|mar\\s*\\d{4}|apr\\s*\\d{4}|mag\\s*\\d{4}|giu\\s*\\d{4}|lug\\s*\\d{4}|ago\\s*\\d{4}|set\\s*\\d{4}|ott\\s*\\d{4}|nov\\s*\\d{4}|dic\\s*\\d{4})\\b/i); return m ? m[1].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "data_del_soggiorno",
            "selector": "(() => { const txt = ROW.innerText || ''; const m = txt.match(/Data del soggiorno\\s*:?\\s*([^\\n]+)/i) || txt.match(/Periodo del soggiorno\\s*:?\\s*([^\\n]+)/i) || txt.match(/Soggiorno\\s*:?\\s*([^\\n]+)/i) || txt.match(/Date of stay\\s*:?\\s*([^\\n]+)/i); return m ? m[1].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "titolo",
            "selector": "(() => { const selectors = ['[data-test-target=\"review-title\"]', 'q[data-test-target=\"review-title\"]', '.quote a span', '.quote span', 'a[href*=\"ShowUserReviews\"] span']; for (const s of selectors) { const el = ROW.querySelector(s); const text = el && (el.innerText || el.textContent || '').trim(); if (text) return text; } return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "contenuto",
            "selector": "(() => { const selectors = ['[data-test-target=\"review-entry\"]', 'q[data-test-target=\"review-entry\"]', '.partial_entry', '[class*=\"reviewText\"]', '[class*=\"review-text\"]']; for (const s of selectors) { const el = ROW.querySelector(s); const text = el && (el.innerText || el.textContent || '').trim(); if (text) return text; } const lines = (ROW.innerText || '').split('\\n').map(s => s.trim()).filter(Boolean); return lines.slice(-3).join(' ').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "voto_utile",
            "selector": "(() => { const txt = ROW.innerText || ''; const m = txt.match(/(\\d+)\\s+(?:vot[io]\\s+util[ei]|utile|helpful vote|helpful votes)/i); return m ? m[1] : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "stato_estrazione",
            "selector": "'ok_review_extracted'",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 3000,
      "position_y": 220,
      "config": {
        "selector": "a[aria-label=\"Pagina successiva\"], a[aria-label=\"Avanti\"], a[aria-label=\"Next\"], a.nav.next:not(.disabled), a.next:not(.disabled)",
        "color": "bg-[#ff832b]",
        "tags": [
          "pagination"
        ]
      }
    },
    {
      "block_id": "structured-export-2",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1920,
      "position_y": 560,
      "config": {
        "rowSelector": "body",
        "fileName": "crawler-recensioni-hotel-tripadvisor.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#ff832b]",
        "tags": [
          "blocked-diagnostic",
          "csv"
        ],
        "columns": [
          {
            "name": "pagina_attuale",
            "selector": "window.location.href",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "nome_hotel",
            "selector": "(() => { const path = decodeURIComponent(location.pathname); const byReviewId = path.match(/-r\\d+-([^-\\/]+)-/i); const byDetailId = path.match(/-d\\d+-([^-\\/]+)-/i); const raw = (byReviewId && byReviewId[1]) || (byDetailId && byDetailId[1]) || ''; return raw.replace(/_/g, ' ').replace(/\\.html$/i, '').replace(/\\s+/g, ' ').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "recensioni_totali",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating_hotel",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "nome_utente",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "indirizzo_utente",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "data_della_recensione",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "data_del_soggiorno",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "titolo",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "contenuto",
            "selector": "(() => { const hasDataDome = !!document.querySelector('iframe[src*=\"captcha-delivery\"], script[src*=\"captcha-delivery\"], iframe[title*=\"DataDome\"]'); const bodyText = (document.body.innerText || '').trim(); if (hasDataDome) return 'BLOCKED_BY_TRIPADVISOR_DATADOME_CAPTCHA_OR_403'; if (!bodyText) return 'NO_VISIBLE_REVIEW_CONTENT'; return 'NO_REVIEW_CARD_FOUND'; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "voto_utile",
            "selector": "''",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "stato_estrazione",
            "selector": "(() => { const hasDataDome = !!document.querySelector('iframe[src*=\"captcha-delivery\"], script[src*=\"captcha-delivery\"], iframe[title*=\"DataDome\"]'); return hasDataDome ? 'blocked_datadome_or_403' : 'no_review_cards_visible'; })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2280,
      "position_y": 560,
      "config": {
        "color": "bg-[#8d8d8d]",
        "tags": [
          "next-input-url"
        ]
      }
    },
    {
      "block_id": "click-1",
      "block_type": "process",
      "title": "Click",
      "description": "Click on element",
      "position_x": 3360,
      "position_y": 560,
      "config": {
        "selector": "a[aria-label=\"Pagina successiva\"], a[aria-label=\"Avanti\"], a[aria-label=\"Next\"], a.nav.next:not(.disabled), a.next:not(.disabled)",
        "timeout": 20,
        "color": "bg-[#ff832b]",
        "tags": [
          "pagination-next"
        ]
      }
    },
    {
      "block_id": "wait-for-page-load-2",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 3720,
      "position_y": 560,
      "config": {
        "timeout": 45,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 4080,
      "position_y": 560,
      "config": {
        "duration": 3,
        "color": "bg-[#ff832b]"
      }
    }
  ],
  "connections": [
    {
      "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": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-1",
      "from_connector_id": "right",
      "to_block_id": "sleep-3",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-3",
      "from_connector_id": "right",
      "to_block_id": "element-exists-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-2",
      "from_connector_id": "true",
      "to_block_id": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-2",
      "from_connector_id": "false",
      "to_block_id": "structured-export-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-1",
      "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": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-1",
      "from_connector_id": "right",
      "to_block_id": "element-exists-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "true",
      "to_block_id": "click-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "false",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-2",
      "from_connector_id": "right",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "click-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-page-load-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-page-load-2",
      "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": "element-exists-2",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 48,
      "position_y": 116,
      "width": 4280,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "wait-for-element-1",
          "sleep-3",
          "sleep-1",
          "wait-for-page-load-2",
          "sleep-2"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1488,
      "position_y": 116,
      "width": 2120,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-2",
          "element-exists-1",
          "loop-continue-1",
          "click-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1848,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1848,
      "position_y": 116,
      "width": 1040,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1",
          "structured-export-2"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Italian TripAdvisor hotel reviews from supplied Tripadvisor.it ShowUserReviews/hotel review URLs. Extracts hotel metadata, reviewer details, rating, review date, stay date, title, content, helpful votes, and extraction status. Navigation uses a multi-URL input loop plus a click-next pagination loop when TripAdvisor exposes additional review pages. TripAdvisor may show DataDome/CAPTCHA or return a 403 interstitial; when reviews are not visible, this template writes a diagnostic blocked-page row for the URL instead of producing no CSV.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-element-exists-2",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `div[data-reviewid], div[id^=\"review_\"], div[data-automation=\"reviewCard\"], [data-test-target=\"HR_CC_CARD\"], [data-test-t`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 200,
      "width": 340,
      "height": 170,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-2"
      }
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(() => {\n  const labels = ['altro', 'leggi di più', 'leggi tutto', 'more', 'read more'];\n  const but...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 200,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (pagina_attuale, nome_hotel, recensioni_totali, rating_hotel, nome_utente). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2840,
      "position_y": 200,
      "width": 340,
      "height": 138,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-element-exists-1",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `a[aria-label=\"Pagina successiva\"], a[aria-label=\"Avanti\"], a[aria-label=\"Next\"], a.nav.next:not(.disabled), a.next:not(.`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 3200,
      "position_y": 200,
      "width": 340,
      "height": 170,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-1"
      }
    },
    {
      "id": "note-block-structured-export-2",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (pagina_attuale, nome_hotel, recensioni_totali, rating_hotel, nome_utente). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 540,
      "width": 340,
      "height": 138,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-2"
      }
    },
    {
      "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": 2480,
      "position_y": 540,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    },
    {
      "id": "note-block-click-1",
      "element_type": "note",
      "title": "Note: Click",
      "content": "Pagination click — add waits after this block; the page reloads asynchronously.",
      "color": "#ee5396",
      "position_x": 3560,
      "position_y": 540,
      "width": 316,
      "height": 106,
      "z_index": 22,
      "data": {
        "block_id": "click-1"
      }
    }
  ]
}