Last active
February 13, 2026 06:15
-
-
Save arafathusayn/101a211b3d8122876d70cf1af04ae81d to your computer and use it in GitHub Desktop.
Remove Tawk.to Branding (2026)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Remove Tawk.to Branding | |
| * | |
| * What it hides: | |
| * - Footer branding links (tawk.to, utm_source=tawk-messenger) | |
| * - "Add Chat to your website" link | |
| * - Popout button/icon | |
| * - Branding container classes | |
| * | |
| * Key design decisions: | |
| * - CSS injection over DOM removal (less disruptive, survives re-renders) | |
| * - MutationObserver over setInterval (reacts to changes, no wasted cycles) | |
| * - Debounced re-scans (Tawk rebuilds its widget DOM sometimes) | |
| * - iframe `load` listener stays active (catches SPA navigations) | |
| * - JS fallback for popout buttons (`:has()` unsupported in older browsers) | |
| */ | |
| ;(function removeTawkBranding() { | |
| "use strict"; | |
| // ── Config ──────────────────────────────────────────────────────────── | |
| var STYLE_ID = "hide-tawk-branding"; | |
| // NOTE: No `:contains()` (jQuery-only, invalid in browsers). | |
| // No `:has()` in CSS (Firefox < 121, older Safari/Chrome). | |
| // Popout buttons handled via JS fallback below. | |
| var BRANDING_CSS = [ | |
| "a[href*='tawk.to'] { display: none !important; }", | |
| "a[href*='utm_source=tawk-messenger'] { display: none !important; }", | |
| "a[title*='Add Chat to your website'] { display: none !important; }", | |
| ".tawk-branding { display: none !important; }", | |
| "[class*='tawk-branding'] { display: none !important; }", | |
| ".tawk-padding-small { display: none !important; }", | |
| ".tawk-icon-popout { display: none !important; }", | |
| ].join("\n"); | |
| var RETRY_DELAY_MS = 1500; | |
| // ── State ───────────────────────────────────────────────────────────── | |
| var processedIframes = new WeakSet(); | |
| var pendingRetries = new Map(); | |
| var debounceTimer = null; | |
| // ── Core ────────────────────────────────────────────────────────────── | |
| /** | |
| * Inject a <style> into a document. Returns true on success. | |
| */ | |
| function injectStyle(doc) { | |
| try { | |
| if (!doc || !doc.createElement) return false; | |
| if (doc.getElementById(STYLE_ID)) return true; | |
| var style = doc.createElement("style"); | |
| style.id = STYLE_ID; | |
| style.textContent = BRANDING_CSS; | |
| var target = doc.head || doc.documentElement; | |
| if (target) { | |
| target.appendChild(style); | |
| return true; | |
| } | |
| } catch (_) { | |
| // Cross-origin — expected. | |
| } | |
| return false; | |
| } | |
| /** | |
| * JS fallback: hide popout buttons for browsers without CSS `:has()`. | |
| */ | |
| function hidePopoutButtons(doc) { | |
| try { | |
| if (!doc || !doc.querySelectorAll) return; | |
| var icons = doc.querySelectorAll(".tawk-icon-popout"); | |
| for (var i = 0; i < icons.length; i++) { | |
| var btn = icons[i].closest("button"); | |
| if (btn) btn.style.setProperty("display", "none", "important"); | |
| } | |
| } catch (_) {} | |
| } | |
| /** | |
| * Inject styles into an iframe. Retries once if contentDocument isn't ready. | |
| */ | |
| function injectIntoIframe(iframe) { | |
| try { | |
| var doc = iframe.contentDocument; | |
| if (!doc) { | |
| // Schedule a single retry if iframe not ready yet | |
| if (!pendingRetries.has(iframe)) { | |
| var timeout = setTimeout(function () { | |
| pendingRetries.delete(iframe); | |
| injectIntoIframe(iframe); | |
| }, RETRY_DELAY_MS); | |
| pendingRetries.set(iframe, timeout); | |
| } | |
| return; | |
| } | |
| injectStyle(doc); | |
| hidePopoutButtons(doc); | |
| } catch (_) { | |
| // Cross-origin — expected. | |
| } | |
| } | |
| /** | |
| * Process a chat iframe: mark as processed, inject now, re-inject on reload. | |
| */ | |
| function handleIframe(iframe) { | |
| if (processedIframes.has(iframe)) return; | |
| var title = (iframe.title || "").toLowerCase(); | |
| if (title.indexOf("chat") === -1) return; | |
| processedIframes.add(iframe); | |
| // Inject immediately (may already be loaded) | |
| injectIntoIframe(iframe); | |
| // Re-inject on subsequent loads (SPA navigation, widget rebuild). | |
| // Intentionally NOT `{ once: true }` — Tawk can reload iframe content. | |
| iframe.addEventListener("load", function () { | |
| injectIntoIframe(iframe); | |
| }); | |
| } | |
| /** | |
| * Scan a root document for all chat iframes. | |
| */ | |
| function scanIframes(root) { | |
| try { | |
| var iframes = (root || document).querySelectorAll("iframe"); | |
| for (var i = 0; i < iframes.length; i++) { | |
| handleIframe(iframes[i]); | |
| } | |
| } catch (_) {} | |
| } | |
| // ── Observer ────────────────────────────────────────────────────────── | |
| function onMutations(mutations) { | |
| var foundNewIframe = false; | |
| for (var i = 0; i < mutations.length; i++) { | |
| var added = mutations[i].addedNodes; | |
| for (var j = 0; j < added.length; j++) { | |
| var node = added[j]; | |
| if (node.nodeName === "IFRAME") { | |
| handleIframe(node); | |
| foundNewIframe = true; | |
| } else if (node.nodeType === 1 && node.querySelectorAll) { | |
| var nested = node.querySelectorAll("iframe"); | |
| if (nested.length) { | |
| for (var k = 0; k < nested.length; k++) { | |
| handleIframe(nested[k]); | |
| } | |
| foundNewIframe = true; | |
| } | |
| } | |
| } | |
| } | |
| // Debounced re-scan: Tawk sometimes rebuilds its widget DOM entirely, | |
| // so existing iframes may get new content without a new IFRAME node. | |
| if (foundNewIframe && !debounceTimer) { | |
| debounceTimer = setTimeout(function () { | |
| debounceTimer = null; | |
| scanIframes(); | |
| hidePopoutButtons(document); | |
| }, 500); | |
| } | |
| } | |
| // ── Bootstrap ───────────────────────────────────────────────────────── | |
| function start() { | |
| // Main document branding (outside iframes) | |
| injectStyle(document); | |
| hidePopoutButtons(document); | |
| // Initial iframe scan | |
| scanIframes(); | |
| // Watch for dynamically added iframes | |
| if (typeof MutationObserver !== "undefined" && document.body) { | |
| var observer = new MutationObserver(onMutations); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| // Cleanup | |
| window.addEventListener("beforeunload", function () { | |
| observer.disconnect(); | |
| pendingRetries.forEach(clearTimeout); | |
| pendingRetries.clear(); | |
| if (debounceTimer) { | |
| clearTimeout(debounceTimer); | |
| debounceTimer = null; | |
| } | |
| }); | |
| } | |
| } | |
| // Guard: script may be in <head> before document.body exists | |
| if (document.body) { | |
| start(); | |
| } else { | |
| document.addEventListener("DOMContentLoaded", start); | |
| } | |
| })(); |
How we can achieve this is next js website bro please help me.
Perfect @enkiark
Worked for me.
hello all of you guys, here is how you remove all the brandings whether outside chat or inside chat widget for tawk.io
For React/Next.js
"use client";
import { useEffect } from "react";
export default function HideTawkBranding() {
useEffect(() => {
const hideBranding = (iframe: HTMLIFrameElement) => {
try {
const doc = iframe.contentDocument;
const link = doc?.querySelector(
"a[href*='tawk.to']"
) as HTMLElement | null;
if (link) {
link.style.setProperty("display", "none", "important");
}
} catch {
// cross-origin iframe → expected
}
};
const scanIframes = () => {
document
.querySelectorAll("iframe[title*='chat']")
.forEach((iframe) => {
console.log("I am here ",)
hideBranding(iframe as HTMLIFrameElement)
});
};
// initial scan
scanIframes();
// watch for new iframes
const observer = new MutationObserver(scanIframes);
observer.observe(document.body, {
childList: true,
subtree: true,
});
return () => observer.disconnect();
}, []);
return null;
}
Import this above component in root of your react/Next js.
And for plain JS:
// hide-tawk-branding.js
(function() {
const processedIframes = new WeakSet();
const retryTimeouts = new Map();
const injectHideStyles = (iframe) => {
try {
const doc = iframe.contentDocument;
if (!doc) {
// Retry once after 2s if iframe not ready
if (!retryTimeouts.has(iframe)) {
const timeout = setTimeout(() => {
retryTimeouts.delete(iframe);
injectHideStyles(iframe);
}, 2000);
retryTimeouts.set(iframe, timeout);
}
return;
}
// Skip if already injected
if (doc.getElementById("hide-tawk-branding")) return;
const style = doc.createElement("style");
style.id = "hide-tawk-branding";
style.textContent = "a[href*='tawk.to']{display:none!important}";
doc.head.appendChild(style);
} catch {
// Silently fail on cross-origin errors
}
};
const handleIframe = (iframe) => {
// Skip if already processed
if (processedIframes.has(iframe)) return;
const title = iframe.title;
if (title && title.toLowerCase().includes("chat")) {
processedIframes.add(iframe);
injectHideStyles(iframe);
}
};
// Process existing iframes
document.querySelectorAll("iframe[title*='chat' i]").forEach(handleIframe);
// Watch for new iframes
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeName === "IFRAME") {
handleIframe(node);
continue;
}
if (node.nodeType === 1) {
const iframes = node.querySelectorAll("iframe[title*='chat' i]");
if (iframes.length) {
iframes.forEach(handleIframe);
}
}
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
// Cleanup on page unload
window.addEventListener("beforeunload", () => {
observer.disconnect();
retryTimeouts.forEach(clearTimeout);
retryTimeouts.clear();
});
})();
Updated Code 2026:
- Remove Footer Branding
- Remove "Add Chat to your Website"
- Remove Popout
All type of Branding is removed!
<script> (function() { const processedIframes = new WeakSet(); const retryTimeouts = new Map(); const hideTawkElements = (doc) => { try { if (!doc) return; // Don't add duplicate styles if (doc.getElementById("hide-tawk-global")) return; const style = doc.createElement("style"); style.id = "hide-tawk-global"; style.textContent = ` a[href*='tawk.to'] { display: none !important; } a[href*='utm_source=tawk-messenger'] { display: none !important; } a[href*='Add Chat to your website'] { display: none !important; } .tawk-dropdown-menu a:last-child { display: none !important; } button[role="button"] + div a[href*='tawk.to'] { display: none !important; } div[data-v-2fc2d95d] a:last-child { display: none !important; } button:has(.tawk-icon-popout) { display: none !important; } button:has(.tawk-icon-popout) + div { display: none !important; } .tawk-icon-popout { display: none !important; } button:contains("Pop out widget") { display: none !important; } [class*="tawk-dropdown"] button:has(.tawk-icon-popout) { display: none !important; } `; if (doc.head) { doc.head.appendChild(style); } else if (doc.documentElement) { doc.documentElement.appendChild(style); } // Also directly hide any existing tawk.to links and popout buttons const links = doc.querySelectorAll('a[href*="tawk.to"], a[href*="utm_source=tawk-messenger"]'); links.forEach(link => { link.style.display = 'none'; if (link.parentElement) { link.parentElement.style.display = 'none'; } }); // Directly hide popout buttons const popoutButtons = doc.querySelectorAll('button:has(.tawk-icon-popout), button:contains("Pop out widget"), .tawk-icon-popout'); popoutButtons.forEach(button => { button.style.display = 'none'; if (button.parentElement) { button.parentElement.style.display = 'none'; } }); } catch (e) { // Cross-origin error - can't access } }; const processDocument = (doc) => { hideTawkElements(doc); // Find all iframes inside this document try { const iframes = doc.querySelectorAll('iframe'); iframes.forEach(iframe => { if (!processedIframes.has(iframe)) { processedIframes.add(iframe); // Try to access iframe content when loaded try { if (iframe.contentDocument) { processDocument(iframe.contentDocument); } iframe.addEventListener('load', () => { try { if (iframe.contentDocument) { processDocument(iframe.contentDocument); } } catch (e) {} }, { once: true }); } catch (e) {} } }); } catch (e) {} }; // Start with main document processDocument(document); // Watch for new iframes and DOM changes const observer = new MutationObserver((mutations) => { // Process main document again hideTawkElements(document); for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeName === "IFRAME") { if (!processedIframes.has(node)) { processedIframes.add(node); try { if (node.contentDocument) { processDocument(node.contentDocument); } node.addEventListener('load', () => { try { if (node.contentDocument) { processDocument(node.contentDocument); } } catch (e) {} }, { once: true }); } catch (e) {} } } // Also hide popout buttons when they're added if (node.nodeType === 1) { if (node.matches && node.matches('button:has(.tawk-icon-popout), button:contains("Pop out widget")')) { node.style.display = 'none'; } const popoutButtons = node.querySelectorAll('button:has(.tawk-icon-popout), button:contains("Pop out widget"), .tawk-icon-popout'); popoutButtons.forEach(button => { button.style.display = 'none'; }); } } } }); observer.observe(document.body, { childList: true, subtree: true }); // Cleanup window.addEventListener("beforeunload", () => { observer.disconnect(); retryTimeouts.forEach(clearTimeout); retryTimeouts.clear(); }); })(); </script>
Author
Code updated for 2026. Please test and let me know if it works.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
var removeBranding = function() {
try {
const style = document.createElement('style');
style.textContent = '.tawk-padding-small {display:none !important;}';
document.querySelector('iframe[title*="chat"]:nth-child(2)').contentDocument.head.appendChild(style)
} catch (e) {}
}
var tick = 100
setInterval(removeBranding, tick)
2025 new tawk remove logo