Cómo Implementar un Chat en Blogger paso a paso

Cómo Implementar un Chat en Blogger con Firebase
En este tutorial aprenderás a crear un chat en tiempo real para Blogger usando Firebase. Este chat es totalmente responsive, minimalista y permite que tus visitantes interactúen fácilmente en tu blog.
Ver demo en vivo del chat1. Preparación: Crear un proyecto en Firebase
Para empezar necesitamos una cuenta de Firebase. Si no tienes una, ve a https://firebase.google.com y regístrate.
1.1 Crear un proyecto
- Entra a la consola de Firebase y haz clic en Agregar proyecto.
- Ingresa un nombre para tu proyecto, por ejemplo: chat-blogger.
- Desactiva o activa Google Analytics según tu preferencia y finaliza la creación.
1.2 Autenticación y Configuración de Dominio en el Chat de Blogger
El chat de Blogger que hemos implementado utiliza Firebase Authentication para gestionar los usuarios de manera segura. Actualmente, la autenticación se realiza mediante Google Sign-In, lo que permite a los visitantes iniciar sesión rápidamente sin necesidad de crear cuentas adicionales.
1.2.1 Pasos para habilitar la autenticación
- Ve a la consola de Firebase y selecciona tu proyecto.
- En el menú lateral, haz clic en Authentication → Métodos de acceso → Proveedores de acceso → Agregar Proveedor Nuevo.
- Activa el método Google y guarda los cambios.
1.2.2 Configurar dominio permitido
Para que la autenticación funcione correctamente, debes registrar el dominio de tu blog en Firebase:
- En la consola de Firebase, ve a Authentication → Configuración → dominios autorizados.
- Agrega el dominio donde está publicado tu blog, por ejemplo:
https://tublog.blogspot.com
. - Guarda los cambios. Sin esto, los usuarios no podrán iniciar sesión desde tu blog.
1.3 Configurar Realtime Database
- En el menú lateral Categorías de producto → Compilación, selecciona Realtime Database.
- Haz clic en Crear base de datos y selecciona tu ubicación.
- Para pruebas iniciales puedes usar reglas permisivas (solo mientras desarrollas):
{
{
"rules": {
"chat": {
".read": "auth != null",
".write": "auth != null",
".indexOn": ["timestamp"]
},
"online": {
".read": "auth != null",
".write": "auth != null"
}
}
}
2. Obtener la configuración de Firebase
Ve a Configuración del proyecto → Configuración general → Tus apps y agrega una app web. Copia la configuración de Firebase:
const firebaseConfig = {
apiKey: "TU_API_KEY",
authDomain: "TU_PROYECTO.firebaseapp.com",
databaseURL: "https://TU_PROYECTO.firebaseio.com",
projectId: "TU_PROYECTO",
storageBucket: "TU_PROYECTO.appspot.com",
messagingSenderId: "TU_MESSAGING_ID",
appId: "TU_APP_ID"
};
3. Insertar el chat en Blogger
Ahora vamos a insertar el chat en tiempo real en tu blog de Blogger:
3.1 Crear un gadget o entrada HTML
En Blogger, ve a Diseño → Añadir gadget → HTML/JavaScript y pega el siguiente código:
<!-- Chat App Blogger -->
<div id="chat-app" class="chat-container">
<div id="login-section" class="chat-login">
<button id="google-login">Iniciar sesión con Google</button>
</div>
<div id="chat-section" class="chat-area" style="display:none;">
<div id="online-users" class="online-users"></div>
<div id="messages" class="messages-list"></div>
<div id="new-message-alert" style="display:none;">⬆ Nuevo mensaje</div>
<!-- Caja de respuesta arriba del input -->
<div id="reply-box" class="reply-preview" style="display:none;">
<div><strong id="reply-author"></strong>: <span id="reply-text"></span></div>
<button onclick="cancelReply()" style="margin-left:6px;font-size:11px;">✖</button>
</div>
<!-- Input de mensaje y botón -->
<div class="chat-input">
<input type="text" id="message-input" placeholder="Escribe tu mensaje...">
<button id="send-btn">Enviar</button>
</div>
<button id="logout-btn">Cerrar sesión</button>
</div>
</div>
<audio id="notify-sound" src="https://actions.google.com/sounds/v1/alarms/beep_short.ogg" preload="auto"></audio>
3.2 Agregar estilos CSS
Pega el siguiente CSS para que el chat se vea minimalista y responsive:
<style>
/* Mantener todo tu CSS actual */
.chat-container { width:100%; max-width:100%; margin:0 auto; font-family: system-ui; border:1px solid #ddd; border-radius:12px; overflow:hidden; display:flex; flex-direction:column; background:#f9f9f9;}
.chat-login { text-align:center; padding:20px;}
.chat-login button, #send-btn, #logout-btn { background:#1f2937;color:#fff;border:none;padding:8px 14px;border-radius:6px;cursor:pointer;margin:5px 0;}
.chat-area { display:flex; flex-direction:column; height:500px;}
.online-users { background:#e0e0e0;padding:6px 10px;font-size:14px;border-bottom:1px solid #ccc;}
.messages-list { flex:1; overflow-y:auto; padding:10px; display:flex; flex-direction:column; gap:8px; position:relative;}
#new-message-alert { position:absolute; bottom:10px; left:50%; transform:translateX(-50%); background:#f59e0b; color:#fff; padding:4px 10px; border-radius:12px; cursor:pointer; font-weight:bold; z-index:10;}
.message-item { display:flex; align-items:flex-start; gap:8px; max-width:85%; padding:10px 12px; border-radius:12px; word-break:break-word; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,0.1);}
.message-item.self { align-self:flex-end; background:#1f2937; color:#fff;}
.message-item img { width:32px;height:32px;border-radius:50%; flex-shrink:0; margin-top:2px;}
.message-content { display:flex; flex-direction:column; gap:4px; flex:1;}
.message-author { font-weight:bold; font-size:13px;}
.message-text { font-size:14px; line-height:1.4;}
.message-footer { display:flex; justify-content:space-between; align-items:center; font-size:11px; color:#555;}
.message-item.self .message-footer { color:#ccc;}
.reactions { display:flex; gap:6px;}
.reaction-btn { background:#e5e7eb; padding:2px 6px; border-radius:12px; font-size:12px; cursor:pointer; display:flex; align-items:center; gap:2px; user-select:none;}
.message-item.self .reaction-btn { background:#374151;color:#fff;}
.reaction-counter { font-size:10px;}
.reply-preview { background:#e5e7eb; border-left:3px solid #3b82f6; padding:6px 10px; margin:0 10px 6px 10px; font-size:12px; border-radius:4px; color:#374151; display:flex; justify-content:space-between; align-items:center; flex-shrink:0; width:auto;}
.reply-preview strong { color:#111827;}
.message-reply { background:#f3f4f6; border-left:3px solid #3b82f6; padding:4px 6px; font-size:12px; border-radius:4px; margin-bottom:4px; color:#374151; cursor:pointer;}
.message-item.self .message-reply { background:#374151; color:#d1d5db;}
.message-date { text-align:center; font-size:12px; color:#888; margin:10px 0;}
.message-item a { color:#3b82f6; text-decoration:underline;}
.message-item.self a { color:#93c5fd;}
.chat-input { display:flex; gap:6px; padding:8px 10px; border-top:1px solid #ccc; background:#fafafa;}
.chat-input input#message-input { flex:1; padding:8px 12px; border-radius:20px; border:1px solid #ccc; outline:none; font-size:14px;}
.chat-input button#send-btn { background:#1f2937;color:#fff;border:none;padding:8px 14px;border-radius:20px;cursor:pointer;font-size:14px;transition:background 0.2s;}
.chat-input button#send-btn:hover { background:#111827;}
@media screen and (max-width:768px){.chat-container{border-radius:0;border:none;}.message-item{max-width:100%;}}
</style>
3.3 Agregar scripts de Firebase y chat
Incluye los scripts de Firebase y el script de tu chat:
<script src="https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.23.0/firebase-auth-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.23.0/firebase-database-compat.js"></script>
<script>
/* Firebase Config */
const firebaseConfig = {
apiKey: "TU_API_KEY",
authDomain: "TU_PROYECTO.firebaseapp.com",
databaseURL: "https://TU_PROYECTO.firebaseio.com",
projectId: "TU_PROYECTO",
storageBucket: "TU_PROYECTO.appspot.com",
messagingSenderId: "TU_MESSAGING_ID",
appId: "TU_APP_ID"
};
firebase.initializeApp(firebaseConfig);
const auth=firebase.auth(), db=firebase.database();
const loginSection=document.getElementById("login-section"),
chatSection=document.getElementById("chat-section"),
googleLoginBtn=document.getElementById("google-login"),
logoutBtn=document.getElementById("logout-btn"),
sendBtn=document.getElementById("send-btn"),
messageInput=document.getElementById("message-input"),
messagesList=document.getElementById("messages"),
onlineUsersDiv=document.getElementById("online-users"),
newMessageAlert=document.getElementById("new-message-alert");
let currentUser=null, autoScroll=true, lastMessageDate=null;
let replyTo=null, lastMessageKey=null, isLoadingOlder=false;
/* Login / Logout */
googleLoginBtn.addEventListener("click",()=>{auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());});
logoutBtn.addEventListener("click",()=>{if(currentUser)db.ref("online/"+currentUser.uid).remove();auth.signOut();});
auth.onAuthStateChanged(user=>{
if(user){
currentUser=user;
loginSection.style.display="none";
chatSection.style.display="flex";
db.ref("online/"+user.uid).set({name:user.displayName,photo:user.photoURL});
db.ref("online/"+user.uid).onDisconnect().remove();
loadMessages(); loadOnlineUsers();
} else {
currentUser=null; loginSection.style.display="block"; chatSection.style.display="none";
}
});
/* Enviar mensaje */
sendBtn.addEventListener("click",sendMessage);
messageInput.addEventListener("keypress",e=>{if(e.key==="Enter")sendMessage();});
function sendMessage(){
const text=messageInput.value.trim();
if(!text||!currentUser)return;
db.ref("chat").push({
author:currentUser.displayName,
photo:currentUser.photoURL,
uid:currentUser.uid,
message:text,
timestamp:Date.now(),
reactions:{},
replyTo: replyTo || null
});
messageInput.value="";
cancelReply();
}
/* Scroll y paginación */
messagesList.addEventListener("scroll",()=>{
const {scrollTop} = messagesList;
autoScroll = scrollTop + messagesList.clientHeight >= messagesList.scrollHeight-10;
if(scrollTop === 0 && !isLoadingOlder && lastMessageKey){
loadOlderMessages();
}
});
/* Formato y linkify */
const formatDate=ts=>new Date(ts).toLocaleDateString();
const formatTime=ts=>new Date(ts).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'});
const linkify=text=>text.replace(/(https?:\/\/[^\s]+)/g,'<a href="$1" target="_blank" rel="noopener">$1</a>');
/* Reacciones */
function addReaction(messageId,emoji){
if(!currentUser)return;
const ref=db.ref("chat/"+messageId+"/reactions/"+currentUser.uid);
ref.once("value",snap=>{if(snap.exists()&&snap.val()===emoji)ref.remove();else ref.set(emoji);});
}
/* Responder */
function replyMessage(messageId, author, text){
replyTo = {id: messageId, author, text};
document.getElementById("reply-author").textContent = author;
document.getElementById("reply-text").textContent = text.substring(0,40)+"...";
document.getElementById("reply-box").style.display = "flex";
}
function cancelReply(){ replyTo = null; document.getElementById("reply-box").style.display = "none"; }
function scrollToMessage(id){
const target=document.getElementById("msg-"+id);
if(target){ target.scrollIntoView({behavior:"smooth",block:"center"}); target.style.boxShadow="0 0 10px #3b82f6"; setTimeout(()=>target.style.boxShadow="",1500); }
}
/* Cargar mensajes iniciales */
function loadMessages(){
db.ref("chat").orderByKey().limitToLast(50).on("child_added",snap=>{renderMessage(snap.key,snap.val()); lastMessageKey=snap.key;});
db.ref("chat").on("child_changed",snap=>{renderMessage(snap.key,snap.val(),true);});
db.ref("chat").on("child_removed",snap=>{
const div=document.getElementById("msg-"+snap.key);
if(div) div.remove();
});
}
/* Cargar mensajes antiguos (scroll arriba) */
function loadOlderMessages(){
if(!lastMessageKey) return;
isLoadingOlder = true;
db.ref("chat").orderByKey().endBefore(lastMessageKey).limitToLast(50).once("value",snap=>{
const items = [];
snap.forEach(s => items.push({key:s.key,val:s.val()}));
items.sort((a,b)=>a.val.timestamp-b.val.timestamp);
items.forEach(item => { renderMessage(item.key,item.val); lastMessageKey=item.key; });
isLoadingOlder = false;
});
}
/* Renderizado mensajes con eliminar */
function renderMessage(id,msg,update=false){
const msgDate=formatDate(msg.timestamp);
if(!update && lastMessageDate!==msgDate){
const d=document.createElement("div");
d.className="message-date"; d.textContent=msgDate;
messagesList.appendChild(d);
lastMessageDate=msgDate;
}
let div=document.getElementById("msg-"+id);
if(!div){
div=document.createElement("div");
div.className="message-item"; div.id="msg-"+id;
if(currentUser && msg.uid===currentUser.uid) div.classList.add("self");
messagesList.appendChild(div);
}
const counts={}; if(msg.reactions)Object.values(msg.reactions).forEach(e=>counts[e]=(counts[e]||0)+1);
let reactionsHtml=""; for(let e in counts) reactionsHtml+=`<span class="reaction-btn">${e}<span class="reaction-counter">${counts[e]}</span></span>`;
let replyHtml = "";
if(msg.replyTo){
replyHtml = `<div class="message-reply" onclick="scrollToMessage('${msg.replyTo.id}')"><strong>${msg.replyTo.author}</strong>: ${msg.replyTo.text.substring(0,50)}...</div>`;
}
let deleteBtn = "";
if(currentUser && msg.uid === currentUser.uid){
deleteBtn = `<span class="reaction-btn" style="background:#ef4444;color:#fff;" onclick="deleteMessage('${id}')">🗑️</span>`;
}
div.innerHTML=`
<img src="${msg.photo}" alt="${msg.author}">
<div class="message-content">
<div class="message-author">${msg.author}</div>
${replyHtml}
<div class="message-text">${linkify(msg.message)}</div>
<div class="message-footer">
<span class="message-time">${formatTime(msg.timestamp)}</span>
<div class="reactions">
<span class="reaction-btn" onclick="addReaction('${id}','👍')">👍</span>
<span class="reaction-btn" onclick="addReaction('${id}','❤️')">❤️</span>
<span class="reaction-btn" onclick="replyMessage('${id}','${msg.author}','${msg.message.replace(/"/g,""")}')">💬</span>
${reactionsHtml} ${deleteBtn}
</div>
</div>
</div>
`;
if(autoScroll) messagesList.scrollTop = messagesList.scrollHeight;
else newMessageAlert.style.display="block";
}
/* Eliminar mensaje */
function deleteMessage(id){
if(confirm("¿Eliminar este mensaje?")) db.ref("chat/"+id).remove();
}
/* Alert scroll */
newMessageAlert.addEventListener("click",()=>{messagesList.scrollTop=messagesList.scrollHeight; newMessageAlert.style.display="none";});
/* Usuarios conectados */
function loadOnlineUsers(){db.ref("online").on("value",snap=>{const u=[];snap.forEach(c=>u.push(c.val().name));onlineUsersDiv.innerHTML="Conectados: "+u.join(", ");});}
</script>
4. Cómo funciona este chat
- Permite iniciar sesión con Google y publicar mensajes en tiempo real.
- Los usuarios conectados se muestran en la parte superior.
- Se puede responder a mensajes y ver de quién es cada mensaje.
- Funciona en móviles y PC, totalmente responsive.
- Reacciones con emojis disponibles para cada mensaje.
5. Recomendaciones finales
Para un blog en producción, recuerda:
- Actualizar las reglas de Firebase para seguridad.
- Probar el chat en distintos dispositivos para asegurar la compatibilidad responsive.
- Personalizar colores, tamaño y estilo según tu plantilla.
Descarga gratis el código completo
Descarga ahora el código completo del chat y pégalo fácilmente en tu entrada de Blogger, página o cualquier CMS externo. ¡Implementa tu chat en minutos!
¡Descargar Ahora!Conclusión
Con este tutorial puedes crear un chat para Blogger funcional, seguro y moderno usando Firebase Realtime Database. Tus visitantes podrán interactuar en tiempo real y tu blog ganará una experiencia más interactiva.
Aún no hay comentarios, sé el primero en comentar.
Publicar un comentario