[{"data":1,"prerenderedAt":1110},["ShallowReactive",2],{"blog-es-supabase-email-rate-limit-exceeded":3,"blog-index-es":580},{"id":4,"title":5,"body":6,"category":535,"cover":536,"coverAlt":537,"description":538,"draft":539,"extension":540,"faq":541,"image":560,"keywords":561,"meta":569,"navigation":570,"ogTitle":5,"path":571,"published":572,"seo":573,"stem":574,"tldr":575,"updated":572,"__hash__":579},"blog_es\u002Fblog\u002Fsupabase-email-rate-limit-exceeded.md","Supabase \"Email Rate Limit Exceeded\": dos límites, un solo código",{"type":7,"value":8,"toc":522},"minimark",[9,18,28,31,43,48,51,54,73,91,110,116,124,128,131,188,200,207,212,216,219,234,237,241,249,252,258,265,287,291,294,318,321,346,353,357,364,370,373,384,389,393,396,402,412,416,419,428,446,455,475,479,516],[10,11,12,13,17],"p",{},"Estás probando tu formulario de registro antes de compartir la app. Te registras\ncon tu propia dirección, luego con ",[14,15,16],"code",{},"tu+2@gmail.com",", y luego una vez más para ver\nsi el email de confirmación se ve bien. Uno de esos intentos se detiene aquí:",[19,20,25],"pre",{"className":21,"code":23,"language":24},[22],"language-text","AuthApiError: email rate limit exceeded\n","text",[14,26,23],{"__ignoreMap":27},"",[10,29,30],{},"Supabase \"Email Rate Limit Exceeded\" significa que tu proyecto gastó su cupo de\nemails de la hora, así que Supabase Auth, la parte de Supabase que inicia la\nsesión de la gente, se negó a enviar otro. Con el servicio de email con el que\narranca todo proyecto, ese cupo es de dos emails por hora para todo el proyecto.",[10,32,33,34,38,39,42],{},"Aquí está la parte que es fácil entender al revés: ",[35,36,37],"strong",{},"el código de error cubre dos\nlímites distintos."," La propia lista de códigos de error de Auth de Supabase\ndescribe ",[14,40,41],{},"over_email_send_rate_limit"," como \"Too many emails have been sent to this\nemail address.\" Eso es cierto para uno de los dos. El mismo código también vuelve\ncuando todo el proyecto se quedó sin cupo, sea quien sea el destinatario, así que\nprobar con otra dirección no cambia nada. Y el consejo habitual, \"conecta tu\npropio SMTP\", es la mitad del arreglo, porque Supabase arranca un servidor de\nemail recién conectado en 30 emails por hora.",[44,45,47],"h2",{"id":46},"qué-significa-email-rate-limit-exceeded-en-supabase","¿Qué significa \"Email rate limit exceeded\" en Supabase?",[10,49,50],{},"Que tu proyecto ya envió en esta hora todos los emails que Supabase Auth\npermite, y el siguiente fue rechazado.",[10,52,53],{},"Piensa en el cupo como una hoja de sellos. Supabase le da a cada proyecto un\nnúmero fijo de sellos por hora, y cada email que envía Supabase Auth gasta uno,\nsea del tipo que sea y vaya para quien vaya:",[55,56,57,61,64,67,70],"ul",{},[58,59,60],"li",{},"el enlace de confirmación después de que alguien se registra",[58,62,63],{},"un magic link o un código de un solo uso para iniciar sesión",[58,65,66],{},"un restablecimiento de contraseña",[58,68,69],{},"una invitación que envías desde la página Users",[58,71,72],{},"la confirmación cuando alguien cambia su dirección de email",[10,74,75,76,78,79,82,83,90],{},"Cuando la hoja se vacía, Supabase Auth responde con HTTP 429, que significa\n\"demasiadas solicitudes\", el código ",[14,77,41],{}," y el mensaje\n",[14,80,81],{},"email rate limit exceeded",". Esas palabras salen\n",[84,85,89],"a",{"href":86,"rel":87},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Fmail.go",[88],"nofollow","del propio código del servidor de Supabase Auth",".",[10,92,93,94,97,98,103,104,109],{},"Con el remitente integrado, el servicio de email con el que arranca un proyecto\nnuevo, la hoja tiene ",[35,95,96],{},"dos sellos por hora",". Es la cifra de la\n",[84,99,102],{"href":100,"rel":101},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Frate-limits",[88],"página de límites de Supabase","\ncuando la leímos el 20 de octubre de 2026, y la\n",[84,105,108],{"href":106,"rel":107},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fauth-smtp",[88],"guía de SMTP de Supabase"," dice\nque \"can change without notice\". A dos por hora, un registro y un restablecimiento\nde contraseña son todo el cupo de la hora.",[111,112],"diagram",{"alt":113,"caption":114,"src":115},"Cuatro tipos de email, para una cuenta nueva, un enlace de inicio de sesión, un restablecimiento de contraseña y una invitación, toman todos de una misma hoja que tiene dos sellos por hora. Dos sobres salen sellados. Los otros dos se quedan parados en una barrera, sin sello.","Cada email que envía Supabase Auth gasta un sello de la misma hoja. Con el remitente integrado, la hoja tiene dos por hora.","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fone-sheet-every-email-1600x760.png",[10,117,118,119,123],{},"Si nadie puede iniciar sesión, o toda la app está en blanco, lo que tienes es\notra cosa, y\n",[84,120,122],{"href":121},"\u002Fblog\u002Fis-supabase-down-or-your-app","¿Supabase está caído o es tu app?"," es por\ndonde empezar.",[44,125,127],{"id":126},"dos-límites-comparten-un-código-de-error","Dos límites comparten un código de error",[10,129,130],{},"El mensaje te dice qué límite alcanzaste. El código es el mismo para los dos:",[132,133,134,153],"table",{},[135,136,137],"thead",{},[138,139,140,144,147,150],"tr",{},[141,142,143],"th",{},"El mensaje",[141,145,146],{},"Qué limita",[141,148,149],{},"Qué cuenta",[141,151,152],{},"El valor por defecto",[154,155,156,172],"tbody",{},[138,157,158,163,166,169],{},[159,160,161],"td",{},[14,162,81],{},[159,164,165],{},"Todo el proyecto",[159,167,168],{},"Cada email que envía Supabase Auth, por hora",[159,170,171],{},"2 por hora con el remitente integrado, 30 cuando conectas el tuyo",[138,173,174,179,182,185],{},[159,175,176],{},[14,177,178],{},"For security purposes, you can only request this after N seconds.",[159,180,181],{},"Una dirección",[159,183,184],{},"El mismo tipo de email, enviado otra vez a la misma dirección",[159,186,187],{},"Uno cada 60 segundos",[10,189,190,191,193,194,199],{},"Los dos responden HTTP 429 con ",[14,192,41],{},". La\n",[84,195,198],{"href":196,"rel":197},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fdebugging\u002Ferror-codes",[88],"lista de códigos de error de Auth","\nde Supabase te pide identificar los errores por su código y \"not string matching\non error messages\". Eso está bien para el código de tu app, y aquí deja un hueco:\nsolo el mensaje dice qué límite alcanzaste. Así que lee el mensaje para entender\nqué pasó, y deja que tu app reaccione al código.",[10,201,202,203,206],{},"Si tu app solo dice \"algo salió mal\", el mensaje exacto está en la respuesta a la\nsolicitud fallida, en la pestaña Red de las herramientas para desarrolladores de\ntu navegador. Un código ",[14,204,205],{},"over_request_rate_limit"," es un tercer límite, sobre las\nsolicitudes desde una misma dirección IP, y la lista de Supabase dice que puede\nseñalar un fallo en tu app que envía demasiadas.",[111,208],{"alt":209,"caption":210,"src":211},"Dos paneles. En el de la izquierda, la hoja de sellos del proyecto está vacía y tres sobres para tres personas distintas están parados. En el de la derecha, una persona ya recibió un sobre, y un segundo para la misma persona espera junto a un reloj que marca 60 segundos. Los dos paneles llevan al mismo código de error, over_email_send_rate_limit, con estado 429.","Una hoja vacía y una espera de 60 segundos son rechazos distintos, y Supabase informa los dos con el mismo código.","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Ftwo-refusals-one-code-1600x720.png",[44,213,215],{"id":214},"por-qué-dice-you-can-only-request-this-after-0-seconds","¿Por qué dice \"you can only request this after 0 seconds\"?",[10,217,218],{},"Porque quedaba menos de un segundo de espera. El límite por dirección permite un\nemail de cada tipo a la misma dirección cada 60 segundos: una confirmación de\nregistro, un restablecimiento de contraseña, un magic link o un código. Si lo\npides antes, Supabase Auth calcula cuánto falta y lo pone en el mensaje.",[10,220,221,222,229,230,233],{},"Cuenta en segundos enteros y descarta el resto. La función del servidor de Auth\nque escribe este mensaje\n(",[84,223,226],{"href":224,"rel":225},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Ferrors.go",[88],[14,227,228],{},"errors.go",")\ndivide el tiempo restante entre un segundo, así que 0,8 segundos se muestra como\n",[14,231,232],{},"0",". Vuelve a intentarlo un momento después y pasa, siempre que al tope por hora\ndel proyecto le quede un sello.",[10,235,236],{},"Esta espera funciona como debe. Es lo que impide que un botón de reenviar,\npulsado veinte veces, envíe veinte emails. Déjala en 60 segundos y deja que tu\nformulario la explique.",[44,238,240],{"id":239},"el-tope-por-hora-y-para-quién-es","El tope por hora, y para quién es",[10,242,243,244,248],{},"El remitente integrado es para probar Supabase, y Supabase lo dice en su\n",[84,245,247],{"href":106,"rel":246},[88],"guía de SMTP",". Ahí enumera para\nqué está pensado el servicio: \"Exploring and getting started with Supabase\nAuth\", \"Setting up and testing email templates with the members of the project's\nteam\" y \"Building toy projects, demos or any non-mission-critical application\".\nTambién viene con \"No SLA guarantee on message delivery or uptime\".",[10,250,251],{},"La misma guía tiene una segunda regla, y es la que decide quién ve cada error.\nMientras no conectes tu propio servidor de email, Supabase Auth \"will refuse to\ndeliver messages to addresses that are not part of the project's team\". Un\ncliente que se registra con su propia dirección queda rechazado antes de que se\ncuente ningún sello, con otro mensaje:",[19,253,256],{"className":254,"code":255,"language":24},[22],"Email address \"customer@example.com\" cannot be used as it is not authorized\n",[14,257,255],{"__ignoreMap":27},[10,259,260,261,264],{},"Eso es HTTP 400 con el código ",[14,262,263],{},"email_address_not_authorized",", y en el código del\nservidor de Auth esta comprobación va antes que los dos límites. Si el registro\nfunciona cuando lo pruebas tú y falla para todos los demás, este es el motivo.",[10,266,267,268,270,271,274,275,278,279,282,283,286],{},"Así que, con el remitente integrado, ",[14,269,81],{}," le toca sobre\ntodo a ti y a tu equipo, al probar. Cuando el servidor de Auth comprueba si una\ndirección es de tu equipo, ignora todo lo que haya entre un ",[14,272,273],{},"+"," y la ",[14,276,277],{},"@",". Por eso\n",[14,280,281],{},"tu+test1@gmail.com"," y ",[14,284,285],{},"tu+test2@gmail.com"," cuentan los dos como tú, y cada\nregistro de prueba gasta uno de los mismos dos sellos.",[44,288,290],{"id":289},"cómo-subo-el-límite-de-emails-de-supabase","¿Cómo subo el límite de emails de Supabase?",[10,292,293],{},"Conecta tu propio proveedor de email y luego sube el límite que Supabase le pone.\nSon dos pasos separados, y el segundo es el que se olvida.",[295,296,297,306,312],"ol",{},[58,298,299,302,303,90],{},[35,300,301],{},"Elige un servicio de envío y consigue sus datos SMTP."," La guía de Supabase\nnombra Resend, AWS SES, Postmark, Twilio SendGrid, ZeptoMail y Brevo, y dice\nque cualquier servicio que admita SMTP funcionará. Necesitas el host, el\npuerto, un usuario y una contraseña, además de una dirección de remitente como\n",[14,304,305],{},"no-reply@tudominio.com",[58,307,308,311],{},[35,309,310],{},"Activa el SMTP personalizado"," en los ajustes de Authentication de tu\nproyecto y escribe esos datos. Desde entonces Supabase envía a cualquier\ndirección.",[58,313,314,317],{},[35,315,316],{},"Sube el límite de emails"," en la página Rate Limits, también dentro de\nAuthentication. La guía dice que un servidor recién conectado recibe \"a low\nrate-limit of 30 messages per hour\" para proteger su reputación, y que se\ncambia ahí. Ponlo en lo que tu proveedor permita y en lo que necesite tu hora\nde más movimiento.",[10,319,320],{},"Otras tres cosas de la misma guía van con este cambio:",[55,322,323,329,335],{},[58,324,325,328],{},[35,326,327],{},"Configura DKIM, DMARC y SPF"," para tu dominio de envío, con tu proveedor.\nSupabase dice que esto \"will significantly increase the deliverability of your\nmessages\".",[58,330,331,334],{},[35,332,333],{},"Activa CAPTCHA en los registros."," La guía señala a los bots que registran\nlistas de direcciones como \"a common source of abuse\", y cada uno de esos\nregistros es un email sacado de tu hora. Llama a CAPTCHA \"the most effective\nway\" de frenarlos.",[58,336,337,340,341,345],{},[35,338,339],{},"Comprueba que no se esté cerrando la sesión de tus usuarios."," Según la guía,\nlas sesiones cortas obligan a \"active users to sign in frequently, increasing\nthe number of messages\", y si tus usuarios entran con un enlace por email, cada\ncierre de sesión inesperado cuesta un sello.\n",[84,342,344],{"href":343},"\u002Fblog\u002Fsupabase-users-logged-out","Por qué Supabase cierra la sesión de tus usuarios","\nexplica las causas.",[10,347,348,349,90],{},"Para los otros límites con los que se topa un proyecto gratuito, mira\n",[84,350,352],{"href":351},"\u002Fblog\u002Fsupabase-free-plan-limits","qué incluye el plan gratuito de Supabase",[44,354,356],{"id":355},"manejar-el-error-en-tu-formulario-de-registro","Manejar el error en tu formulario de registro",[10,358,359,360,363],{},"Atrápalo por su código y dile a la persona qué hacer, con palabras claras. El\ncliente de JavaScript de Supabase pone el código del servidor en el error que\ndevuelve, como ",[14,361,362],{},"error.code",", así que la comprobación es una línea:",[19,365,368],{"className":366,"code":367,"language":24},[22],"const { error } = await supabase.auth.signUp({ email, password })\n\nif (error?.code === 'over_email_send_rate_limit') {\n  \u002F\u002F mostrar: \"No pudimos enviar tu email ahora mismo. Vuelve a intentarlo en un minuto.\"\n}\n",[14,369,367],{"__ignoreMap":27},[10,371,372],{},"Pídele a tu herramienta, sea Lovable, Bolt, v0, Cursor, Claude Code o Replit,\ntres cosas:",[55,374,375,378,381],{},[58,376,377],{},"la misma comprobación en cada formulario que envía un email: registro, \"olvidé\nmi contraseña\", inicio de sesión con enlace por email y \"reenviar\"",[58,379,380],{},"un mensaje que pida a la persona volver a intentarlo en un rato, en lugar del\nerror en bruto o de un formulario que no hace nada sin avisar",[58,382,383],{},"el botón de reenviar desactivado 60 segundos después de cada envío, para que\nnadie pueda pulsarlo dentro de la espera por dirección",[10,385,386,387,90],{},"No pongas reintentos automáticos. Mientras la hoja esté vacía, cada reintento se\nrechaza, y las solicitudes de registro además están limitadas por dirección IP, a\n30 cada 5 minutos por defecto. Un bucle de reintentos también puede activar ese\nlímite, que responde con ",[14,388,205],{},[44,390,392],{"id":391},"qué-no-cambiar-mientras-los-registros-están-atascados","Qué no cambiar mientras los registros están atascados",[10,394,395],{},"La confirmación por email, y desde dónde salen los emails. Hay dos atajos que\nhacen desaparecer el error y te dejan peor.",[10,397,398,401],{},[35,399,400],{},"Deja activada la confirmación por email."," Si desactivas \"Confirm email\", los\nregistros dejan de enviar nada y el error se va. La guía de SMTP de Supabase\nincluye \"Do not disable email confirmations under pressure\" entre sus defensas,\nporque sin confirmación alguien puede crear una cuenta a nombre de otra persona.",[10,403,404,407,408,90],{},[35,405,406],{},"Mantén los emails fuera del navegador."," Pídele a un asistente que \"envíe la\nconfirmación con Resend y ya\" y puede meter la clave de API del proveedor en el\ncódigo frontend de tu app, donde cualquier visitante puede leerla y enviar\ncorreos en tu nombre. Envía los emails con los ajustes SMTP de Supabase o con una\nfunción del lado del servidor, nunca con una clave en la página. Si no estás\nseguro de que no se coló ninguna, nuestro escaneo gratuito lee el código que tu\napp en vivo envía a cada visitante y marca las claves secretas que encuentra\nahí. Tarda unos 20 segundos y no pide cuenta:\n",[84,409,411],{"href":410},"\u002Fsecurity-scanner","escanea tu app",[44,413,415],{"id":414},"vigilar-la-app-mientras-cambias-cómo-envía-los-emails","Vigilar la app mientras cambias cómo envía los emails",[10,417,418],{},"Dos cosas pueden salir mal mientras rehaces el envío de emails: una clave acaba en\nel código de tu app, y un mensaje que dice \"nadie puede registrarse\" te manda a\nbuscar una caída.",[10,420,421],{},[35,422,423,427],{},[84,424,426],{"href":425},"\u002Fwebsite-monitoring","Reeve Monitor"," sigue comprobando desde fuera:",[55,429,430,433,436,443],{},[58,431,432],{},"si tu app responde, comprobado cada minuto, para saber enseguida si una queja sobre el registro es una caída o algo más acotado",[58,434,435],{},"la comprobación de seguridad completa cada hora, en hasta tres apps, incluidas las claves secretas en el código que tu app envía a los visitantes",[58,437,438,439,442],{},"un mensaje cuando un resultado ",[35,440,441],{},"cambia",", para que una clave que sale con un despliegue posterior te llegue sin que tengas que ir a mirar",[58,444,445],{},"un informe mensual, en lenguaje claro, de lo que vio",[10,447,448],{},[35,449,450,454],{},[84,451,453],{"href":452},"\u002Fsupabase-backups","Reeve Care"," guarda una copia de tu base de datos de Supabase:",[55,456,457,460,463,466,469,472],{},[58,458,459],{},"una copia cifrada según un calendario, en el almacenamiento propio de Reeve en la UE, fuera de tu cuenta de Supabase",[58,461,462],{},"el esquema auth, donde vive cada cuenta que sí logró registrarse",[58,464,465],{},"cada copia verificada antes de contar, contando las filas de cada tabla",[58,467,468],{},"también tus archivos subidos, en cuanto conectas una credencial de Storage",[58,470,471],{},"una restauración con un clic, con una copia de seguridad del estado actual tomada antes",[58,473,474],{},"todo lo que hace Monitor",[44,476,478],{"id":477},"qué-hacer-ahora","Qué hacer ahora",[480,481,482],"key-takeaways",{},[55,483,484,494,501,504,507,513],{},[58,485,486,487,489,490,493],{},"Lee el mensaje además del código: ",[14,488,81],{}," es el tope por hora del proyecto, y ",[14,491,492],{},"For security purposes…"," es la espera de 60 segundos para una dirección.",[58,495,496,497,500],{},"Si tus clientes ven ",[14,498,499],{},"Email address … cannot be used as it is not authorized",", tu proyecto sigue con el remitente integrado de Supabase, que solo escribe a tu equipo.",[58,502,503],{},"Conecta tu propio proveedor SMTP y luego sube el límite de emails en la página Rate Limits, que empieza en 30 por hora.",[58,505,506],{},"Configura DKIM, DMARC y SPF con tu proveedor, y activa CAPTCHA en los registros.",[58,508,509,510,512],{},"Haz que cada formulario que envía un email compruebe ",[14,511,41],{},", muestre un mensaje claro y bloquee el botón de reenviar 60 segundos.",[58,514,515],{},"Deja activada la confirmación por email, y nunca pongas la clave de un proveedor de email en tu frontend.",[10,517,518,519,521],{},"Empieza por el mensaje de la respuesta fallida, porque te dice cuál de los dos\nlímites alcanzaste. Luego, cuando los emails ya salgan por tu propio proveedor,\n",[84,520,411],{"href":410}," para comprobar que no se coló ninguna clave\npor el camino.",{"title":27,"searchDepth":523,"depth":523,"links":524},3,[525,527,528,529,530,531,532,533,534],{"id":46,"depth":526,"text":47},2,{"id":126,"depth":526,"text":127},{"id":214,"depth":526,"text":215},{"id":239,"depth":526,"text":240},{"id":289,"depth":526,"text":290},{"id":355,"depth":526,"text":356},{"id":391,"depth":526,"text":392},{"id":414,"depth":526,"text":415},{"id":477,"depth":526,"text":478},"Fundamentos de seguridad","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcover-1200x630.png","Una hoja de sellos a la que ya le arrancaron todos, junto a una pila de sobres cerrados que no llevan nada en la esquina.","Supabase \"Email Rate Limit Exceeded\" limita cada email que envía tu proyecto: 2 por hora con el remitente integrado. Qué cuenta y cómo subirlo.",false,"md",[542,545,548,551,554,557],{"q":543,"a":544},"¿Qué significa \"email rate limit exceeded\" en Supabase?","Que tu proyecto ya envió en esta hora todos los emails que Supabase Auth permite, así que el siguiente fue rechazado. La cuenta incluye cada email que envía Auth, a quien sea: confirmaciones de registro, magic links, restablecimientos de contraseña e invitaciones. Con el remitente integrado son 2 por hora. Con tu propio proveedor SMTP el número lo pones tú.",{"q":546,"a":547},"¿Por qué dice que solo puedo volver a pedirlo después de 0 segundos?","Porque quedaba menos de un segundo de la espera de 60. Supabase Auth cuenta el tiempo restante en segundos enteros y descarta el resto, así que el último segundo se muestra como 0. Vuelve a intentarlo un momento después y el email sale, siempre que el tope por hora todavía tenga sitio.",{"q":549,"a":550},"¿Cuántos emails puede enviar Supabase por mí?","Con el remitente integrado, 2 por hora para todo el proyecto, y solo a personas de tu equipo de Supabase. Supabase dice que esa cifra puede cambiar sin aviso. Con tu propio proveedor SMTP no hay una cifra fija: Supabase empieza en 30 por hora y tú la subes en la página Rate Limits.",{"q":552,"a":553},"¿Necesito mi propio proveedor SMTP?","Sí, en cuanto alguien de fuera de tu equipo se registre por email. El remitente integrado rechaza las direcciones que no están en tu equipo, y Supabase lo describe como pensado para probar, para ensayar plantillas y para demos. Resend, AWS SES, Postmark, SendGrid, ZeptoMail y Brevo están entre los servicios que Supabase menciona como compatibles.",{"q":555,"a":556},"¿Cómo evito que esto rompa mi formulario de registro?","Revisa el código del error antes de que nada llegue a la pantalla. Si es over_email_send_rate_limit, muestra un mensaje claro que pida volver a intentarlo en un minuto, y deja el botón de reenviar desactivado 60 segundos después de cada envío, para que nadie pueda pulsarlo dentro de la espera.",{"q":558,"a":559},"¿Por qué mis clientes reciben \"Email address not authorized\"?","Porque tu proyecto todavía envía con el remitente integrado de Supabase, que solo entrega a miembros de tu organización de Supabase. A todos los demás los rechaza con el código email_address_not_authorized. Conectar tu propio proveedor SMTP lo arregla, y es el mismo cambio que quita el tope por hora.","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",[562,563,41,564,565,566,567,568],"email rate limit exceeded supabase","supabase email rate limit exceeded","for security purposes you can only request this after","supabase límite smtp","supabase no llega el email de confirmación","supabase magic link no llega","email address not authorized supabase",{},true,"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","2026-10-20",{"title":5,"description":538},"blog\u002Fsupabase-email-rate-limit-exceeded",[576,577,578],"Supabase \"Email Rate Limit Exceeded\" significa que tu proyecto ya envió en esta hora todos los emails que tiene permitidos. Con el remitente integrado son 2 por hora, y cuenta cada confirmación de registro, cada magic link y cada restablecimiento de contraseña.","El mismo código, over_email_send_rate_limit, también vuelve como \"For security purposes, you can only request this after N seconds\", una espera de 60 segundos para una sola dirección. Solo el mensaje distingue uno de otro.","Tu propio proveedor SMTP quita el tope por hora una vez que también subes el límite en la página Rate Limits, que lo empieza en 30 por hora. La espera de 60 segundos se queda, y tu formulario debería explicarla.","DBYqUOsDtnmbLOX0nzWjU5hTJdU3uwbOY-H5xlRZoN4",[581,587,593,599,605,611,617,623,629,635,641,648,654,660,666,672,678,684,690,696,702,703,708,714,720,726,732,738,744,750,756,762,768,774,780,786,792,798,804,810,815,821,826,832,838,844,849,855,861,867,873,879,885,891,897,903,909,915,921,927,933,939,945,951,957,963,969,975,981,987,993,999,1005,1011,1017,1023,1029,1035,1041,1047,1053,1059,1065,1071,1076,1082,1088,1094,1099,1105],{"path":582,"title":583,"description":584,"published":585,"category":535,"image":586,"draft":539},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": el pooler no tiene sitio para un cliente más. El puerto de tu cadena de conexión decide el límite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":588,"title":589,"description":590,"published":591,"category":535,"image":592,"draft":539},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Error de Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": Google está desactivado en tu proyecto Supabase. Cómo activarlo y arreglar redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":594,"title":595,"description":596,"published":597,"category":535,"image":598,"draft":539},"\u002Fblog\u002Fviolates-foreign-key-constraint","Error de Supabase \"violates foreign key constraint\" al insertar","Supabase \"insert or update on table violates foreign key constraint\": tu fila apunta a una fila que no existe. Cuál, por qué, y cómo arreglarlo.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":600,"title":601,"description":602,"published":603,"category":535,"image":604,"draft":539},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Error de Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": una columna obligatoria llegó vacía. De dónde vino el null, y cómo arreglarlo.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":606,"title":607,"description":608,"published":609,"category":535,"image":610,"draft":539},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": adónde fue la sesión","\"Auth session missing!\" es supabase-js sin encontrar ninguna sesión iniciada y sin llegar a preguntar a Supabase. Adónde fue la sesión, y el arreglo.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":612,"title":613,"description":614,"published":615,"category":535,"image":616,"draft":539},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": no hay nadie conectado","\"invalid claim: missing sub claim\": Supabase Auth recibió un token auténtico sin ningún usuario, la clave del proyecto en lugar de una sesión.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":618,"title":619,"description":620,"published":621,"category":535,"image":622,"draft":539},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": la causa real","\"Failed to send a request to the Edge Function\": el navegador no recibió una respuesta legible. Su consola dice por qué y si tu función se ejecutó.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":624,"title":625,"description":626,"published":627,"category":535,"image":628,"draft":539},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por qué los enlaces de email de Supabase redirigen a localhost:3000","Si Supabase redirige a localhost:3000, la Site URL nunca se cambió o tu dirección falta en Redirect URLs. La solución, y el comodín que debes evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":630,"title":631,"description":632,"published":633,"category":535,"image":634,"draft":539},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" con un enlace nuevo","Con un enlace enviado hace un minuto, \"Email link is invalid or has expired\" en Supabase suele indicar que un filtro de correo lo usó antes. Cómo arreglarlo.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":636,"title":637,"description":638,"published":639,"category":535,"image":640,"draft":539},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": una consulta superó el límite de su rol, 3 segundos para un visitante. Revisa antes la política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":642,"title":643,"description":644,"published":645,"category":646,"image":647,"draft":539},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" en Supabase, y qué se va con él","\"Database error deleting user\" en Supabase: tu base de datos rechazó el borrado. La causa está en tus logs y el arreglo decide qué más se borra.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":649,"title":650,"description":651,"published":652,"category":535,"image":653,"draft":539},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" en Supabase","¿Tu webhook de Stripe en una Edge Function de Supabase dice \"No signatures found matching the expected signature\"? Tiene dos causas. Sigue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":655,"title":656,"description":657,"published":658,"category":535,"image":659,"draft":539},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" en Supabase: las tres causas","Supabase dice \"Invalid login credentials\" ante una contraseña errónea, un email desconocido y una cuenta de Google. Cómo saber cuál es.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":661,"title":662,"description":663,"published":664,"category":535,"image":665,"draft":539},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": el error real","\"Edge Function returned a non-2xx status code\" significa que tu función de Supabase respondió con un error. Aquí ves dónde leer el real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":667,"title":668,"description":669,"published":670,"category":535,"image":671,"draft":539},"\u002Fblog\u002Fcertificate-not-trusted","Certificado no confiable: tres causas aparte de la caducidad","¿Certificado no confiable aunque la fecha está bien? Nombra otra dirección, se firmó a sí mismo o a su cadena le falta un eslabón. Cómo saber cuál.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":673,"title":674,"description":675,"published":676,"category":535,"image":677,"draft":539},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": lee las comillas","Supabase \"invalid input syntax for type uuid\" significa que tu app envió algo que no es un id. Lee las comillas, frena la consulta, conserva la columna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":679,"title":680,"description":681,"published":682,"category":535,"image":683,"draft":539},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": el valor ya está ocupado. Encuentra la columna, elige un arreglo y aparta el valor de la pantalla.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":685,"title":686,"description":687,"published":688,"category":535,"image":689,"draft":539},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" aunque la tabla está ahí","Supabase \"relation does not exist\" o PGRST205: ninguna tabla tiene ese nombre en ese esquema. Cuatro comprobaciones, y lo que abre exponer un esquema.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":691,"title":692,"description":693,"published":694,"category":535,"image":695,"draft":539},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" muestra los nombres de argumentos que envió tu app. Compáralos con la función.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":697,"title":698,"description":699,"published":700,"category":535,"image":701,"draft":539},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" suele ser un nombre que no coincide. Cuatro comprobaciones y la línea que recarga.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":571,"title":5,"description":538,"published":572,"category":535,"image":560,"draft":539},{"path":343,"title":704,"description":705,"published":706,"category":535,"image":707,"draft":539},"Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" cierra la sesión de tus usuarios. Tres causas, y cómo las separa el log de Auth.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":709,"title":710,"description":711,"published":712,"category":535,"image":713,"draft":539},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": tres causas","Supabase \"permission denied for schema public\" es un grant que falta en el esquema. Qué lo quitó y la línea que lo devuelve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":715,"title":716,"description":717,"published":718,"category":535,"image":719,"draft":539},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": las tres cosas que significa","Supabase \"Bucket not found\" es una de tres cosas: un enlace público a un bucket privado, un nombre que no coincide exactamente o el proyecto equivocado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":721,"title":722,"description":723,"published":724,"category":535,"image":725,"draft":539},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: ¿qué clave dejó de funcionar?","Un error Supabase invalid JWT es PGRST301: un token firmado no pasó la verificación. En un proyecto nuevo se trata de la sesión, no de la clave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":727,"title":728,"description":729,"published":730,"category":535,"image":731,"draft":539},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" casi siempre es ninguna","Supabase devuelve PGRST116, \"JSON object requested, multiple (or no) rows returned\", cuando tu consulta no encontró nada. Una fila oculta parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":733,"title":734,"description":735,"published":736,"category":535,"image":737,"draft":539},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" en Supabase: dónde mirar","\"Database error saving new user\" significa que algo unido a tu registro de Supabase falló y se deshizo entero. El error real está en tus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":739,"title":740,"description":741,"published":742,"category":535,"image":743,"draft":539},"\u002Fblog\u002Fwhat-is-supabase","¿Qué es Supabase? La base de datos que eligió tu builder","Qué es Supabase: la base de datos, el login y el almacenamiento de archivos de tu app. Supabase lleva los servidores; las reglas sobre tus filas son tuyas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":745,"title":746,"description":747,"published":748,"category":535,"image":749,"draft":539},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Una clave AWS expuesta en tu frontend no es como una clave OpenAI","Una clave de acceso de AWS expuesta en tu frontend lee y escribe tu almacenamiento. La solución suele ser una presigned URL, no una clave nueva.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":751,"title":752,"description":753,"published":754,"category":535,"image":755,"draft":539},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" al subir","\"New row violates row-level security policy for table objects\" significa que tu subida no tiene regla insert. Hacer público el bucket no añade ninguna.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":757,"title":758,"description":759,"published":760,"category":535,"image":761,"draft":539},"\u002Fblog\u002Fbase44-security-scan","Escaneo de seguridad de Base44: lo que solo él ve","El escaneo de seguridad de Base44 revisa siete tipos de problema desde dentro. Esta es la mitad que lee y nadie más puede leer, y la mitad que nunca mira.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":763,"title":764,"description":765,"published":766,"category":535,"image":767,"draft":539},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Tu clave API se filtró. El orden en el que hay que actuar","Una clave API se filtró y no sabes por dónde empezar. No todas las claves de tu frontend lo son, y el orden importa más que la velocidad.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":769,"title":770,"description":771,"published":772,"category":535,"image":773,"draft":539},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sin desactivar RLS","\"Infinite recursion detected in policy for relation\" significa que tu policy preguntó a la tabla que protege. Así se rompe el círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":775,"title":776,"description":777,"published":778,"category":535,"image":779,"draft":539},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" en Supabase, y el arreglo equivocado","\"No API key found in request\" significa que tu petición llegó a Supabase sin clave. Casi todas las respuestas apuntan a las reglas de tu base de datos.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":781,"title":782,"description":783,"published":784,"category":535,"image":785,"draft":539},"\u002Fblog\u002Fis-base44-safe","¿Es seguro Base44? Lo que vimos en 5.442 apps Base44","¿Es seguro Base44? Pasamos nueve comprobaciones a 5.442 apps Base44 en producción. Casi todas sacaron B por motivos que su dueño nunca eligió.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":787,"title":788,"description":789,"published":790,"category":535,"image":791,"draft":539},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Ocultar una clave API: muévela a una Edge Function de Supabase","Ocultar una clave API significa sacarla del navegador, y una Edge Function de Supabase es el sitio más pequeño donde ponerla. Dos pasos importan más.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":793,"title":794,"description":795,"published":796,"category":535,"image":797,"draft":539},"\u002Fblog\u002Fenv-file-exposed-on-your-server","¿Tu archivo .env está expuesto? Las doce rutas a revisar","¿Tu archivo .env está expuesto en tu propio servidor web? Doce direcciones te lo dicen, y un acierto significa que todo lo que contiene ya es público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":799,"title":800,"description":801,"published":802,"category":535,"image":803,"draft":539},"\u002Fblog\u002Fis-v0-safe","Seguridad de v0: las 1.790 aplicaciones escaneadas sacaron una A","Seguridad de v0, medida en 1.790 aplicaciones v0 en vivo: todas sacaron A. Solo 17 nombraban una base de datos, y eso es casi todo lo que mide la A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":805,"title":806,"description":807,"published":808,"category":535,"image":809,"draft":539},"\u002Fblog\u002Fis-bolt-safe","¿Es seguro Bolt? Lo que vimos en 1.123 aplicaciones Bolt","¿Es seguro Bolt? Pasamos 1.123 aplicaciones Bolt en vivo por nueve comprobaciones. El hosting salió limpio. Los hallazgos eran claves y tablas abiertas dentro.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":121,"title":811,"description":812,"published":813,"category":535,"image":814,"draft":539},"¿Supabase está caído o es tu app? Cómo distinguirlo","¿Supabase está caído o es tu app? Un proyecto pausado, una base de datos llena y un fallo tuyo parecen lo mismo. Cuatro comprobaciones los separan.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":816,"title":817,"description":818,"published":819,"category":535,"image":820,"draft":539},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","¿Supabase cifra mis datos? Sí. Esto es lo que detiene","¿Supabase cifra los datos? Sí: AES-256 en reposo, TLS en tránsito, SOC 2 e ISO 27001. Qué cubre cada uno, y la fuga que ninguno de ellos detiene.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":351,"title":822,"description":823,"published":824,"category":535,"image":825,"draft":539},"¿Cuánto cuesta Supabase? Los límites del plan gratuito","Los límites del plan gratuito de Supabase: 500 MB de base de datos, 5 GB de egress y ningún backup. Qué pasa en cada uno y qué cambia Pro por $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":827,"title":828,"description":829,"published":830,"category":646,"image":831,"draft":539},"\u002Fblog\u002Ftest-your-supabase-backup","Prueba tu backup de Supabase antes del día que lo necesites","Cómo probar tu backup de Supabase: restaurarlo en un proyecto de prueba, contar filas, iniciar sesión y buscar la línea que le falta a un archivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":833,"title":834,"description":835,"published":836,"category":646,"image":837,"draft":539},"\u002Fblog\u002Fsupabase-backup-github-action","Backup gratis de Supabase con una GitHub Action, y la trampa","Un backup de Supabase con GitHub Action es gratis y sirve a muchas apps. El workflow, el connection string correcto y el egress de cada ejecución.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":646,"image":843,"draft":539},"\u002Fblog\u002Fdownload-your-supabase-backup","Por qué no puedes descargar tu backup de Supabase","No puedes descargar tu backup de Supabase en un proyecto actual: la copia diaria es una instantánea física. Cómo comprobarlo y tener tu propia copia.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":842,"category":535,"image":848,"draft":539},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": el grant que falta","Desde el 30 de octubre, una tabla nueva de Supabase responde \"permission denied for table\" hasta que le das acceso. El grant del email es la mitad del arreglo.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":850,"title":851,"description":852,"published":853,"category":535,"image":854,"draft":539},"\u002Fblog\u002Fopen-api-endpoint-exposed","¿Un endpoint de API abierto es un problema? Mira el JSON","Tu escaneo señaló un endpoint de API abierto. Que importe depende de lo que devolvió, y la mayoría de los que encontramos eran de la plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":856,"title":857,"description":858,"published":859,"category":535,"image":860,"draft":539},"\u002Fblog\u002Flovable-security-scan","Escaneo de seguridad de Lovable: lo que no puede probar","Escaneo de seguridad de Lovable: qué revisan el Quick scan y el Deep scan, cuándo corre cada uno, y lo único que ningún escaneo desde dentro puede probar.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":862,"title":863,"description":864,"published":865,"category":646,"image":866,"draft":539},"\u002Fblog\u002Fsupabase-backup-auth-users","Por qué tu dump de Supabase no tiene usuarios dentro","Ejecuta supabase db dump por sí solo y obtienes la forma de tu base de datos y ninguna de sus filas, sin el esquema auth donde viven tus usuarios.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":868,"title":869,"description":870,"published":871,"category":535,"image":872,"draft":539},"\u002Fblog\u002Fdomain-and-certificate-expiry","Dominio caducado, web caída: qué pasa a partir de ahora","Tu dominio caducó y tu web está caída. Aquí tienes el reloj que acaba de arrancar, por qué el certificado es el menor problema, y cómo comprobar ambos.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":874,"title":875,"description":876,"published":877,"category":535,"image":878,"draft":539},"\u002Fblog\u002Fis-lovable-safe","¿Es seguro Lovable? Lo que vimos en 18.554 aplicaciones Lovable","¿Es seguro Lovable? Pasamos 18.554 aplicaciones Lovable por nueve comprobaciones. La plataforma fue la más limpia de cinco. Los hallazgos estaban dentro.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":880,"title":881,"description":882,"published":883,"category":535,"image":884,"draft":539},"\u002Fblog\u002Fvibe-coded-app-security-checklist","La lista de seguridad del vibe coding, en nueve comprobaciones","Una lista de seguridad del vibe coding con nueve puntos, cada uno verificable en tu app desde fuera por cualquiera, y cada uno con una prueba de una línea.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":886,"title":887,"description":888,"published":889,"category":535,"image":890,"draft":539},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Una clave secreta de Stripe en tu frontend puede mover dinero","Una clave secreta de Stripe expuesta en tu frontend puede reembolsar, cobrar y leer cada ficha de cliente que tienes. Tu clave pk_live_ sí debe estar ahí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":892,"title":893,"description":894,"published":895,"category":535,"image":896,"draft":539},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variables de entorno de Vite expuestas: el prefijo dice publica esto","Variables de entorno de Vite expuestas en tu app: hicieron lo que pedía el prefijo. VITE_ y NEXT_PUBLIC_ significan publica esto, y la IA nunca supo el coste.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":898,"title":899,"description":900,"published":901,"category":535,"image":902,"draft":539},"\u002Fblog\u002Fbase44-source-maps","Seguridad en Base44: qué marca un escaneo y qué te toca arreglar a ti","Seguridad en Base44 en 5.438 apps escaneadas: tres hallazgos en casi todas son de la plataforma, el source map es la insignia de Base44 y lo tuyo es poco.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":904,"title":905,"description":906,"published":907,"category":535,"image":908,"draft":539},"\u002Fblog\u002Fis-cursor-ai-safe","¿Es seguro Cursor AI? El editor, el código y la app que publicaste","¿Es seguro Cursor AI? Tres preguntas en una búsqueda: qué guarda Cursor, en qué falla el código que escribe y si la app que publicaste está abierta.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":910,"title":911,"description":912,"published":913,"category":535,"image":914,"draft":539},"\u002Fblog\u002Fis-replit-safe","¿Es seguro Replit? Lo que vimos en 3.042 aplicaciones Replit en vivo","¿Es seguro Replit? Pasamos 3.042 aplicaciones Replit en vivo por nueve comprobaciones externas. Los hallazgos estaban en la aplicación publicada, no en el host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":916,"title":917,"description":918,"published":919,"category":646,"image":920,"draft":539},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: tu copia de la base no tiene archivos","Un Supabase storage backup es una tarea aparte. Las copias de la base guardan la lista de tus archivos y ninguno de ellos, así que cada upload queda roto.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":646,"image":926,"draft":539},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery de Supabase: precio y límites","El point-in-time recovery de Supabase rebobina tu base de datos a cualquier segundo de la última semana. Cuesta $100 al mes sobre Pro y solo cubre la base.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":931,"category":646,"image":932,"draft":539},"\u002Fblog\u002Fsupabase-project-paused-recover","¿Proyecto de Supabase pausado? Tus datos siguen ahí","Supabase pausó tu proyecto tras una semana sin actividad. No se ha borrado nada, Restaurar está junto al nombre y tienes un año antes de que eso cambie.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":934,"title":935,"description":936,"published":937,"category":535,"image":938,"draft":539},"\u002Fblog\u002Fsafest-ai-app-builder","¿Qué builder de apps con IA es más seguro? 30.998 apps escaneadas","¿Qué builder de apps con IA es más seguro? Escaneamos 30.998 apps activas de Lovable, Base44, Replit, v0 y Bolt. El builder no es lo que decide tu nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":940,"title":941,"description":942,"published":943,"category":535,"image":944,"draft":539},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Activa Row Level Security en cada tabla de Supabase y compruébalo","Activar Row Level Security en Supabase sin política cierra la tabla del todo. Una política sin el interruptor no hace nada. Aquí tienes el SQL y la prueba.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":946,"title":947,"description":948,"published":949,"category":535,"image":950,"draft":539},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": lo que el aviso no ve","Supabase marca \"RLS disabled in public\" como error. No dice nada de la política de lectura que deja tu tabla igual de abierta a cualquiera.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":952,"title":953,"description":954,"published":955,"category":535,"image":956,"draft":539},"\u002Fblog\u002Frotate-supabase-service-role-key","Cómo rotar una clave service_role de Supabase filtrada","Supabase dice que primero cierres la fuga. Otras guías dicen que rotes ya. Cuál es lo correcto depende de dónde se filtró tu clave service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":958,"title":959,"description":960,"published":961,"category":535,"image":962,"draft":539},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Escáneres de seguridad vibe coding comparados, el nuestro incluido","El mejor escáner de seguridad para vibe coding depende de tres preguntas que ninguna lista de funciones responde. Ocho herramientas, con precios.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":964,"title":965,"description":966,"published":967,"category":535,"image":968,"draft":539},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: haz tú mismo las cinco comprobaciones","Un Supabase security checker lee tu app publicada en lugar de la configuración de tu proyecto. Estas son las cinco comprobaciones y cómo hacer cada una.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":970,"title":971,"description":972,"published":973,"category":535,"image":974,"draft":539},"\u002Fblog\u002Fvibe-coding-security-scanner","Escáner de seguridad para vibe coding: qué se le escapa","Un escáner de seguridad para vibe coding lee tu app en vivo desde fuera. Qué cubre eso, las cuatro cosas que no puede ver y cómo leer el resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":976,"title":977,"description":978,"published":979,"category":535,"image":980,"draft":539},"\u002Fblog\u002Fmissing-security-headers","Faltan cabeceras de seguridad: cuándo importa de verdad","Que falten cabeceras de seguridad es el hallazgo que más imprime nuestro escáner. Contra qué protegen y cuándo son la línea menos urgente de tu informe.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":982,"title":983,"description":984,"published":985,"category":535,"image":986,"draft":539},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Tu clave de API de OpenAI está expuesta en tu frontend. Rótala.","Una clave de API de OpenAI expuesta en tu frontend no se puede atar a un dominio. Rótala hoy, mueve la llamada a tu servidor y limita el gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":988,"title":989,"description":990,"published":991,"category":535,"image":992,"draft":539},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Clave de API expuesta en el frontend: qué llevan 30.998 apps","Una clave de API expuesta en tu frontend suele ser una clave de Google Maps. Escaneamos 30.998 apps vibe-coded y contamos qué secretos se filtran de verdad.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":994,"title":995,"description":996,"published":997,"category":646,"image":998,"draft":539},"\u002Fblog\u002Fsupabase-backup-tools-compared","Herramientas de backup de Supabase comparadas, la nuestra incluida","Cuatro tipos de herramienta de backup de Supabase, qué copia cada una y cuándo una GitHub Action gratuita le gana a pagar a cualquiera, nosotros incluidos.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1000,"title":1001,"description":1002,"published":1003,"category":535,"image":1004,"draft":539},"\u002Fblog\u002Freplit-secrets-explained","Cómo usar secrets en Replit, y qué se publica de todos modos","Cómo usar secrets en Replit: añadir uno, leerlo y arreglar las dos causas del undefined. Y las claves que la herramienta Secrets no puede mantener privadas.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1006,"title":1007,"description":1008,"published":1009,"category":646,"image":1010,"draft":539},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups del plan gratuito de Supabase: cómo hacer uno sin terminal","No hay backups en el plan gratuito de Supabase: la copia tienes que hacerla tú. Cómo sacarla desde el panel y qué deja fuera la vía CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1012,"title":1013,"description":1014,"published":1015,"category":535,"image":1016,"draft":539},"\u002Fblog\u002Fis-supabase-secure","¿Supabase es seguro? Sí. Tu proyecto es otra pregunta","¿Supabase es seguro? La plataforma está auditada, cifrada y sometida a pentests. Su propia documentación dice dónde termina eso y empiezan tus ajustes.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1018,"title":1019,"description":1020,"published":1021,"category":535,"image":1022,"draft":539},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Dónde están tus claves API de Supabase: anon, service_role y URL","La URL del proyecto, la clave anon y la clave service_role están en una sola página del panel. Aquí tienes dónde está, y cuál de los cuatro va en tu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1024,"title":1025,"description":1026,"published":1027,"category":535,"image":1028,"draft":539},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy en Supabase. ¿Y ahora?","\"New row violates row-level security policy\" significa que Supabase rechazó una escritura. El arreglo rápido vuelve a abrir la tabla para cualquiera.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1030,"title":1031,"description":1032,"published":1033,"category":535,"image":1034,"draft":539},"\u002Fblog\u002Fcors-wildcard-security-risk","¿Es un comodín CORS un riesgo de seguridad? Casi nunca.","¿Es un comodín CORS un riesgo de seguridad? Casi siempre es el ajuste por defecto de tu builder y no entrega nada que tu servidor no diera ya a cualquiera.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1036,"title":1037,"description":1038,"published":1039,"category":646,"image":1040,"draft":539},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching no es un backup. Solo va hacia adelante.","Por qué el branching de Supabase no es un backup: una rama arranca sin tus datos y un merge solo mueve el esquema. Para qué sirve y qué usar en su lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1042,"title":1043,"description":1044,"published":1045,"category":646,"image":1046,"draft":539},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Cómo restaurar un backup de Supabase, y qué se rompe después","Cómo restaurar un backup de Supabase desde el panel o desde un archivo de volcado, qué reemplaza la restauración y por qué tu app puede seguir rota al terminar.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1048,"title":1049,"description":1050,"published":1051,"category":535,"image":1052,"draft":539},"\u002Fblog\u002Fsupabase-storage-bucket-public","Tu bucket de Supabase Storage es público. ¿Es un problema?","Un bucket público de Supabase Storage significa que quien tenga la URL de un archivo puede abrirlo. No significa que alguien pueda listar lo que hay dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1054,"title":1055,"description":1056,"published":1057,"category":535,"image":1058,"draft":539},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","¿Es un problema una clave de API de Google en tu frontend?","Una clave de API de Google en tu frontend es la clave que más encuentra nuestro escáner, y casi siempre no pasa nada. Un ajuste gratuito decide cuál es cuál.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1060,"title":1061,"description":1062,"published":1063,"category":646,"image":1064,"draft":539},"\u002Fblog\u002Fai-agent-deleted-my-database","Un agente de IA borró mis datos de Supabase. ¿Qué puedo recuperar?","Un agente de IA borró datos de tu base. Lo que puedes recuperar ya estaba decidido antes de que se ejecutara, y los próximos minutos deciden el resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1066,"title":1067,"description":1068,"published":1069,"category":535,"image":1070,"draft":539},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","¿Puede cualquiera leer tu base de datos Supabase? 3.680 apps","¿Puede cualquiera leer tu base de datos Supabase sin iniciar sesión? Escaneamos 30.998 apps activas hechas con builders de IA y medimos cuántas dicen que sí.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1072,"title":1073,"description":1074,"published":1069,"category":535,"image":1075,"draft":539},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expuestos: tu app está publicando su código original","Un source map expuesto deja que cualquiera lea el código original de tu app, comentarios incluidos. La comprobación de 30 segundos y lo que de verdad importa.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1077,"title":1078,"description":1079,"published":1080,"category":535,"image":1081,"draft":539},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ¿es la misma que la anon key?","Supabase sustituyó anon y service_role por claves publicables y secretas. ¿Cuál pertenece a tu app y cuál no debe estar nunca?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1083,"title":1084,"description":1085,"published":1086,"category":646,"image":1087,"draft":539},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","¿Supabase respalda mi base de datos? Depende de tu plan.","¿Supabase respalda tu base de datos? A diario en los planes de pago, y nada en el gratuito. Cómo saber cuál tienes y qué es lo que esa copia no cubre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1089,"title":1090,"description":1091,"published":1092,"category":535,"image":1093,"draft":539},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security está activado. Tu tabla sigue pública.","Activar Supabase Row Level Security no protege una tabla. Lo hacen tus políticas, y la que arregló tu app rota puede dejar entrar a cualquiera.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1095,"title":1096,"description":1097,"published":1092,"category":646,"image":1098,"draft":539},"\u002Fblog\u002Fversion-history-is-not-a-backup","El historial de versiones no es un backup. No recupera una tabla.","Lovable y Bolt guardan un historial de versiones de tu código. Tu base de datos es un servicio aparte, y volver atrás no te devuelve tus datos.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1100,"title":1101,"description":1102,"published":1103,"category":646,"image":1104,"draft":539},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Tres formas de respaldar una base Supabase, y qué falta en cada una","El panel, pg_dump y un servicio gestionado. Qué guarda de verdad cada uno, qué deja fuera sin avisar y cuál sobrevive a perder la cuenta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1106,"title":1107,"description":1108,"published":1103,"category":535,"image":1109,"draft":539},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Qué claves de API son seguras en el navegador y cuáles no","Tu clave anon de Supabase está pensada para ser pública. Tu clave service_role no, y se salta todas las reglas que pongas. Cómo distinguirlas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213645204]