-
-
Save arafathusayn/101a211b3d8122876d70cf1af04ae81d to your computer and use it in GitHub Desktop.
| /** | |
| * 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); | |
| } | |
| })(); |
Please provide new tawk brand removing code because previous code not working..
Below mentioned script not working currently.
var removeBranding = function() {
try {
var element = document.querySelector("iframe[title*=chat]:nth-child(2)").contentDocument.querySelector(a[class*=tawk-branding])
if (element) {
element.remove()
}
} catch (e) {}
}
var tick = 100
setInterval(removeBranding, tick)
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
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>Code updated for 2026. Please test and let me know if it works.
Instead of removing a node, you can inject some CSS to change the widget appearance, such as: