Is Claap - Sales meeting recorder safe?

Medium risk

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.

extensionv0.1503.0Chrome Web Store
45Risk
Who publishes it

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.

sharing.clickup.com
Also called by 3 other listings, including Helperbird

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
What actually happens
You did this

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.

The extension did this

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.

Page DOM modified

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
Before
<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>
After the extension changed it
<head>  <style>    bubbles-pinned-extension-a1b2c3 {      display: none !important;      visibility: hidden !important;      opacity: 0 !important;    }  </style></head><body>  <div id="app-root">...</div></body>
The 14 hardcoded hostnames where widget removal fires (plus Claap's own web app domains)
  • Allowlisted site
    app.asana.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    notion.so

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    linkedin.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    linear.app

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    app.clickup.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    trello.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    gitlab.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    docs.google.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    drive.google.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    figma.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    miro.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    whimsical.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    github.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

  • Allowlisted site
    app.attio.com

    Loading this site automatically triggers the widget-removal check; other sites load third-party widgets normally.

The code that does this

The widget-removal logic, shipped vs. formatted

Readable version
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 }))    }())  }()}
Reproduce it yourself

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.

Requires
  • Chrome with the Claap extension installed and enabled
  • DevTools console access
widget-removal-repro.js · js
// 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();
How to run it
  1. 1Open an allowlisted site (github.com, docs.google.com, etc) with Claap installed.
  2. 2Open DevTools console.
  3. 3Paste and run this script.
  4. 4Read the three logged booleans; all true confirms the removal.
Updated 30 September 2026bnflmljpbmkjeahgjakmjdanmhldjhbk