Is View Rendered Source safe?
View Rendered Source sends the analyzed page URL, user-agent, and locale to Beam Analytics each time the extension is invoked.
Each time a user opens View Rendered Source — via toolbar click, keyboard shortcut, or context menu — the extension's popup page loads a Beam Analytics script that fires a POST request to lb1.beamanalytics.io. The payload includes up to 150 characters of the analyzed tab's URL (embedded in the page title), the browser's user-agent string, locale, and viewport width. No user opt-out control is present in the extension UI.
Who publishes itPeg Leg Ltd - no other listings under this identity
Peg Leg Ltd - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Analyzed Page URLs Sent to Beam Analytics
Launching View Rendered Source opens its analysis page, sets that page's title to the tab URL, and loads Beam Analytics, which posts JSON to lb1.beamanalytics.io/api/log with the title, tab ID, language, user agent, width, and site token.
What actually happens
You launch View Rendered Source for the current tab.
The launch can come from the toolbar button, the Alt+U shortcut, or the page context menu.
The extension opens its analysis page and loads Beam Analytics on that page.
Before Beam sends its analytics event, the page title is set to include the analyzed tab URL.
Fields Beam Analytics can receive from the extension page
- Analyzed page URLView Rendered Source: https://intranet.example.com/payroll/reports?quarter=Q2 (illustrative)
Tells the analytics service which page you asked to inspect. URLs may include account pages, document names, search terms, or hostnames.
- Extension page parametertabID=482
Links the analytics event to the extension's analysis tab for your current browser session.
- Browser user agentMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Describes your browser and operating system, adding device context to the analytics event.
- Browser languageen-US
Adds your preferred browser language to the same event as the analyzed URL.
- Window width1440
Adds screen-size context that can help distinguish desktop and mobile-like browsing environments.
- Sender network address203.0.113.42 (illustrative)
The analytics endpoint can observe the network address that delivered the request.
Captured request
- Content-Type
- application/json
The code that does this
The launch path, URL-to-title assignment, and Beam Analytics POST
User launch opens the analysis page
background.jsfunction launchVRS() { chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { //get current tab position so we can open new tab next to it (at index + 1) var tabPosition = tabs[0].index; var tabID = tabs[0].id; chrome.tabs.sendMessage(tabs[0].id, {"message": "Gimme the rendered DOM"}, function(response) { if(response) { var renderedObjURL = response.payload; var renderedStorageKey = "VRS|" + tabs[0].id; var doctypeKey = "VRSDOCTYPE|" + tabs[0].id; var UAKey = "VRSUA|" + tabs[0].id; //add reference in storage to blobURL of rendered page chrome.storage.local.set({ [renderedStorageKey]: renderedObjURL }); chrome.storage.local.set({ [doctypeKey]: response.doctype }); chrome.storage.local.set({ [UAKey]: response.userAgent }); chrome.tabs.create({ url: 'viewrenderedsource.html?tabID=' + tabID, index: tabPosition + 1}); } else { //no response from content.js -- not much we can do... } }); });}//user clicked Browser Action button or used keyboard shortcutchrome.action.onClicked.addListener(function (info) { launchVRS();});// create context menu (right click menu)chrome.contextMenus.create({ id: "vrs_context_menu", title: "View Rendered Source (Alt+U)", contexts:["page"]});// Listen for the context menu item clickchrome.contextMenus.onClicked.addListener(function(info, tab) { if (info.menuItemId === "vrs_context_menu") { launchVRS(); }});// Listen for the keyboard shortcutchrome.commands.onCommand.addListener(function(command) { if (command === "_execute_action") { launchVRS(); }});The selected tab URL is copied into the document title
viewrenderedsource.jschrome.tabs.get(parseInt(tabID), function (tab) { //for some reason there's no way to query if a tab still exists so have to look for error if (chrome.runtime.lastError) { alert('Error: Original tab has been closed. Reload original tab and launch extension again.'); return } //get URL of tab that opened us so we can fetch raw source rawURL = tab.url; d.title = 'View Rendered Source: ' + rawURL.substring(0, 150); currentURL.innerHTML = 'URL: ' + rawURL; currentURLHref.href = rawURL; var doctypeKey = "VRSDOCTYPE|" + tabID; var userAgentKey = "VRSUA|" + tabID; var renderedDOMKey = "VRS|" + tabID; chrome.storage.local.get(doctypeKey, function(result) { doctype = result[doctypeKey]; }); chrome.storage.local.get(userAgentKey, function(result) { userAgent = result[userAgentKey]; //Detect if mobile if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0,4))) { // fetchTypeRendered.innerHTML = 'Chrome, Mobile <div class="tooltip" style="width:15px; height:15px; font-size:14px; font-weight:800">i <span class="tooltiptext">To render as a mobile device, <a href="https://developers.google.com/web/tools/chrome-devtools/device-mode/emulate-mobile-viewports" target="_blank">change the device in Chrome DevTools</a> and re-launch extension</span></div>'; // fetchAsMobile.checked = true; } else { // fetchTypeRendered.innerHTML = 'Chrome, Desktop <div class="tooltip" style="width:15px; height:15px; font-size:14px; font-weight:800">i <span class="tooltiptext">To render as a mobile device, <a href="https://developers.google.com/web/tools/chrome-devtools/device-mode/emulate-mobile-viewports" target="_blank">change the device in Chrome DevTools</a> and re-launch extension</span></div>'; } }); //now get Blob URL of rendered source chrome.storage.local.get(renderedDOMKey, function(result) { var renderedBlobURL = result[renderedDOMKey]; fetchSource(renderedBlobURL, 'rendered'); fetchSource(rawURL, 'raw'); }); });Beam constructs and sends the JSON analytics request
beam.min.js! function() { var e = document.currentScript.getAttribute("data-api") || "https://lb1.beamanalytics.io/api/log"; window.beam = function(t) { if (!/^localhost$|^127(\.[0-9]+){0,2}\.[0-9]+$|^\[::1?\]$/.test(location.hostname) && "file:" !== location.protocol && !window.__nightmare && !window.navigator.webdriver && !window.Cypress) { var a = {}, n = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || "en", r = Object.fromEntries(new URLSearchParams(window.location.search).entries()), i = ""; 0 > document.referrer.indexOf(location.origin) && (i = document.referrer); var s = window.beam_token || document.currentScript.getAttribute("data-token"); if (window.beam_token = window.beam_token || s, s) { a.width = window.innerWidth, a.hostname = location.hostname, a.pathname = t || location.pathname, a.referrer = i, a.user_agent = window.navigator.userAgent, a.locale = n, a.params = r, a.token = s, a.title = document.title, a.hash = location.hash; var o = new XMLHttpRequest; o.open("POST", e, !0), o.setRequestHeader("Content-Type", "application/json"), o.send(JSON.stringify(a)) } } }; var t = function(e) { beam() }; window.addEventListener("hashchange", t); var a = window.history; if (a.pushState) { var n = a.pushState; a.pushState = function() { n.apply(this, arguments), beam() }, window.addEventListener("popstate", t) } beam()}();External analytics destination
- lb1.beamanalytics.io
Beam Analytics logging endpoint that receives the extension page analytics event.
What it can do
Permissions this extension asks for, as declared in version 4.0. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
http://*/*
Read and change your data on every secure site you visit
https://*/*
Add items to the right-click menu
contextMenus
Store data in your browser
storage
Where it sends data
Destinations our analysis observed View Rendered Source contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- lb1.beamanalytics.io
View Rendered Source sends data to lb1.beamanalytics.io. No other extension we have analyzed sends data here.
