Is Tree Style Tab safe?
Tree Style Tab sends user interaction telemetry to Google Analytics, including IP-derived location and a persistent tracking UUID.
Each time the extension is installed, updated, or a user interacts with tab management features, it posts event data to Google Analytics (GA4) with a persistent client ID stored in chrome.storage.local. Before sending, it fetches the user's IP-based location from ipinfo.io (country, city, region, continent) and includes it in every analytics payload. Over 20 distinct interaction types are tracked, covering tab creation, deletion, grouping, workspace save/restore, and search actions.
Who publishes itxingtanzjr - no other listings under this identity
xingtanzjr - 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
Interaction telemetry sent with location and a persistent UUID
The extension sends tab, search, workspace, install and update events to Google Analytics, with a persistent client UUID and a location derived from an ipinfo.io lookup included in each request.
What actually happens
You use the extension's tab, search, workspace, install, or side-panel controls.
Examples in the shipped side-panel bundle include switching tabs, Google search, drag-and-drop, creating a tab, saving a workspace, restoring a workspace, and deleting a workspace.
The extension sends an analytics event tied to a persistent UUID and IP-derived location.
The analytics sender builds a Google Analytics Measurement Protocol body with client_id, events, params, and user_location when the location lookup succeeds.
Fields the code places in the analytics request
- Persistent client ID9e23d1a4-8d61-4f3a-bc1d-26e1e2d4a9b7
Lets the same browser installation be linked across multiple extension interactions.
- Interaction nameclick_switch_tab
Shows which extension feature you used.
- Page location (page-view events)chrome-extension://oicakdoenlelpjnkoljnaakdofplkgnd/sidepanel.html
Can identify the extension page or browsing context associated with an analytics event.
- IP-derived locationcountry_id=US, city=San Francisco, region_id=US-CA, continent_id=019, subcontinent_id=021
Adds city, region, country, continent, and subcontinent context derived from your network address.
- Session and engagement timingsession_id=1720794035123, engagement_time_msec=100
Groups nearby extension activity and records an engagement-time value with the event.
Captured request
The code expects JSON fields such as country, city, and region, then maps them into Google Analytics location codes.
Captured request
The shipped fetch call sends a Google Analytics Measurement Protocol request.
The code that does this
Service worker builds the UUID, location lookup, and analytics POST
IP-derived location lookup
service_worker.jsasync function getGeoForGA4() { try { const result = await chrome.storage.local.get(GEO_CACHE_KEY); const geoCache = result[GEO_CACHE_KEY]; if ( geoCache && geoCache.version === GEO_CACHE_VERSION && (Date.now() - geoCache.timestamp) < GEO_CACHE_TTL_MS ) { return geoCache.data; } const response = await fetch('https://ipinfo.io/json'); if (!response.ok) return null; const json = await response.json(); if (!json.country) return null; const data = { country_id: json.country }; if (json.city) { data.city = json.city; } const locationCodes = self.COUNTRY_LOCATION_CODES[json.country]; if (locationCodes) { data.continent_id = locationCodes.continent_id; data.subcontinent_id = locationCodes.subcontinent_id; } const regionCode = self.REGION_CODES[json.country]?.[json.region]; if (regionCode) { data.region_id = `${json.country}-${regionCode}`; } await chrome.storage.local.set({ [GEO_CACHE_KEY]: { data, timestamp: Date.now(), version: GEO_CACHE_VERSION, }, }); return data; } catch (e) { return null; }}Analytics sender
service_worker.jsasync function fireGA4Event(name, params = {}) { try { let { clientId } = await chrome.storage.local.get('clientId'); if (!clientId) { clientId = crypto.randomUUID(); await chrome.storage.local.set({ clientId }); } params.engagement_time_msec = params.engagement_time_msec || '100'; const geo = await getGeoForGA4(); const body = { client_id: clientId, events: [{ name, params }], }; if (geo) { body.user_location = geo; } await fetch( 'https://www.google-analytics.com/mp/collect?measurement_id=G-FZMN8RTLXZ&api_secret=<redacted>', { method: 'POST', body: JSON.stringify(body), } ); } catch (e) { console.error('GA4 event failed', e); }}The code that does this
Side-panel bundle sends the same analytics events from tab and workspace handlers
Analytics sender from source map
util/analytics.jsasync fireEvent(name, params = {}) { if (!params.session_id) { params.session_id = await this.getOrCreateSessionId(); } if (!params.engagement_time_msec) { params.engagement_time_msec = DEFAULT_ENGAGEMENT_TIME_MSEC; } try { const geo = await this.getGeoLocation(); const body = { client_id: await this.getOrCreateClientId(), events: [{ name, params }], }; if (geo) { body.user_location = geo; } const response = await fetch( `${this.debug ? GA_DEBUG_ENDPOINT : GA_ENDPOINT}?measurement_id=${MEASUREMENT_ID}&api_secret=<redacted>`, { method: 'POST', body: JSON.stringify(body), } ); if (this.debug) { console.log('[GA4] Request body:', JSON.stringify(body, null, 2)); console.log('[GA4] Response:', await response.text()); } } catch (e) { console.error('Google Analytics request failed with an exception', e); }}Tab-control event handlers from source map
components/TabTree.jsxconst searchByGoogle = useCallback((query) => { if (!query || query.trim() === '') return; const encodedQuery = encodeURIComponent(query); const url = `https://www.google.com/search?q=${encodedQuery}`; chrome.tabs.create({ url }); analytics.fireEvent('search_google');}, [chrome.tabs]);const onContainerClick = useCallback((tab) => { const noTabSelected = !tab || tab.id === -1; if (noTabSelected) { searchByGoogle(keyword); } else if (tab.isBookmark) { chrome.tabs.create({ url: tab.url }); analytics.fireEvent('click_open_bookmark'); } else if (tab.isGoogleSearch) { searchByGoogle(tab.title); } else { chrome.tabs.update(tab.id, { active: true }); analytics.fireEvent('click_switch_tab'); } if (window.parent !== window) { window.parent.postMessage({ type: 'tst-close-overlay' }, '*'); }}, [chrome.tabs, keyword, searchByGoogle]);Workspace save handler from source map
hooks/useWorkspace.jsconst handleSaveWorkspace = useCallback(() => { const name = wsSaveName.trim(); if (!name) return; const marks = {}; tabMarks.forEach((value, key) => { marks[key] = value; }); const notes = {}; tabNotes?.forEach((value, key) => { notes[key] = value; }); chrome.runtime.sendMessage({ action: 'saveWorkspace', name, marks, notes }, (resp) => { if (resp?.success) { setWsSaving(false); setWsSaveName(''); setWsSaveStatus('saved'); analytics.fireEvent('save_workspace'); setTimeout(() => setWsSaveStatus(null), 2000); } else if (resp?.error === 'limit') { setWsSaving(false); setWsSaveStatus('limit'); setTimeout(() => setWsSaveStatus(null), 3000); } });}, [chrome, tabMarks, tabNotes, wsSaveName]);External services contacted by the telemetry path
- ipinfo.io
Receives a location lookup request so the extension can derive country, city, region, continent, and subcontinent values.
- www.google-analytics.com
Receives Google Analytics Measurement Protocol events containing the client UUID, event name, event parameters, and location fields when available.
Where it sends data
Destinations our analysis observed Tree Style Tab 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.
- www.google-analytics.comwidely used
Tree Style Tab sends data to www.google-analytics.com. A widely used service: 388 other extensions we have analyzed send data here.
- ipinfo.iowidely used
Tree Style Tab sends data to ipinfo.io. A widely used service: 53 other extensions we have analyzed send data here.