Is Claap - Sales meeting recorder safe?
Claap removes Bubbles and Loom companion widgets from productivity sites where its content script runs.
Claap runs a content script on all pages and, on selected productivity sites such as Asana, Notion, GitHub, and Google Docs, looks for Bubbles and Loom companion widgets. When it finds those page elements, it hides or removes them from the DOM without a user click.
Who publishes itextension - no other listings under this identity, 1 shared hostname
extension - no other listings under this identity, 1 shared hostname
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 1 hostname
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Claap automatically hides and deletes competing Bubbles and Loom widgets
On document load at productivity sites like Asana, Notion, Trello, GitHub, and Google Docs, Claap hides and removes competing Bubbles and Loom widgets from the page.
No click or network request is involved.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Dynamic sandbox
You open a page on one of the extension's hardcoded productivity sites, such as github.com or docs.google.com.
The content script is declared for every page (<all_urls>), but only acts on this internal allowlist.
Claap's content script finds and deletes any Bubbles or Loom companion widget already on the page, automatically.
No click, menu action, or setting toggle is involved; removal starts at document_start.
Both the Bubbles custom element and the Loom companion div are removed from the page, and a style rule hiding the Bubbles tag is injected into <head> beforehand.
- Target
- document.body on an allowlisted site, e.g. github.com
<body> <div id="app-root">...</div> <bubbles-pinned-extension-a1b2c3></bubbles-pinned-extension-a1b2c3> <div id="loom-companion-mv3"> <iframe src="https://www.loom.com/companion" title="Loom companion"></iframe> </div></body><head> <style> bubbles-pinned-extension-a1b2c3 { display: none !important; visibility: hidden !important; opacity: 0 !important; } </style></head><body> <div id="app-root">...</div></body>- Allowlisted siteapp.asana.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitenotion.so
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitelinkedin.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitelinear.app
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted siteapp.clickup.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitetrello.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitegitlab.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitedocs.google.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitedrive.google.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitefigma.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitemiro.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitewhimsical.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted sitegithub.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
- Allowlisted siteapp.attio.com
Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.
The widget-removal logic, shipped vs. formatted
const Tl = ["app.asana.com", "notion.so", "linkedin.com", "linear.app", "app.clickup.com", "trello.com", "gitlab.com", "docs.google.com", "drive.google.com", "figma.com", "miro.com", "whimsical.com", "github.com", "app.attio.com"], kl = [...Wt, "local-dev.claap.io"];async function wl({ node: t }) { return new Promise((e => { const n = []; for (const e of t.children) 1 === e.nodeType && n.push(e); e(n) }))}async function Rl({ elements: t }) { return new Promise((e => { e(t.find((t => t.tagName.startsWith("bubbles-pinned-extension-".toUpperCase())))) }))}async function xl() { const t = await async function() { for (let t = 0; t < 5; t++) { const t = await wl({ node: document.body }), e = await Rl({ elements: t }); if (e) return e; await s(200) } }(); if (t) { const e = t.tagName.toLowerCase(), n = await async function({ tagName: t }) { const e = document.createElement("style"); return e.textContent = `\n ${t} {\n display: none !important;\n visibility: hidden !important;\n opacity: 0 !important;\n }\n `, e }({ tagName: e }); await async function({ styleElement: t }) { try { document.head.appendChild(t) } catch (t) { e = { err: t }, El.error("error while trying to add <style /> element in <head />", e) } var e }({ styleElement: n }), t.remove(), bl("Bubbles widget removed from the DOM", { remote: !0 }) }}async function Il() { return new Promise((t => { const e = document.getElementById("loom-companion-mv3"); e?.tagName !== "div".toUpperCase() ? t(void 0) : t(e) }))}async function Cl() { await async function() { for (;;) { if (document.body) return; await s(200) } }(), await async function() { const t = window.location.hostname.replace("www.", ""); [...Tl, ...kl].includes(t) && (await xl(), await async function() { const t = await async function() { for (let t = 0; t < 5; t++) { const t = await Il(); if (t) return t; await s(200) } }(); t && (t.remove(), bl("Loom widget removed from the DOM", { remote: !0 })) }()) }()}Plants synthetic Bubbles and Loom widget elements in the page and checks whether Claap removes them, mirroring the positive/negative control used to confirm this claim.
- Chrome with the Claap extension installed and enabled
- DevTools console access
// Run this in the DevTools console on an allowlisted site (e.g. github.com)// with the Claap extension installed and enabled.function plantWidgets() { const bubbles = document.createElement('bubbles-pinned-extension-test'); document.body.appendChild(bubbles); const loom = document.createElement('div'); loom.id = 'loom-companion-mv3'; loom.textContent = 'Loom companion widget'; document.body.appendChild(loom); return { bubbles, loom };}async function checkRemoval() { const { bubbles, loom } = plantWidgets(); await new Promise((r) => setTimeout(r, 2000)); const bubblesGone = !document.body.contains(bubbles); const loomGone = !document.body.contains(loom); const hidingStyle = [...document.querySelectorAll('style')].some((s) => s.textContent.includes('bubbles-pinned-extension') ); console.log('Bubbles element removed:', bubblesGone); console.log('Loom element removed:', loomGone); console.log('Hiding <style> rule injected:', hidingStyle);}checkRemoval();- 1Open an allowlisted site (github.com, docs.google.com, etc) with Claap installed.
- 2Open DevTools console.
- 3Paste and run this script.
- 4Read the three logged booleans; all true confirms the removal.