Inspired by @cbhours "Eye Contact Tool", this script introduces a new "Eye Contact Chat" tab to your broadcaster page. When activated, chat messages go fullscreen and appear from the top down, keeping them closer to your webcam—helping you maintain natural eye contact with viewers!
How It Works:


const chatTabDefault = document.querySelector("div#chat-tab-default");
if (chatTabDefault) {
const clonedTab = chatTabDefault.cloneNode(true);
// Modify cloned tab properties
clonedTab.id = "eye-contact-tab-default";
clonedTab.classList.replace("chat-tab-handle", "eye-contact-tab-handle");
clonedTab.setAttribute("data-testid", "eye-contact-tab-default");
const tabLabel = clonedTab.querySelector("span");
if (tabLabel) tabLabel.textContent = "EYE CONTACT CHAT";
// Insert cloned tab
chatTabDefault.parentElement.insertBefore(clonedTab, chatTabDefault);
// Ensure the Eye Contact tab is not active by default
clonedTab.classList.remove("active");
clonedTab.style.backgroundColor = "rgb(201, 201, 201)";
clonedTab.style.color = "rgb(76, 76, 76)";
clonedTab.style.cursor = "pointer";
}
// Tab behavior for switching
const allTabs = Array.from(
document.querySelectorAll(
"div#eye-contact-tab-default, div#chat-tab-default, div#pm-tab-default, div#users-tab-default, div#settings-tab-default"
)
).filter(Boolean);
const tsLeElement = document.querySelector('div[ts="le"]');
const messageList = document.querySelector(".msg-list-fvm.message-list");
const theaterChatDiv = document.querySelector(".ChatTabContents.TheatermodeChatDivChat");
// Helper to reset Eye Contact–specific styles
function resetEyeContactStyles() {
if (messageList) {
messageList.style.display = "";
messageList.style.flexDirection = "";
messageList.style.width = ""; // Reset width
messageList.style.margin = ""; // Reset margin
messageList.style.transform = "";
}
const msgListWrapper = document.querySelector('.msg-list-wrapper-split');
if (msgListWrapper) {
msgListWrapper.style.transform = "";
}
const noticeList = document.querySelector('.notice-list-fvm');
if (noticeList) {
noticeList.style.transform = "";
}
if (theaterChatDiv) {
theaterChatDiv.style.flexDirection = "column";
}
toggleFullscreen(false); // Exit fullscreen if active
// Reset emoji modal (regular) to default so it displays in front
const emojiModal = document.querySelector('.emojiSelectionModal');
if (emojiModal) {
emojiModal.style.position = '';
emojiModal.style.top = '';
emojiModal.style.left = '';
emojiModal.style.zIndex = '1001';
}
// Reset emojicon autocomplete modal styles to default
const emoticonList = document.querySelector('.autocompleteModal.theatermodeEmoticonAutocompleteModalChat');
if (emoticonList) {
emoticonList.style.top = '-181.337px';
emoticonList.style.bottom = '';
emoticonList.style.right = '';
emoticonList.style.left = '8px';
emoticonList.style.overflow = '';
emoticonList.style.maxHeight = '';
emoticonList.style.maxWidth = '';
emoticonList.style.width = '100%';
emoticonList.style.height = '';
emoticonList.style.zIndex = '1001';
}
}
// Helper to apply Eye Contact–specific styles
function applyEyeContactStyles() {
if (messageList) {
const msgListWrapper = document.querySelector('.msg-list-wrapper-split');
const noticeList = document.querySelector('.notice-list-fvm');
// Flip the scroll container
if (msgListWrapper) {
msgListWrapper.style.transform = 'scaleY(-1)';
}
// Ensure the message list uses column-reverse order and flip it back to normal
messageList.style.display = 'flex';
messageList.style.flexDirection = 'column-reverse';
messageList.style.transform = 'scaleY(-1)';
// Flip notice list elements back to normal
if (noticeList) {
noticeList.style.transform = 'scaleY(-1)';
}
// Additional styling specific to Eye Contact mode
messageList.style.width = "50%"; // Narrow the message container
messageList.style.margin = "0 auto"; // Center the container horizontally
// Set scroll position to the top so messages initiate at the top
messageList.scrollTop = 0;
}
if (theaterChatDiv) {
theaterChatDiv.style.flexDirection = "column-reverse";
}
toggleFullscreen(true); // Enter fullscreen
}
// Fullscreen toggle for Eye Contact tab
function toggleFullscreen(isActive) {
const chatTabContainer = document.querySelector("#ChatTabContainer");
if (isActive) {
if (chatTabContainer?.requestFullscreen) {
chatTabContainer.requestFullscreen();
} else if (chatTabContainer?.mozRequestFullScreen) {
chatTabContainer.mozRequestFullScreen();
} else if (chatTabContainer?.webkitRequestFullscreen) {
chatTabContainer.webkitRequestFullscreen();
} else if (chatTabContainer?.msRequestFullscreen) {
chatTabContainer.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
}
// Attach tab switching behavior
allTabs.forEach(tab => {
tab.addEventListener("click", () => {
// Reset all tabs to default styles
allTabs.forEach(otherTab => {
otherTab.classList.remove("active");
otherTab.style.backgroundColor = "rgb(201, 201, 201)";
otherTab.style.color = "rgb(76, 76, 76)";
otherTab.style.cursor = "pointer";
});
// Activate the clicked tab
tab.classList.add("active");
tab.style.backgroundColor = "rgb(255, 255, 255)";
tab.style.color = "rgb(220, 85, 0)";
tab.style.cursor = "default";
// Adjust UI based on the active tab
if (tsLeElement) {
if (tab.id === "chat-tab-default") {
tsLeElement.style.display = "block";
resetEyeContactStyles();
} else if (tab.id === "eye-contact-tab-default") {
tsLeElement.style.display = "block";
applyEyeContactStyles();
} else {
tsLeElement.style.display = "none";
resetEyeContactStyles();
}
}
// Update scroll button's SVG and text based on active tab
const scrollDownButton = document.querySelector('.scrollDownButton');
if (scrollDownButton) {
const svgElement = scrollDownButton.querySelector('svg');
const spanText = scrollDownButton.querySelector('span.scrollDownText');
if (tab.id === "eye-contact-tab-default") {
// For Eye Contact: flip SVG and set text to "Scroll to top"
if (svgElement) {
svgElement.style.transform = 'rotate(180deg)';
}
if (spanText) {
spanText.textContent = 'Scroll to top';
}
} else {
// For other tabs: restore the default SVG and set text to "Scroll to bottom"
if (svgElement) {
svgElement.setAttribute("width", "9px");
svgElement.setAttribute("height", "13px");
svgElement.setAttribute("viewBox", "0 0 9 13");
svgElement.setAttribute("fill", "none");
svgElement.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svgElement.innerHTML = `<path d="M4.50848 7.97048V1.5" stroke="white" stroke-width="1.4" stroke-linecap="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M1.24099 4.92406C0.957097 4.66164 0.496814 4.66164 0.21292 4.92406C-0.0709734 5.18648 -0.0709734 5.61194 0.21292 5.87436L3.90125 9.28368C4.18515 9.5461 4.64543 9.5461 4.92932 9.28368L8.67227 5.82387C8.95617 5.56145 8.95617 5.13599 8.67227 4.87357C8.38838 4.61115 7.9281 4.61115 7.6442 4.87357L4.41529 7.85823L1.24099 4.92406ZM0.655497 11.2058C0.298143 11.2058 0.00844965 11.4955 0.00844965 11.8528C0.00844965 12.2102 0.298143 12.4999 0.655498 12.4999H8.3614C8.71876 12.4999 9.00845 12.2102 9.00845 11.8528C9.00845 11.4955 8.71876 11.2058 8.3614 11.2058H0.655497Z" fill="white"></path>`;
svgElement.style.transform = "";
}
if (spanText) {
spanText.textContent = 'Scroll to bottom';
}
}
}
});
});
// Observe DOM changes to adjust emoji modals when the Eye Contact tab is active
const observer = new MutationObserver(() => {
const activeTab = document.querySelector(".tab.active");
if (activeTab && activeTab.id === "eye-contact-tab-default") {
// Relocate the emoji selection modal
const emojiSelectionModal = document.querySelector(".emojiSelectionModal");
const emojiSelectionModalOverlay = document.querySelector(".emojiSelectionModalOverlay");
if (emojiSelectionModal && emojiSelectionModalOverlay) {
emojiSelectionModal.style.position = "absolute";
emojiSelectionModal.style.top = "50px"; // Lower position for better visibility
emojiSelectionModal.style.right = "10px"; // Anchored to the right with a small margin
emojiSelectionModal.style.transform = "translateY(0)";
emojiSelectionModal.style.zIndex = "1001";
}
// Apply settings for the theater mode emojicon autocomplete modal
const emojiconList = document.querySelector('.autocompleteModal.theatermodeEmoticonAutocompleteModalChat');
if (emojiconList) {
emojiconList.style.top = '100%';
emojiconList.style.bottom = 'auto';
emojiconList.style.right = 'auto';
emojiconList.style.left = '0';
emojiconList.style.overflow = 'auto';
emojiconList.style.maxHeight = '';
emojiconList.style.maxWidth = '';
emojiconList.style.width = '100%';
emojiconList.style.height = 'auto';
emojiconList.style.borderTopWidth = 'none';
emojiconList.style.borderBottomWidth = '1px';
emojiconList.style.borderBottomStyle = 'solid';
}
}
});
// Start observing the body for changes
observer.observe(document.body, { childList: true, subtree: true });
// Disconnect observer when a different tab is active
document.querySelectorAll(".tab").forEach(tab => {
tab.addEventListener("click", () => {
const activeTab = document.querySelector(".tab.active");
if (activeTab && activeTab.id !== "eye-contact-tab-default") {
observer.disconnect();
} else {
observer.observe(document.body, { childList: true, subtree: true });
}
});
});
// Ensure that when the .msg-list-wrapper-split scrolls to the bottom,
// the scroll button text remains "Scroll to top" and the SVG stays flipped.
const msgWrapper = document.querySelector('.msg-list-wrapper-split');
if (msgWrapper) {
msgWrapper.addEventListener('scroll', () => {
const activeTab = document.querySelector('.tab.active');
if (activeTab && activeTab.id === 'eye-contact-tab-default') {
const scrollDownButton = document.querySelector('.scrollDownButton');
if (scrollDownButton) {
const spanText = scrollDownButton.querySelector('span.scrollDownText');
if (spanText) {
spanText.textContent = 'Scroll to top';
}
const svgElement = scrollDownButton.querySelector('svg');
if (svgElement) {
svgElement.style.transform = 'rotate(180deg)';
}
}
}
});
}
const targetDiv = document.querySelector('div#chat-tab-default');
if (targetDiv) {
const targetSpan = targetDiv.querySelector('span');
if (targetSpan) {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'characterData' || mutation.type === 'childList') {
if (targetSpan.textContent !== "DEFAULT") {
targetSpan.textContent = "DEFAULT";
}
}
});
});
observer.observe(targetSpan, { characterData: true, childList: true, subtree: true });
if (targetSpan.textContent !== "DEFAULT") {
targetSpan.textContent = "DEFAULT";
}
}
}
const data = {
message: "MutationObserver is set up to override the text content of the span to 'DEFAULT'."
}
How It Works:
- A new "Eye Contact Chat" tab appears on your broadcaster page.
- Clicking it expands chat to fullscreen, repositioning messages to stack from top to bottom.
- Keeps your gaze aligned with the camera for better engagement!
Steps to Inject the Script Using Chrome Developer Tools:
- Open the Chaturbate website:
- Go to your Chaturbate broadcast page.
- Open Chrome Developer Tools:
- Right-click anywhere on the page and select "Inspect" or press Ctrl + Shift + I (Windows) or Cmd + Option + I (Mac).
- Alternatively, press F12 to open the DevTools window.
- Navigate to the Console Tab:
- Inside the Developer Tools window, click on the "Console" tab. This is where you can execute JavaScript code.
- Paste Your Script:
- Copy the entire attached script .
- Paste the copied script directly into the Console tab.
- Press Enter:
- After pasting the code, press Enter to execute the script. The changes should take effect immediately, and the Eye Contact tab will be added to the Chaturbate page.
- IMPORTANT: Close the Developer Tools window.
- Test the New Feature:
- Once the script is injected, you should see the new Eye Contact Chat tab on your Chaturbate broadcast page. Test it to ensure everything works as expected.
Additional Notes:
- The script will only stay active for the current session. If you refresh the page, you will need to inject the script again.
- We’re not professional coders—this took many hours of trial and error with ChatGPT to figure out. If you find this helpful, we’d love your support! Please visit our CB page and drop a follow (tips are also greatly appreciated!
).
https://chaturbate.com/alyxxandmsstarzz/
The full code is pasted down below the screenshots...
Screenshots:


Full Code:
// Create Eye Contact tabconst chatTabDefault = document.querySelector("div#chat-tab-default");
if (chatTabDefault) {
const clonedTab = chatTabDefault.cloneNode(true);
// Modify cloned tab properties
clonedTab.id = "eye-contact-tab-default";
clonedTab.classList.replace("chat-tab-handle", "eye-contact-tab-handle");
clonedTab.setAttribute("data-testid", "eye-contact-tab-default");
const tabLabel = clonedTab.querySelector("span");
if (tabLabel) tabLabel.textContent = "EYE CONTACT CHAT";
// Insert cloned tab
chatTabDefault.parentElement.insertBefore(clonedTab, chatTabDefault);
// Ensure the Eye Contact tab is not active by default
clonedTab.classList.remove("active");
clonedTab.style.backgroundColor = "rgb(201, 201, 201)";
clonedTab.style.color = "rgb(76, 76, 76)";
clonedTab.style.cursor = "pointer";
}
// Tab behavior for switching
const allTabs = Array.from(
document.querySelectorAll(
"div#eye-contact-tab-default, div#chat-tab-default, div#pm-tab-default, div#users-tab-default, div#settings-tab-default"
)
).filter(Boolean);
const tsLeElement = document.querySelector('div[ts="le"]');
const messageList = document.querySelector(".msg-list-fvm.message-list");
const theaterChatDiv = document.querySelector(".ChatTabContents.TheatermodeChatDivChat");
// Helper to reset Eye Contact–specific styles
function resetEyeContactStyles() {
if (messageList) {
messageList.style.display = "";
messageList.style.flexDirection = "";
messageList.style.width = ""; // Reset width
messageList.style.margin = ""; // Reset margin
messageList.style.transform = "";
}
const msgListWrapper = document.querySelector('.msg-list-wrapper-split');
if (msgListWrapper) {
msgListWrapper.style.transform = "";
}
const noticeList = document.querySelector('.notice-list-fvm');
if (noticeList) {
noticeList.style.transform = "";
}
if (theaterChatDiv) {
theaterChatDiv.style.flexDirection = "column";
}
toggleFullscreen(false); // Exit fullscreen if active
// Reset emoji modal (regular) to default so it displays in front
const emojiModal = document.querySelector('.emojiSelectionModal');
if (emojiModal) {
emojiModal.style.position = '';
emojiModal.style.top = '';
emojiModal.style.left = '';
emojiModal.style.zIndex = '1001';
}
// Reset emojicon autocomplete modal styles to default
const emoticonList = document.querySelector('.autocompleteModal.theatermodeEmoticonAutocompleteModalChat');
if (emoticonList) {
emoticonList.style.top = '-181.337px';
emoticonList.style.bottom = '';
emoticonList.style.right = '';
emoticonList.style.left = '8px';
emoticonList.style.overflow = '';
emoticonList.style.maxHeight = '';
emoticonList.style.maxWidth = '';
emoticonList.style.width = '100%';
emoticonList.style.height = '';
emoticonList.style.zIndex = '1001';
}
}
// Helper to apply Eye Contact–specific styles
function applyEyeContactStyles() {
if (messageList) {
const msgListWrapper = document.querySelector('.msg-list-wrapper-split');
const noticeList = document.querySelector('.notice-list-fvm');
// Flip the scroll container
if (msgListWrapper) {
msgListWrapper.style.transform = 'scaleY(-1)';
}
// Ensure the message list uses column-reverse order and flip it back to normal
messageList.style.display = 'flex';
messageList.style.flexDirection = 'column-reverse';
messageList.style.transform = 'scaleY(-1)';
// Flip notice list elements back to normal
if (noticeList) {
noticeList.style.transform = 'scaleY(-1)';
}
// Additional styling specific to Eye Contact mode
messageList.style.width = "50%"; // Narrow the message container
messageList.style.margin = "0 auto"; // Center the container horizontally
// Set scroll position to the top so messages initiate at the top
messageList.scrollTop = 0;
}
if (theaterChatDiv) {
theaterChatDiv.style.flexDirection = "column-reverse";
}
toggleFullscreen(true); // Enter fullscreen
}
// Fullscreen toggle for Eye Contact tab
function toggleFullscreen(isActive) {
const chatTabContainer = document.querySelector("#ChatTabContainer");
if (isActive) {
if (chatTabContainer?.requestFullscreen) {
chatTabContainer.requestFullscreen();
} else if (chatTabContainer?.mozRequestFullScreen) {
chatTabContainer.mozRequestFullScreen();
} else if (chatTabContainer?.webkitRequestFullscreen) {
chatTabContainer.webkitRequestFullscreen();
} else if (chatTabContainer?.msRequestFullscreen) {
chatTabContainer.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
}
// Attach tab switching behavior
allTabs.forEach(tab => {
tab.addEventListener("click", () => {
// Reset all tabs to default styles
allTabs.forEach(otherTab => {
otherTab.classList.remove("active");
otherTab.style.backgroundColor = "rgb(201, 201, 201)";
otherTab.style.color = "rgb(76, 76, 76)";
otherTab.style.cursor = "pointer";
});
// Activate the clicked tab
tab.classList.add("active");
tab.style.backgroundColor = "rgb(255, 255, 255)";
tab.style.color = "rgb(220, 85, 0)";
tab.style.cursor = "default";
// Adjust UI based on the active tab
if (tsLeElement) {
if (tab.id === "chat-tab-default") {
tsLeElement.style.display = "block";
resetEyeContactStyles();
} else if (tab.id === "eye-contact-tab-default") {
tsLeElement.style.display = "block";
applyEyeContactStyles();
} else {
tsLeElement.style.display = "none";
resetEyeContactStyles();
}
}
// Update scroll button's SVG and text based on active tab
const scrollDownButton = document.querySelector('.scrollDownButton');
if (scrollDownButton) {
const svgElement = scrollDownButton.querySelector('svg');
const spanText = scrollDownButton.querySelector('span.scrollDownText');
if (tab.id === "eye-contact-tab-default") {
// For Eye Contact: flip SVG and set text to "Scroll to top"
if (svgElement) {
svgElement.style.transform = 'rotate(180deg)';
}
if (spanText) {
spanText.textContent = 'Scroll to top';
}
} else {
// For other tabs: restore the default SVG and set text to "Scroll to bottom"
if (svgElement) {
svgElement.setAttribute("width", "9px");
svgElement.setAttribute("height", "13px");
svgElement.setAttribute("viewBox", "0 0 9 13");
svgElement.setAttribute("fill", "none");
svgElement.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svgElement.innerHTML = `<path d="M4.50848 7.97048V1.5" stroke="white" stroke-width="1.4" stroke-linecap="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M1.24099 4.92406C0.957097 4.66164 0.496814 4.66164 0.21292 4.92406C-0.0709734 5.18648 -0.0709734 5.61194 0.21292 5.87436L3.90125 9.28368C4.18515 9.5461 4.64543 9.5461 4.92932 9.28368L8.67227 5.82387C8.95617 5.56145 8.95617 5.13599 8.67227 4.87357C8.38838 4.61115 7.9281 4.61115 7.6442 4.87357L4.41529 7.85823L1.24099 4.92406ZM0.655497 11.2058C0.298143 11.2058 0.00844965 11.4955 0.00844965 11.8528C0.00844965 12.2102 0.298143 12.4999 0.655498 12.4999H8.3614C8.71876 12.4999 9.00845 12.2102 9.00845 11.8528C9.00845 11.4955 8.71876 11.2058 8.3614 11.2058H0.655497Z" fill="white"></path>`;
svgElement.style.transform = "";
}
if (spanText) {
spanText.textContent = 'Scroll to bottom';
}
}
}
});
});
// Observe DOM changes to adjust emoji modals when the Eye Contact tab is active
const observer = new MutationObserver(() => {
const activeTab = document.querySelector(".tab.active");
if (activeTab && activeTab.id === "eye-contact-tab-default") {
// Relocate the emoji selection modal
const emojiSelectionModal = document.querySelector(".emojiSelectionModal");
const emojiSelectionModalOverlay = document.querySelector(".emojiSelectionModalOverlay");
if (emojiSelectionModal && emojiSelectionModalOverlay) {
emojiSelectionModal.style.position = "absolute";
emojiSelectionModal.style.top = "50px"; // Lower position for better visibility
emojiSelectionModal.style.right = "10px"; // Anchored to the right with a small margin
emojiSelectionModal.style.transform = "translateY(0)";
emojiSelectionModal.style.zIndex = "1001";
}
// Apply settings for the theater mode emojicon autocomplete modal
const emojiconList = document.querySelector('.autocompleteModal.theatermodeEmoticonAutocompleteModalChat');
if (emojiconList) {
emojiconList.style.top = '100%';
emojiconList.style.bottom = 'auto';
emojiconList.style.right = 'auto';
emojiconList.style.left = '0';
emojiconList.style.overflow = 'auto';
emojiconList.style.maxHeight = '';
emojiconList.style.maxWidth = '';
emojiconList.style.width = '100%';
emojiconList.style.height = 'auto';
emojiconList.style.borderTopWidth = 'none';
emojiconList.style.borderBottomWidth = '1px';
emojiconList.style.borderBottomStyle = 'solid';
}
}
});
// Start observing the body for changes
observer.observe(document.body, { childList: true, subtree: true });
// Disconnect observer when a different tab is active
document.querySelectorAll(".tab").forEach(tab => {
tab.addEventListener("click", () => {
const activeTab = document.querySelector(".tab.active");
if (activeTab && activeTab.id !== "eye-contact-tab-default") {
observer.disconnect();
} else {
observer.observe(document.body, { childList: true, subtree: true });
}
});
});
// Ensure that when the .msg-list-wrapper-split scrolls to the bottom,
// the scroll button text remains "Scroll to top" and the SVG stays flipped.
const msgWrapper = document.querySelector('.msg-list-wrapper-split');
if (msgWrapper) {
msgWrapper.addEventListener('scroll', () => {
const activeTab = document.querySelector('.tab.active');
if (activeTab && activeTab.id === 'eye-contact-tab-default') {
const scrollDownButton = document.querySelector('.scrollDownButton');
if (scrollDownButton) {
const spanText = scrollDownButton.querySelector('span.scrollDownText');
if (spanText) {
spanText.textContent = 'Scroll to top';
}
const svgElement = scrollDownButton.querySelector('svg');
if (svgElement) {
svgElement.style.transform = 'rotate(180deg)';
}
}
}
});
}
const targetDiv = document.querySelector('div#chat-tab-default');
if (targetDiv) {
const targetSpan = targetDiv.querySelector('span');
if (targetSpan) {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'characterData' || mutation.type === 'childList') {
if (targetSpan.textContent !== "DEFAULT") {
targetSpan.textContent = "DEFAULT";
}
}
});
});
observer.observe(targetSpan, { characterData: true, childList: true, subtree: true });
if (targetSpan.textContent !== "DEFAULT") {
targetSpan.textContent = "DEFAULT";
}
}
}
const data = {
message: "MutationObserver is set up to override the text content of the span to 'DEFAULT'."
}
Last edited: