Last active
May 31, 2026 15:35
-
-
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); | |
| } | |
| })(); |
@hazelcorp2011-cmd π§ try this β it seems the Tawk guys were smart π they removed the
href, so you canβt easily target it anymore with:a[href*="tawk.to"]But haha πππππ you can still catch that anchor using other CSS attribute selectors. See below π
method one just hiding the brand
// ================== embed tawk.to script ================== useEffect(() => { const BRANDING_SELECTORS = ` /* expanded widget branding */ a[style*="font-size: 12px"][style*="font-weight: 400"][style*="padding: 0.5em"], /* minimized widget branding */ a[style*="font-size: 12px"][style*="border-radius: 100px"] `; const injectStyle = (doc: Document) => { if (doc.getElementById("hide-tawk-branding")) return; const style = doc.createElement("style"); style.id = "hide-tawk-branding"; style.textContent = ` ${BRANDING_SELECTORS} { display: none !important; visibility: hidden !important; opacity: 0 !important; pointer-events: none !important; width: 0 !important; height: 0 !important; overflow: hidden !important; max-width: 0 !important; max-height: 0 !important; } `; (doc.head || doc.documentElement).prepend(style); }; const handleIframe = (iframe: HTMLIFrameElement) => { const apply = () => { try { const doc = iframe.contentDocument || iframe.contentWindow?.document; if (!doc) return; injectStyle(doc); } catch { // cross-origin iframe β expected for non-tawk iframes } }; apply(); iframe.addEventListener("load", apply); }; // existing iframes document.querySelectorAll("iframe").forEach((iframe) => { handleIframe(iframe as HTMLIFrameElement); }); // future iframes const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node instanceof HTMLIFrameElement) { handleIframe(node); } if (node instanceof HTMLElement) { node.querySelectorAll("iframe").forEach((iframe) => { handleIframe(iframe as HTMLIFrameElement); }); } }); }); }); observer.observe(document.documentElement, { childList: true, subtree: true, }); return () => { observer.disconnect(); }; }, []);method two hiding the brand and adding ur own brand
// ================== embed tawk.to script ================== useEffect(() => { if (typeof window === "undefined") return; const s1 = document.createElement("script"); const s0 = document.getElementsByTagName("script")[0]; s1.async = true; s1.src = "Add link to the widget"; s1.charset = "UTF-8"; s1.setAttribute("crossorigin", "*"); s0?.parentNode?.insertBefore(s1, s0); }, []); // //================ latest hide branding and add ur custom branding ================= useEffect(() => { const BRAND_TEXT = "Powered by bloodykheeng"; const OVERLAY_ID = "custom-tawk-branding"; // ========================= // create stable branding overlay // ========================= let branding = document.getElementById(OVERLAY_ID); if (!branding) { branding = document.createElement("div"); branding.id = OVERLAY_ID; branding.innerText = BRAND_TEXT; Object.assign(branding.style, { position: "fixed", bottom: "30px", right: "100px", zIndex: "999999", background: "#fff", padding: "6px 12px", borderRadius: "999px", fontSize: "11px", color: "#6b7280", boxShadow: "0 4px 14px rgba(0,0,0,0.12)", pointerEvents: "none", transition: "opacity .2s ease", opacity: "0", visibility: "hidden", }); document.body.appendChild(branding); } // ========================= // show/hide overlay // ========================= const showBranding = () => { if (!branding) return; branding.style.opacity = "1"; branding.style.visibility = "visible"; }; const hideBranding = () => { if (!branding) return; branding.style.opacity = "0"; branding.style.visibility = "hidden"; }; // ========================= // tawk callbacks // ========================= const w = window as any; w.Tawk_API = w.Tawk_API || {}; w.Tawk_API.onChatMaximized = showBranding; w.Tawk_API.onChatStarted = showBranding; w.Tawk_API.onChatMinimized = hideBranding; w.Tawk_API.onChatHidden = hideBranding; // ========================= // aggressively hide real branding // ========================= const injectStyle = (doc: Document) => { if (doc.getElementById("hide-real-tawk-branding")) return; const style = doc.createElement("style"); style.id = "hide-real-tawk-branding"; style.textContent = ` a[style*="font-size: 12px"][style*="padding: 0.5em"], a[style*="border-radius: 100px"] { opacity: 0 !important; visibility: hidden !important; pointer-events: none !important; transform: scale(0) !important; } `; (doc.head || doc.documentElement).prepend(style); }; const handleIframe = (iframe: HTMLIFrameElement) => { const apply = () => { try { const doc = iframe.contentDocument || iframe.contentWindow?.document; if (!doc) return; injectStyle(doc); } catch { // cross-origin } }; apply(); iframe.addEventListener("load", apply); }; // existing iframes document.querySelectorAll("iframe").forEach((iframe) => { handleIframe(iframe as HTMLIFrameElement); }); // future iframes const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node instanceof HTMLIFrameElement) { handleIframe(node); } if (node instanceof HTMLElement) { node.querySelectorAll("iframe").forEach((iframe) => { handleIframe(iframe as HTMLIFrameElement); }); } }); }); }); observer.observe(document.documentElement, { childList: true, subtree: true, }); return () => { observer.disconnect(); branding?.remove(); }; }, []);
I was try, but still not remove tawk branding
Anyone can help me for removing tawk chat branding with plan JS Code.
Removed branding and also 2 items from dropdown menu.
Tested on tawk.to plugin for wordpress.
Works on mobile also.
Here:
var removeBranding = function () {
var iframes = document.querySelectorAll("iframe");
iframes.forEach(function (ifr, idx) {
try {
var doc = ifr.contentDocument || (ifr.contentWindow && ifr.contentWindow.document);
if (!doc) return;
var btn = doc.querySelector('a[class*="tawk-button-small"]');
if (btn) {
btn.remove();
}
var popoutIcon = doc.querySelector("i.tawk-icon.tawk-icon-popout");
if (popoutIcon) {
var popoutButton = popoutIcon.closest("button");
if (popoutButton) {
popoutButton.remove();
}
}
var byHref = doc.querySelector('a[href*="tawk.to/?utm_source=tawk-messenger"], a[href*="tawk.to/?utm_"]');
if (byHref) {
console.log("Removed by href:", byHref);
byHref.remove();
return;
}
var svgBranding = doc.querySelector('a svg[viewBox="0 0 107 15"]');
if (svgBranding) {
var brandingLink = svgBranding.closest("a");
if (brandingLink) {
console.log("Removed SVG branding:", brandingLink);
brandingLink.remove();
return;
}
}
var nodes = Array.from(doc.querySelectorAll("a, div, span"));
var poweredBy = nodes.find(function (el) {
return normalizeText(el.textContent).includes("powered by tawk.to");
});
if (poweredBy) {
console.log("Removed powered by text:", poweredBy);
var a = poweredBy.tagName === "A" ? poweredBy : poweredBy.querySelector("a");
(a || poweredBy).remove();
}
}
catch (e) {
}
});
};
setInterval(removeBranding, 250);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@hazelcorp2011-cmd π§ try this β it seems the Tawk guys were smart π they removed the
href, so you canβt easily target it anymore with:But haha πππππ you can still catch that anchor using other CSS attribute selectors. See below π
method one just hiding the brand
method two hiding the brand and adding ur own brand