{
  "version": "1.0.0",
  "exported_at": "2026-05-31T00:00:00.000Z",
  "project": {
    "name": "Twitter Scraper",
    "description": "Best-effort X/Twitter scraper for tweet/search/profile timelines. Target site: x.com. Default URL is an editable X account timeline; replace it with any X profile, hashtag, search, or advanced-search URL. Extracts tweet author, handle, timestamp, tweet text, tweet URL, engagement counts, views/bookmark labels when exposed, media URLs, and visible profile follower/following metadata. Pagination/navigation strategy: X uses infinite scroll and a virtualized DOM, so this template injects a collector script that scrolls through multiple batches, de-duplicates tweet cards as they appear, writes them into a hidden dataset, then exports the normalized rows. If X requires login, CAPTCHA, or blocks guest access, the export includes a diagnostic row instead of silently producing no file.",
    "color": "bg-[#1d9bf0]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "set-window-size-1",
      "block_type": "process",
      "title": "Set Window Size",
      "description": "Set browser viewport size",
      "position_x": 120,
      "position_y": 240,
      "config": {
        "width": 1920,
        "height": 1080,
        "color": "bg-[#4589ff]"
      }
    },
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 480,
      "position_y": 240,
      "config": {
        "url": "https://x.com/X",
        "color": "bg-[#4589ff]",
        "tags": [
          "edit-url",
          "x.com",
          "twitter"
        ]
      }
    },
    {
      "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": 240,
      "config": {
        "timeout": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1200,
      "position_y": 240,
      "config": {
        "duration": 4,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1560,
      "position_y": 240,
      "config": {
        "jsCode": "(function(){window.__uscraperTwitterDone=false;window.__uscraperTweets=new Map();const sleep=ms=>new Promise(r=>setTimeout(r,ms));const clean=s=>(s||'').replace(/\\s+/g,' ').trim();const text=(el,sel)=>{const n=sel?el.querySelector(sel):el;return n?clean(n.innerText||n.textContent||''):''};const attr=(el,sel,a)=>{const n=sel?el.querySelector(sel):el;return n?(n.getAttribute(a)||''):''};const abs=u=>{try{return u?new URL(u,location.origin).href:''}catch(e){return u||''}};const countFrom=(el,testid)=>{const n=el.querySelector(`[data-testid='${testid}']`);if(!n)return '';const label=n.getAttribute('aria-label')||n.innerText||'';const m=label.match(/[\\d.,]+\\s*[KMB]?/i);return m?m[0]:clean(label)};const profileMeta=()=>{const profileName=text(document,`[data-testid='UserName']`)||text(document,`h1`);const body=document.body.innerText||'';const handle=(body.match(/@\\w+/)||[''])[0];let followers='',following='';const links=Array.from(document.querySelectorAll(`a[href$='/followers'],a[href$='/verified_followers'],a[href$='/following']`));for(const a of links){const h=a.getAttribute('href')||'';const t=clean(a.innerText||a.textContent||'');if(h.endsWith('/following'))following=t;if(h.endsWith('/followers')||h.endsWith('/verified_followers'))followers=t}return {profileName,profileHandle:handle,profileFollowers:followers,profileFollowing:following}};const collect=()=>{const meta=profileMeta();const articles=Array.from(document.querySelectorAll(`article[data-testid='tweet']`));for(const article of articles){const userBlock=article.querySelector(`[data-testid='User-Name']`);const userText=userBlock?(userBlock.innerText||''):'';const userLines=userText.split('\\n').map(s=>clean(s)).filter(Boolean);const authorName=userLines.find(s=>!s.startsWith('@')&&!/^·$/.test(s)&&!/^\\d+[smhd]$/i.test(s))||userLines[0]||'';const handleMatch=userText.match(/@\\w+/);const handle=handleMatch?handleMatch[0]:'';const timestamp=attr(article,'time','datetime');const tweetText=text(article,`[data-testid='tweetText']`);const statusLink=article.querySelector(`a[href*='/status/']`);const tweetUrl=statusLink?abs(statusLink.getAttribute('href')):'';const repliesCount=countFrom(article,'reply');const repostsCount=countFrom(article,'retweet');const likesCount=countFrom(article,'like');const viewsEl=article.querySelector(`a[aria-label*='views'],a[aria-label*='Views'],[aria-label*='views'],[aria-label*='Views']`);const viewsLabel=viewsEl?(viewsEl.getAttribute('aria-label')||viewsEl.innerText||''):'';const viewsMatch=viewsLabel.match(/[\\d.,]+\\s*[KMB]?/i);const viewsCount=viewsMatch?viewsMatch[0]:clean(viewsLabel);const bookmarkEl=article.querySelector(`[data-testid='bookmark'],[aria-label*='Bookmark'],[aria-label*='bookmark']`);const bookmarkLabel=bookmarkEl?(bookmarkEl.getAttribute('aria-label')||bookmarkEl.innerText||''):'';const bookmarkMatch=bookmarkLabel.match(/[\\d.,]+\\s*[KMB]?/i);const bookmarksCount=bookmarkMatch?bookmarkMatch[0]:clean(bookmarkLabel);const mediaUrls=Array.from(article.querySelectorAll(`[data-testid='tweetPhoto'] img,video,img[src*='twimg.com/media']`)).map(n=>n.currentSrc||n.src||n.getAttribute('poster')||'').filter(Boolean).map(abs).join(' | ');const key=tweetUrl||handle+'|'+timestamp+'|'+tweetText.slice(0,120);if(tweetText||tweetUrl){window.__uscraperTweets.set(key,{pageStatus:'ok',blockedReason:'',profileName:meta.profileName,profileHandle:meta.profileHandle,profileFollowers:meta.profileFollowers,profileFollowing:meta.profileFollowing,authorName,handle,timestamp,tweetText,tweetUrl,repliesCount,repostsCount,likesCount,viewsCount,bookmarksCount,mediaUrls,capturedPageUrl:location.href})}}};const render=()=>{const old=document.getElementById('uscraper-tweet-dataset');if(old)old.remove();const container=document.createElement('div');container.id='uscraper-tweet-dataset';container.style.display='none';document.body.appendChild(container);if(window.__uscraperTweets.size===0){const bodyText=clean((document.body&&document.body.innerText)||'').slice(0,700);const isBlocked=/sign in|log in|captcha|something went wrong|rate limit|try again/i.test(bodyText);const meta=profileMeta();window.__uscraperTweets.set('diagnostic|'+location.href,{pageStatus:isBlocked?'blocked_or_login_required':'no_visible_tweets',blockedReason:bodyText,profileName:meta.profileName,profileHandle:meta.profileHandle,profileFollowers:meta.profileFollowers,profileFollowing:meta.profileFollowing,authorName:'',handle:'',timestamp:'',tweetText:'',tweetUrl:'',repliesCount:'',repostsCount:'',likesCount:'',viewsCount:'',bookmarksCount:'',mediaUrls:'',capturedPageUrl:location.href})}for(const t of window.__uscraperTweets.values()){const row=document.createElement('div');row.className='tweet-row';for(const k in t){row.setAttribute('data-'+k.replace(/[A-Z]/g,m=>'-'+m.toLowerCase()),t[k]||'')}row.textContent=t.tweetText||t.blockedReason||'';container.appendChild(row)}};(async()=>{try{for(let i=0;i<8;i++){collect();window.scrollBy(0,Math.max(900,window.innerHeight*0.9));await sleep(1300)}collect();render()}catch(e){console.error('UScraper Twitter collector error',e);render()}window.__uscraperTwitterDone=true})()})();",
        "waitForCompletion": false,
        "timeout": 5,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1920,
      "position_y": 240,
      "config": {
        "duration": 14,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 2280,
      "position_y": 240,
      "config": {
        "selector": "#uscraper-tweet-dataset .tweet-row",
        "timeout": 20,
        "visible": false,
        "color": "bg-[#42be65]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2640,
      "position_y": 240,
      "config": {
        "rowSelector": "#uscraper-tweet-dataset .tweet-row",
        "fileName": "twitter-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "create",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "page_status",
            "selector": "",
            "attribute": "data-page-status"
          },
          {
            "name": "blocked_reason",
            "selector": "",
            "attribute": "data-blocked-reason"
          },
          {
            "name": "profile_name",
            "selector": "",
            "attribute": "data-profile-name"
          },
          {
            "name": "profile_handle",
            "selector": "",
            "attribute": "data-profile-handle"
          },
          {
            "name": "profile_followers",
            "selector": "",
            "attribute": "data-profile-followers"
          },
          {
            "name": "profile_following",
            "selector": "",
            "attribute": "data-profile-following"
          },
          {
            "name": "author_name",
            "selector": "",
            "attribute": "data-author-name"
          },
          {
            "name": "handle",
            "selector": "",
            "attribute": "data-handle"
          },
          {
            "name": "timestamp",
            "selector": "",
            "attribute": "data-timestamp"
          },
          {
            "name": "tweet_text",
            "selector": "",
            "attribute": "data-tweet-text"
          },
          {
            "name": "tweet_url",
            "selector": "",
            "attribute": "data-tweet-url"
          },
          {
            "name": "replies_count",
            "selector": "",
            "attribute": "data-replies-count"
          },
          {
            "name": "reposts_count",
            "selector": "",
            "attribute": "data-reposts-count"
          },
          {
            "name": "likes_count",
            "selector": "",
            "attribute": "data-likes-count"
          },
          {
            "name": "views_count",
            "selector": "",
            "attribute": "data-views-count"
          },
          {
            "name": "bookmarks_count_or_label",
            "selector": "",
            "attribute": "data-bookmarks-count"
          },
          {
            "name": "media_urls",
            "selector": "",
            "attribute": "data-media-urls"
          },
          {
            "name": "captured_page_url",
            "selector": "",
            "attribute": "data-captured-page-url"
          }
        ]
      }
    },
    {
      "block_id": "end-1",
      "block_type": "output",
      "title": "End",
      "description": "Terminate execution flow",
      "position_x": 3000,
      "position_y": 240,
      "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": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-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": "sleep-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-2",
      "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": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-1",
      "from_connector_id": "right",
      "to_block_id": "end-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-entry",
      "element_type": "group",
      "title": "Entry & Setup",
      "color": "#4589ff",
      "position_x": 48,
      "position_y": 136,
      "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": 136,
      "width": 2120,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "sleep-2",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1488,
      "position_y": 136,
      "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": 2568,
      "position_y": 136,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-control",
      "element_type": "group",
      "title": "Control Flow",
      "color": "#8d8d8d",
      "position_x": 2928,
      "position_y": 136,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "end-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Best-effort X/Twitter scraper for tweet/search/profile timelines. Target site: x.com. Default URL is an editable X account timeline; replace it with any X profile, hashtag, search, or advanced-search URL. Extracts tweet author, handle, timestamp, tweet text, tweet URL, engagement counts, views/bookmark labels when exposed, media URLs, and visible profile follower/following metadata. Pagination/navigation strategy: X uses infinite scroll and a virtualized DOM, so this template injects a collector script that scrolls through multiple batches, de-duplicates tweet cards as they appear, writes them into a hidden dataset, then exports the normalized rows. If X requires login, CAPTCHA, or blocks guest access, the export includes a diagnostic row instead of silently producing no file.",
      "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: `(function(){window.__uscraperTwitterDone=false;window.__uscraperTweets=new Map();const sleep=ms=>new...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 220,
      "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": "Extracts rows matching `#uscraper-tweet-dataset .tweet-row`. Confirm row count > 0 before running at scale.",
      "color": "#ee5396",
      "position_x": 2840,
      "position_y": 220,
      "width": 340,
      "height": 115,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    }
  ]
}